diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/alpha/config.in linux.20pre2-ac1/arch/alpha/config.in --- linux.20pre2/arch/alpha/config.in 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/alpha/config.in 2002-08-13 14:00:30.000000000 +0100 @@ -385,6 +385,7 @@ # fi # fi source drivers/video/Config.in + source drivers/char/speakup/Config.in if [ "$CONFIG_FB" = "y" ]; then define_bool CONFIG_PCI_CONSOLE y fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/alpha/kernel/pci.c linux.20pre2-ac1/arch/alpha/kernel/pci.c --- linux.20pre2/arch/alpha/kernel/pci.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/alpha/kernel/pci.c 2002-08-06 15:42:19.000000000 +0100 @@ -351,7 +351,7 @@ } int -pcibios_enable_device(struct pci_dev *dev) +pcibios_enable_device(struct pci_dev *dev, int mask) { /* Nothing to do, since we enable all devices at startup. */ return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/alpha/kernel/process.c linux.20pre2-ac1/arch/alpha/kernel/process.c --- linux.20pre2/arch/alpha/kernel/process.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/alpha/kernel/process.c 2002-08-06 15:42:19.000000000 +0100 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -74,9 +75,6 @@ cpu_idle(void) { /* An endless idle loop with no priority at all. */ - current->nice = 20; - current->counter = -100; - while (1) { /* FIXME -- EV6 and LCA45 know how to power down the CPU. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/alpha/kernel/smp.c linux.20pre2-ac1/arch/alpha/kernel/smp.c --- linux.20pre2/arch/alpha/kernel/smp.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/alpha/kernel/smp.c 2002-08-06 15:42:19.000000000 +0100 @@ -82,6 +82,7 @@ int smp_num_cpus = 1; /* Number that came online. */ int smp_threads_ready; /* True once the per process idle is forked. */ cycles_t cacheflush_time; +unsigned long cache_decay_ticks; int __cpu_number_map[NR_CPUS]; int __cpu_logical_map[NR_CPUS]; @@ -156,11 +157,6 @@ { int cpuid = hard_smp_processor_id(); - if (current != init_tasks[cpu_number_map(cpuid)]) { - printk("BUG: smp_calling: cpu %d current %p init_tasks[cpu_number_map(cpuid)] %p\n", - cpuid, current, init_tasks[cpu_number_map(cpuid)]); - } - DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state)); /* Turn on machine checks. */ @@ -215,9 +211,6 @@ DBGS(("smp_callin: commencing CPU %d current %p\n", cpuid, current)); - /* Setup the scheduler for this processor. */ - init_idle(); - /* ??? This should be in init_idle. */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; @@ -236,8 +229,9 @@ smp_tune_scheduling (int cpuid) { struct percpu_struct *cpu; - unsigned long on_chip_cache; - unsigned long freq; + unsigned long on_chip_cache; /* kB */ + unsigned long freq; /* Hz */ + unsigned long bandwidth = 350; /* MB/s */ cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset + cpuid * hwrpb->processor_size); @@ -258,29 +252,21 @@ case EV6_CPU: case EV67_CPU: - on_chip_cache = 64 + 64; - break; - default: - on_chip_cache = 8 + 8; + on_chip_cache = 64 + 64; break; } freq = hwrpb->cycle_freq ? : est_cycle_freq; -#if 0 - /* Magic estimation stolen from x86 port. */ - cacheflush_time = freq / 1024L * on_chip_cache / 5000L; - - printk("Using heuristic of %d cycles.\n", - cacheflush_time); -#else - /* Magic value to force potential preemption of other CPUs. */ - cacheflush_time = INT_MAX; + cacheflush_time = (freq / 1000000) * (on_chip_cache << 10) / bandwidth; + cache_decay_ticks = cacheflush_time / (freq / 1000) * HZ / 1000; - printk("Using heuristic of %d cycles.\n", - cacheflush_time); -#endif + printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", + cacheflush_time/(freq/1000000), + (cacheflush_time*100/(freq/1000000)) % 100); + printk("task migration cache decay timeout: %ld msecs.\n", + (cache_decay_ticks + 1) * 1000 / HZ); } /* @@ -505,14 +491,11 @@ if (idle == &init_task) panic("idle process is init_task for CPU %d", cpuid); - idle->processor = cpuid; - idle->cpus_runnable = 1 << cpuid; /* we schedule the first task manually */ + init_idle(idle, cpuid); + unhash_process(idle); + __cpu_logical_map[cpunum] = cpuid; __cpu_number_map[cpuid] = cpunum; - - del_from_runqueue(idle); - unhash_process(idle); - init_tasks[cpunum] = idle; DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n", cpuid, idle->state, idle->flags)); @@ -619,14 +602,11 @@ __cpu_number_map[boot_cpuid] = 0; __cpu_logical_map[0] = boot_cpuid; - current->processor = boot_cpuid; smp_store_cpu_info(boot_cpuid); smp_tune_scheduling(boot_cpuid); smp_setup_percpu_timer(boot_cpuid); - init_idle(); - /* ??? This should be in init_idle. */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/alpha/mm/fault.c linux.20pre2-ac1/arch/alpha/mm/fault.c --- linux.20pre2/arch/alpha/mm/fault.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/alpha/mm/fault.c 2002-08-06 15:42:19.000000000 +0100 @@ -88,6 +88,7 @@ struct mm_struct *mm = current->mm; unsigned int fixup; int fault; + siginfo_t info; /* As of EV6, a load into $31/$f31 is a prefetch, and never faults (or is suppressed by the PALcode). Support that for older CPUs @@ -108,6 +109,8 @@ if (!mm || in_interrupt()) goto no_context; + info.si_code = SEGV_MAPERR; + #ifdef CONFIG_ALPHA_LARGE_VMALLOC if (address >= TASK_SIZE) goto vmalloc_fault; @@ -119,8 +122,6 @@ goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, address)) goto bad_area; /* @@ -128,6 +129,7 @@ * we can handle it.. */ good_area: + info.si_code = SEGV_ACCERR; if (cause < 0) { if (!(vma->vm_flags & VM_EXEC)) goto bad_area; @@ -164,7 +166,12 @@ up_read(&mm->mmap_sem); if (user_mode(regs)) { - force_sig(SIGSEGV, current); + + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* info.si_code has been set above */ + info.si_addr = (void *)address; + force_sig_info(SIGSEGV,&info,current); return; } @@ -196,8 +203,7 @@ */ out_of_memory: if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } @@ -212,7 +218,12 @@ * Send a sigbus, regardless of whether we were in kernel * or user mode. */ - force_sig(SIGBUS, current); + info.si_signo = SIGBUS; + info.si_errno = 0; + /* not sure si_code value here */ + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + force_sig_info(SIGBUS,&info,current); if (!user_mode(regs)) goto no_context; return; @@ -220,7 +231,11 @@ #ifdef CONFIG_ALPHA_LARGE_VMALLOC vmalloc_fault: if (user_mode(regs)) { - force_sig(SIGSEGV, current); + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* info.si_code has been set above */ + info.si_addr = (void *)address; + force_sig_info(SIGSEGV,&info,current); return; } else { /* Synchronize this task's top level page-table diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/arm/config.in linux.20pre2-ac1/arch/arm/config.in --- linux.20pre2/arch/arm/config.in 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/arm/config.in 2002-08-13 14:01:01.000000000 +0100 @@ -606,6 +606,7 @@ bool 'VGA text console' CONFIG_VGA_CONSOLE fi source drivers/video/Config.in + source drivers/char/speakup/Config.in endmenu fi @@ -646,6 +647,7 @@ bool 'Kernel debugging' CONFIG_DEBUG_KERNEL dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL dep_bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL +dep_bool ' Morse code panics' CONFIG_PANIC_MORSE $CONFIG_DEBUG_KERNEL $CONFIG_PC_KEYB dep_bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL dep_bool ' Wait queue debugging' CONFIG_DEBUG_WAITQ $CONFIG_DEBUG_KERNEL dep_bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE $CONFIG_DEBUG_KERNEL diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/arm/mach-integrator/cpu.c linux.20pre2-ac1/arch/arm/mach-integrator/cpu.c --- linux.20pre2/arch/arm/mach-integrator/cpu.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/arm/mach-integrator/cpu.c 2002-08-06 15:42:21.000000000 +0100 @@ -121,7 +121,7 @@ cpu_freq_khz = vco_to_freq(vco, 1); #ifdef CONFIG_CPU_FREQ - cpufreq_init(cpu_freq_khz); + cpufreq_init(cpu_freq_khz, 1000, 0); cpufreq_setfunctions(integrator_validatespeed, integrator_setspeed); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/arm/mach-sa1100/generic.c linux.20pre2-ac1/arch/arm/mach-sa1100/generic.c --- linux.20pre2/arch/arm/mach-sa1100/generic.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/arm/mach-sa1100/generic.c 2002-08-06 15:42:21.000000000 +0100 @@ -86,7 +86,7 @@ static int __init sa11x0_init_clock(void) { - cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100); + cpufreq_init(cclk_frequency_100khz[PPCR & 0xf] * 100, 0, 0); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/arm/mm/fault-common.c linux.20pre2-ac1/arch/arm/mm/fault-common.c --- linux.20pre2/arch/arm/mm/fault-common.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/arm/mm/fault-common.c 2002-08-06 15:42:21.000000000 +0100 @@ -225,12 +225,11 @@ * If we are out of memory for pid1, * sleep for a while and retry */ - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); goto survive; check_stack: - if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) + if (!expand_stack(vma, addr)) goto good_area; out: return fault; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/cris/drivers/ide.c linux.20pre2-ac1/arch/cris/drivers/ide.c --- linux.20pre2/arch/cris/drivers/ide.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/arch/cris/drivers/ide.c 2002-08-06 15:42:22.000000000 +0100 @@ -816,13 +816,13 @@ rq = HWGROUP(drive)->rq; for (i = rq->nr_sectors; i > 0;) { i -= rq->current_nr_sectors; - ide_end_request(1, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 1); } return ide_stopped; } printk("%s: bad DMA status\n", drive->name); } - return ide_error(drive, "dma_intr", stat); + return DRIVER(drive)->error(drive, "dma_intr", stat); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/config.in linux.20pre2-ac1/arch/i386/config.in --- linux.20pre2/arch/i386/config.in 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/config.in 2002-08-13 15:08:25.000000000 +0100 @@ -99,13 +99,13 @@ define_int CONFIG_X86_L1_CACHE_SHIFT 5 define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y - define_bool CONFIG_X86_PGE y + bool 'PGE extensions (not for Cyrix/Transmeta)' CONFIG_X86_PGE define_bool CONFIG_X86_USE_PPRO_CHECKSUM y define_bool CONFIG_X86_PPRO_FENCE y define_bool CONFIG_X86_F00F_WORKS_OK y fi if [ "$CONFIG_MPENTIUMIII" = "y" ]; then - define_int CONFIG_X86_L1_CACHE_SHIFT 5 + define_int CONFIG_X86_L1_CACHE_SHIFT 7 define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_PGE y @@ -179,6 +179,17 @@ bool 'Machine Check Exception' CONFIG_X86_MCE +dep_bool 'CPU Frequency scaling' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL +if [ "$CONFIG_CPU_FREQ" != "n" ]; then + tristate ' AMD K6-2/K6-3 PowerNow!' CONFIG_X86_POWERNOW_K6 + tristate ' VIA C3/C5/Cyrix III Longhaul' CONFIG_X86_LONGHAUL + if [ "$CONFIG_X86_LONGHAUL" != "n" ]; then + bool ' Scale voltage according to speed' CONFIG_X86_LONGHAUL_SCALE_VOLTAGE + fi + tristate ' Intel Speedstep' CONFIG_X86_SPEEDSTEP + tristate ' Intel Pentium 4 throttling' CONFIG_X86_P4_CLOCKMOD +fi + tristate 'Toshiba Laptop support' CONFIG_TOSHIBA tristate 'Dell laptop support' CONFIG_I8K @@ -217,6 +228,7 @@ fi else bool 'Multiquad NUMA system' CONFIG_MULTIQUAD + dep_bool 'Summit Architecture support' CONFIG_SUMMIT $CONFIG_MULTIQUAD fi if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then @@ -290,6 +302,8 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'Kernel .config support' CONFIG_IKCONFIG + bool 'Power Management support' CONFIG_PM if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -418,6 +432,7 @@ tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE source drivers/video/Config.in fi + source drivers/char/speakup/Config.in endmenu fi @@ -440,12 +455,13 @@ bool 'Kernel debugging' CONFIG_DEBUG_KERNEL if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then bool ' Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW + bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER bool ' Debug high memory support' CONFIG_DEBUG_HIGHMEM bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ + bool ' Morse code panics' CONFIG_PANIC_MORSE bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK - bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/defconfig linux.20pre2-ac1/arch/i386/defconfig --- linux.20pre2/arch/i386/defconfig 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/defconfig 2002-08-07 14:06:24.000000000 +0100 @@ -2,7 +2,6 @@ # Automatically generated make config: don't edit # CONFIG_X86=y -CONFIG_ISA=y # CONFIG_SBUS is not set CONFIG_UID16=y @@ -45,12 +44,14 @@ CONFIG_X86_POPAD_OK=y # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_X86_L1_CACHE_SHIFT=5 +CONFIG_X86_L1_CACHE_SHIFT=7 CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_F00F_WORKS_OK=y CONFIG_X86_MCE=y +# CONFIG_CPU_FREQ is not set # CONFIG_TOSHIBA is not set # CONFIG_I8K is not set # CONFIG_MICROCODE is not set @@ -63,6 +64,8 @@ # CONFIG_MTRR is not set CONFIG_SMP=y # CONFIG_MULTIQUAD is not set +# CONFIG_SUMMIT is not set +CONFIG_ISA=y CONFIG_HAVE_DEC_LOCK=y # @@ -107,6 +110,7 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y +# CONFIG_IKCONFIG is not set CONFIG_PM=y # CONFIG_APM is not set @@ -237,6 +241,7 @@ # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set # # IDE chipset support/bugfixes @@ -256,7 +261,6 @@ # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_AEC62XX_TUNING is not set # CONFIG_BLK_DEV_ALI15X3 is not set @@ -274,9 +278,11 @@ CONFIG_PIIX_TUNING=y # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_ADMA100 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set # CONFIG_PDC202XX_FORCE is not set +CONFIG_BLK_DEV_RZ1000=y # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_SLC90E66 is not set @@ -433,11 +439,11 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_TULIP is not set -# CONFIG_TC35815 is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set CONFIG_EEPRO100=y +# CONFIG_E100 is not set # CONFIG_LNE390 is not set # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set @@ -454,6 +460,7 @@ # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set +# CONFIG_TC35815 is not set # CONFIG_VIA_RHINE is not set # CONFIG_VIA_RHINE_MMIO is not set # CONFIG_WINBOND_840 is not set @@ -464,6 +471,7 @@ # # CONFIG_ACENIC is not set # CONFIG_DL2K is not set +# CONFIG_E1000 is not set # CONFIG_MYRI_SBUS is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set @@ -589,6 +597,7 @@ # CONFIG_WATCHDOG is not set # CONFIG_AMD_RNG is not set # CONFIG_INTEL_RNG is not set +# CONFIG_AMD_PM768 is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set # CONFIG_DTLK is not set @@ -618,6 +627,7 @@ # CONFIG_DRM_R128 is not set CONFIG_DRM_RADEON=y # CONFIG_DRM_I810 is not set +# CONFIG_DRM_I830 is not set # CONFIG_DRM_MGA is not set # CONFIG_DRM_SIS is not set @@ -625,6 +635,7 @@ # PCMCIA character devices # # CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_SYNCLINK_CS is not set # CONFIG_MWAVE is not set # @@ -636,6 +647,9 @@ # File systems # # CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_QIFACE_COMPAT is not set # CONFIG_AUTOFS_FS is not set CONFIG_AUTOFS4_FS=y # CONFIG_REISERFS_FS is not set @@ -645,6 +659,8 @@ # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set # CONFIG_BFS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set @@ -662,6 +678,9 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -692,6 +711,7 @@ # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -705,7 +725,6 @@ # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set # CONFIG_ZISOFS_FS is not set -# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -720,11 +739,13 @@ # CONFIG_VGA_CONSOLE=y # CONFIG_VIDEO_SELECT is not set +# CONFIG_SPEAKUP is not set # # Sound # CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set @@ -878,3 +899,9 @@ # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set + +# +# Library routines +# +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/apic.c linux.20pre2-ac1/arch/i386/kernel/apic.c --- linux.20pre2/arch/i386/kernel/apic.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/apic.c 2002-08-13 14:02:53.000000000 +0100 @@ -29,6 +29,7 @@ #include #include #include +#include /* Using APIC to generate smp_local_timer_interrupt? */ int using_apic_timer = 0; @@ -260,6 +261,16 @@ apic_write_around(APIC_LVT1, value); } +static unsigned long apic_ldr_value(unsigned long value) +{ + if (clustered_apic_logical) + return (value); + if (clustered_apic_physical) + return (((value) & ~APIC_LDR_MASK) | + SET_APIC_LOGICAL_ID(physical_to_logical_apicid(hard_smp_processor_id()))); + return (((value) & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(1UL << smp_processor_id())); +} + void __init setup_local_APIC (void) { unsigned long value, ver, maxlvt; @@ -292,21 +303,23 @@ * document number 292116). So here it goes... */ - if (!clustered_apic_mode) { + if (!clustered_apic_logical) { /* - * In clustered apic mode, the firmware does this for us - * Put the APIC into flat delivery mode. - * Must be "all ones" explicitly for 82489DX. + * For NUMA-Q (clustered apic logical), the firmware does this + * for us. Otherwise put the APIC into clustered or flat + * delivery mode. Must be "all ones" explicitly for 82489DX. */ - apic_write_around(APIC_DFR, 0xffffffff); + + if(clustered_apic_mode) + apic_write_around(APIC_DFR, APIC_DFR_CLUSTER); + else + apic_write_around(APIC_DFR, APIC_DFR_FLAT); /* * Set up the logical destination ID. */ value = apic_read(APIC_LDR); - value &= ~APIC_LDR_MASK; - value |= (1<<(smp_processor_id()+24)); - apic_write_around(APIC_LDR, value); + apic_write_around(APIC_LDR, apic_ldr_value(value)); } /* @@ -1050,12 +1063,11 @@ /* * Local APIC timer interrupt. This is the most natural way for doing * local interrupts, but local timer interrupts can be emulated by - * broadcast interrupts too. [in case the hw doesn't support APIC timers] + * broadcast interrupts too. [in case the hw doesnt support APIC timers] * * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -unsigned int apic_timer_irqs [NR_CPUS]; void smp_apic_timer_interrupt(struct pt_regs * regs) { @@ -1064,7 +1076,7 @@ /* * the NMI deadlock-detector uses this. */ - apic_timer_irqs[cpu]++; + irq_stat[cpu].apic_timer_irqs++; /* * NOTE! We'd better ACK the irq immediately, @@ -1130,7 +1142,7 @@ 6: Received illegal vector 7: Illegal register address */ - printk (KERN_INFO "APIC error on CPU%d: %02lx(%02lx)\n", + printk (KERN_ERR "APIC error on CPU%d: %02lx(%02lx)\n", smp_processor_id(), v , v1); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/apm.c linux.20pre2-ac1/arch/i386/kernel/apm.c --- linux.20pre2/arch/i386/kernel/apm.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/apm.c 2002-08-13 15:09:05.000000000 +0100 @@ -247,6 +247,7 @@ * powering off * [no-]debug log some debugging messages * [no-]power[-_]off power off on shutdown + * [no-]smp Use apm even on an SMP box * bounce[-_]interval= number of ticks to ignore suspend * bounces * idle[-_]threshold= System idle percentage above which to @@ -393,6 +394,7 @@ static int got_clock_diff; #endif static int debug; +static int smp = 0; static int apm_disabled = -1; #ifdef CONFIG_SMP static int power_off; @@ -494,6 +496,40 @@ } /* + * Lock APM functionality to physical CPU 0 + */ + +#ifdef CONFIG_SMP + +static unsigned long apm_save_cpus(void) +{ + unsigned long x = current->cpus_allowed; + /* Some bioses don't like being called from CPU != 0 */ + if (cpu_number_map(smp_processor_id()) != 0) { + set_cpus_allowed(current, 1 << cpu_logical_map(0)); + if (unlikely(cpu_number_map(smp_processor_id()) != 0)) + BUG(); + } + return x; +} + +static inline void apm_restore_cpus(unsigned long mask) +{ + set_cpus_allowed(current, mask); +} + +#else + +/* + * No CPU lockdown needed on a uniprocessor + */ + +#define apm_save_cpus() 0 +#define apm_restore_cpus(x) + +#endif + +/* * These are the actual BIOS calls. Depending on APM_ZERO_SEGS and * apm_info.allow_ints, we are being really paranoid here! Not only * are interrupts disabled, but all the segment registers (except SS) @@ -566,7 +602,8 @@ { APM_DECL_SEGS unsigned long flags; - + unsigned long cpus = apm_save_cpus(); + __save_flags(flags); APM_DO_CLI; APM_DO_SAVE_SEGS; @@ -588,6 +625,9 @@ : "memory", "cc"); APM_DO_RESTORE_SEGS; __restore_flags(flags); + + apm_restore_cpus(cpus); + return *eax & 0xff; } @@ -611,6 +651,8 @@ APM_DECL_SEGS unsigned long flags; + unsigned long cpus = apm_save_cpus(); + __save_flags(flags); APM_DO_CLI; APM_DO_SAVE_SEGS; @@ -636,6 +678,9 @@ } APM_DO_RESTORE_SEGS; __restore_flags(flags); + + apm_restore_cpus(cpus); + return error; } @@ -888,17 +933,12 @@ /* * This may be called on an SMP machine. */ -#ifdef CONFIG_SMP - /* Some bioses don't like being called from CPU != 0 */ - if (cpu_number_map(smp_processor_id()) != 0) { - current->cpus_allowed = 1; - schedule(); - if (unlikely(cpu_number_map(smp_processor_id()) != 0)) - BUG(); - } -#endif if (apm_info.realmode_power_off) + { + apm_save_cpus(); machine_real_restart(po_bios_call, sizeof(po_bios_call)); + /* Never returns */ + } else (void) set_system_power_state(APM_STATE_OFF); } @@ -1074,6 +1114,19 @@ } if ((error == APM_SUCCESS) || (error == APM_NO_ERROR)) return 1; + if (error == APM_NOT_ENGAGED) { + static int tried; + int eng_error; + if (tried++ == 0) { + eng_error = apm_engage_power_management(APM_DEVICE_ALL, 1); + if (eng_error) { + apm_error("set display", error); + apm_error("engage interface", eng_error); + return 0; + } else + return apm_console_blank(blank); + } + } apm_error("set display", error); return 0; } @@ -1397,7 +1450,7 @@ as = fp->private_data; if (check_apm_user(as, "read")) return -EIO; - if (count < sizeof(apm_event_t)) + if ((int)count < sizeof(apm_event_t)) return -EINVAL; if ((queue_empty(as)) && (fp->f_flags & O_NONBLOCK)) return -EAGAIN; @@ -1571,7 +1624,7 @@ p = buf; - if ((smp_num_cpus == 1) && + if ((smp_num_cpus == 1 || smp) && !(error = apm_get_power_status(&bx, &cx, &dx))) { ac_line_status = (bx >> 8) & 0xff; battery_status = bx & 0xff; @@ -1716,7 +1769,7 @@ } } - if (debug) { + if (debug && (smp_num_cpus == 1 || smp )) { error = apm_get_power_status(&bx, &cx, &dx); if (error) printk(KERN_INFO "apm: power status not available\n"); @@ -1760,7 +1813,7 @@ pm_power_off = apm_power_off; register_sysrq_key('o', &sysrq_poweroff_op); - if (smp_num_cpus == 1) { + if (smp_num_cpus == 1 || smp) { #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) console_blank_hook = apm_console_blank; #endif @@ -1799,6 +1852,11 @@ str += 3; if (strncmp(str, "debug", 5) == 0) debug = !invert; + if (strncmp(str, "smp", 3) == 0) + { + smp = !invert; + idle_threshold = 100; + } if ((strncmp(str, "power-off", 9) == 0) || (strncmp(str, "power_off", 9) == 0)) power_off = !invert; @@ -1903,7 +1961,7 @@ printk(KERN_NOTICE "apm: disabled on user request.\n"); return -ENODEV; } - if ((smp_num_cpus > 1) && !power_off) { + if ((smp_num_cpus > 1) && !power_off && !smp) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); return -ENODEV; } @@ -1957,7 +2015,7 @@ kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); - if (smp_num_cpus > 1) { + if (smp_num_cpus > 1 && !smp) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe (power off active).\n"); return 0; @@ -2025,5 +2083,8 @@ MODULE_PARM(idle_period, "i"); MODULE_PARM_DESC(idle_period, "Period (in sec/100) over which to caculate the idle percentage"); +MODULE_PARM(smp, "i"); +MODULE_PARM_DESC(smp, + "Set this to enable APM use on an SMP platform. Use with caution on older systems"); EXPORT_NO_SYMBOLS; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/dmi_scan.c linux.20pre2-ac1/arch/i386/kernel/dmi_scan.c --- linux.20pre2/arch/i386/kernel/dmi_scan.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/dmi_scan.c 2002-08-13 14:04:51.000000000 +0100 @@ -475,6 +475,22 @@ return 0; } +/* + * Work around broken HP Pavilion Notebooks which assign USB to + * IRQ 9 even though it is actually wired to IRQ 11 + */ +static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d) +{ +#ifdef CONFIG_PCI + extern int broken_hp_bios_irq9; + if (broken_hp_bios_irq9 == 0) + { + broken_hp_bios_irq9 = 1; + printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident); + } +#endif + return 0; +} /* * Simple "print if true" callback @@ -738,7 +754,14 @@ NO_MATCH, NO_MATCH } }, - + { fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", { + MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + MATCH(DMI_BIOS_VERSION, "GE.M1.03"), + MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), + MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736") + } }, + + /* * Generic per vendor APM settings */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/elanfreq.c linux.20pre2-ac1/arch/i386/kernel/elanfreq.c --- linux.20pre2/arch/i386/kernel/elanfreq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/elanfreq.c 2002-08-06 15:42:19.000000000 +0100 @@ -0,0 +1,235 @@ +/* + * elanfreq: cpufreq driver for the AMD ELAN family + * + * (c) Copyright 2002 Robert Schwebel + * + * Parts of this code are (c) Sven Geggus + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel + * + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */ +#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */ + +#define SAFE_FREQ 33000 /* every Elan CPU can run at 33 MHz */ + +static int currentspeed; /* current frequency in kHz */ +static unsigned int elanfreq_initialised; + +MODULE_LICENSE("GPL"); + +MODULE_AUTHOR( + "Robert Schwebel , Sven Geggus " +); +MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs"); + +struct s_elan_multiplier { + int clock; /* frequency in kHz */ + int val40h; /* PMU Force Mode register */ + int val80h; /* CPU Clock Speed Register */ +}; + +/* + * It is important that the frequencies + * are listed in ascending order here! + */ +struct s_elan_multiplier elan_multiplier[] = { + {1000, 0x02, 0x18}, + {2000, 0x02, 0x10}, + {4000, 0x02, 0x08}, + {8000, 0x00, 0x00}, + {16000, 0x00, 0x02}, + {33000, 0x00, 0x04}, + {66000, 0x01, 0x04}, + {99000, 0x01, 0x05} +}; + + +/** + * elanfreq_get_cpu_frequency: determine current cpu speed + * + * Finds out at which frequency the CPU of the Elan SOC runs + * at the moment. Frequencies from 1 to 33 MHz are generated + * the normal way, 66 and 99 MHz are called "Hyperspeed Mode" + * and have the rest of the chip running with 33 MHz. + */ + +static unsigned int elanfreq_get_cpu_frequency(void) +{ + u8 clockspeed_reg; /* Clock Speed Register */ + + cli(); + outb_p(0x80,REG_CSCIR); + clockspeed_reg = inb_p(REG_CSCDR); + sti(); + + if ((clockspeed_reg & 0xE0) == 0xE0) { return 0; } + + /* Are we in CPU clock multiplied mode (66/99 MHz)? */ + if ((clockspeed_reg & 0xE0) == 0xC0) { + if ((clockspeed_reg & 0x01) == 0) { + return 66000; + } else { + return 99000; + } + } + + /* 33 MHz is not 32 MHz... */ + if ((clockspeed_reg & 0xE0)==0xA0) + return 33000; + + return ((1<<((clockspeed_reg & 0xE0) >> 5)) * 1000); +} + + +/** + * elanfreq_set_cpu_frequency: Change the CPU core frequency + * @freq: frequency in kHz + * + * This function takes a frequency value and changes the CPU frequency + * according to this. Note that the frequency has to be checked by + * elanfreq_validatespeed() for correctness! + * + * There is no return value. + */ + +static void elanfreq_set_cpu_frequency (unsigned int freq) { + + int i; + + printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",freq); + + /* search table entry for given Mhz value */ + for (i=0; i<(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier)); i++) + { + if (elan_multiplier[i].clock==freq) break; + } + + /* XXX Shouldn't we have a sanity check here or can we rely on + the frequency having been checked before ??? */ + + /* + * Access to the Elan's internal registers is indexed via + * 0x22: Chip Setup & Control Register Index Register (CSCI) + * 0x23: Chip Setup & Control Register Data Register (CSCD) + * + */ + + /* + * 0x40 is the Power Management Unit's Force Mode Register. + * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency) + */ + + cli(); + outb_p(0x40,REG_CSCIR); /* Disable hyperspeed mode */ + outb_p(0x00,REG_CSCDR); + sti(); /* wait till internal pipelines and */ + udelay(1000); /* buffers have cleaned up */ + + cli(); + + /* now, set the CPU clock speed register (0x80) */ + outb_p(0x80,REG_CSCIR); + outb_p(elan_multiplier[i].val80h,REG_CSCDR); + + /* now, the hyperspeed bit in PMU Force Mode Register (0x40) */ + outb_p(0x40,REG_CSCIR); + outb_p(elan_multiplier[i].val40h,REG_CSCDR); + udelay(10000); + sti(); + + currentspeed=freq; + +}; + + +/** + * elanfreq_validatespeed: test if frequency is valid + * @freq: frequency in kHz + * + * This function checks if a given frequency in kHz is valid for the + * hardware supported by the driver. It returns a "best fit" frequency + * which might be different from the given one. + */ + +static unsigned int elanfreq_validatespeed (unsigned int freq) +{ + unsigned int best = 0; + int i; + + for (i=0; i<(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier)); i++) + { + if (freq >= elan_multiplier[i].clock) + { + best = elan_multiplier[i].clock; + + } + } + + return best; +} + + + +/* + * Module init and exit code + */ + +static int __init elanfreq_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + struct cpufreq_driver driver; + int ret; + + /* Test if we have the right hardware */ + if ((c->x86_vendor != X86_VENDOR_AMD) || + (c->x86 != 4) || (c->x86_model!=10)) + { + printk(KERN_INFO "elanfreq: error: no Elan processor found!\n"); + return -ENODEV; + } + + driver.freq.cur = elanfreq_get_cpu_frequency(); + driver.validate = &elanfreq_validatespeed; + driver.setspeed = &elanfreq_set_cpu_frequency; + + ret = cpufreq_register(driver); + if (ret) + return ret; + + elanfreq_initialised = 1, + + return 0; +} + + +static void __exit elanfreq_exit(void) +{ + if (elanfreq_initialised) + cpufreq_unregister(); +} + +module_init(elanfreq_init); +module_exit(elanfreq_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/entry.S linux.20pre2-ac1/arch/i386/kernel/entry.S --- linux.20pre2/arch/i386/kernel/entry.S 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/entry.S 2002-08-06 15:42:19.000000000 +0100 @@ -77,7 +77,7 @@ exec_domain = 16 need_resched = 20 tsk_ptrace = 24 -processor = 52 +cpu = 32 ENOSYS = 38 @@ -176,9 +176,11 @@ ENTRY(ret_from_fork) +#if CONFIG_SMP pushl %ebx call SYMBOL_NAME(schedule_tail) addl $4, %esp +#endif GET_CURRENT(%ebx) testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys_exit @@ -637,8 +639,8 @@ .long SYMBOL_NAME(sys_tkill) .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sendfile64 */ .long SYMBOL_NAME(sys_ni_syscall) /* 240 reserved for futex */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_setaffinity */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_getaffinity */ + .long SYMBOL_NAME(sys_sched_setaffinity) + .long SYMBOL_NAME(sys_sched_getaffinity) .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/head.S linux.20pre2-ac1/arch/i386/kernel/head.S --- linux.20pre2/arch/i386/kernel/head.S 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/head.S 2002-08-06 15:42:19.000000000 +0100 @@ -445,4 +445,15 @@ .quad 0x00409a0000000000 /* 0x48 APM CS code */ .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */ .quad 0x0040920000000000 /* 0x58 APM DS data */ + /* Segments used for calling PnP BIOS */ + .quad 0x00c09a0000000000 /* 0x60 32-bit code */ + .quad 0x00809a0000000000 /* 0x68 16-bit code */ + .quad 0x0080920000000000 /* 0x70 16-bit data */ + .quad 0x0080920000000000 /* 0x78 16-bit data */ + .quad 0x0080920000000000 /* 0x80 16-bit data */ + .quad 0x0000000000000000 /* 0x88 not used */ + .quad 0x0000000000000000 /* 0x90 not used */ + .quad 0x0000000000000000 /* 0x98 not used */ + /* Per CPU segments */ .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/i386_ksyms.c linux.20pre2-ac1/arch/i386/kernel/i386_ksyms.c --- linux.20pre2/arch/i386/kernel/i386_ksyms.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/i386_ksyms.c 2002-08-06 15:42:19.000000000 +0100 @@ -49,6 +49,7 @@ EXPORT_SYMBOL(drive_info); #endif +extern unsigned long cpu_khz; extern unsigned long get_cmos_time(void); /* platform dependent support */ @@ -57,6 +58,9 @@ EXPORT_SYMBOL(EISA_bus); #endif EXPORT_SYMBOL(MCA_bus); +#ifdef CONFIG_MULTIQUAD +EXPORT_SYMBOL(xquad_portio); +#endif EXPORT_SYMBOL(__verify_write); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); @@ -71,6 +75,7 @@ EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(get_cmos_time); +EXPORT_SYMBOL(cpu_khz); EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); EXPORT_SYMBOL(empty_zero_page); @@ -175,7 +180,3 @@ extern int is_sony_vaio_laptop; EXPORT_SYMBOL(is_sony_vaio_laptop); - -#ifdef CONFIG_MULTIQUAD -EXPORT_SYMBOL(xquad_portio); -#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/io_apic.c linux.20pre2-ac1/arch/i386/kernel/io_apic.c --- linux.20pre2/arch/i386/kernel/io_apic.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/io_apic.c 2002-08-13 14:05:00.000000000 +0100 @@ -28,10 +28,12 @@ #include #include #include +#include #include #include #include +#include #undef APIC_LOCKUP_DEBUG @@ -183,6 +185,86 @@ clear_IO_APIC_pin(apic, pin); } +static void set_ioapic_affinity (unsigned int irq, unsigned long mask) +{ + unsigned long flags; + + /* + * Only the first 8 bits are valid. + */ + mask = mask << 24; + spin_lock_irqsave(&ioapic_lock, flags); + __DO_ACTION(1, = mask, ) + spin_unlock_irqrestore(&ioapic_lock, flags); +} + +#if CONFIG_SMP + +typedef struct { + unsigned int cpu; + unsigned long timestamp; +} ____cacheline_aligned irq_balance_t; + +static irq_balance_t irq_balance[NR_IRQS] __cacheline_aligned + = { [ 0 ... NR_IRQS-1 ] = { 0, 0 } }; + +extern unsigned long irq_affinity [NR_IRQS]; + +#endif + +#define IDLE_ENOUGH(cpu,now) \ + (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1)) + +#define IRQ_ALLOWED(cpu,allowed_mask) \ + ((1 << cpu) & (allowed_mask)) + +static unsigned long move(int curr_cpu, unsigned long allowed_mask, unsigned long now, int direction) +{ + int search_idle = 1; + int cpu = curr_cpu; + + goto inside; + + do { + if (unlikely(cpu == curr_cpu)) + search_idle = 0; +inside: + if (direction == 1) { + cpu++; + if (cpu >= smp_num_cpus) + cpu = 0; + } else { + cpu--; + if (cpu == -1) + cpu = smp_num_cpus-1; + } + } while (!IRQ_ALLOWED(cpu,allowed_mask) || + (search_idle && !IDLE_ENOUGH(cpu,now))); + + return cpu; +} + +static inline void balance_irq(int irq) +{ +#if CONFIG_SMP + irq_balance_t *entry = irq_balance + irq; + unsigned long now = jiffies; + + if (unlikely(entry->timestamp != now)) { + unsigned long allowed_mask; + int random_number; + + rdtscl(random_number); + random_number &= 1; + + allowed_mask = cpu_online_map & irq_affinity[irq]; + entry->timestamp = now; + entry->cpu = move(entry->cpu, allowed_mask, now, random_number); + set_ioapic_affinity(irq, cpu_present_to_apicid(entry->cpu)); + } +#endif +} + /* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. @@ -287,7 +369,7 @@ Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", bus, slot, pin); - if (mp_bus_id_to_pci_bus[bus] == -1) { + if ((mp_bus_id_to_pci_bus==NULL) || (mp_bus_id_to_pci_bus[bus] == -1)) { printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); return -1; } @@ -605,6 +687,40 @@ return current_vector; } +#ifdef CONFIG_MULTIQUAD + +/* + * round_robin_cpu_apic_id -- Since Linux doesn't use either the APIC TPRs or + * XTPRs to set task/interrupt priority, xAPICs and SAPICs tend to hit one CPU + * with all interrupts for each quad. Distribute the interrupts using a simple + * round robin scheme. + */ +static inline int round_robin_cpu_apic_id(void) +{ + int val; + static unsigned next_cpu = 0; + + for (;; ++next_cpu) { + if (next_cpu >= smp_num_cpus) + next_cpu = 0; + if (!(logical_cpu_present_map & (1UL << next_cpu))) + continue; + val = cpu_present_to_apicid(next_cpu); + ++next_cpu; + return (val); + } +} + +static inline int __target_cpus(void) +{ + if (clustered_apic_logical) + return APIC_BROADCAST_ID_APIC; /* broadcast to local quad */ + if (clustered_apic_physical) + return round_robin_cpu_apic_id(); + return cpu_online_map; +} +#endif + extern void (*interrupt[NR_IRQS])(void); static struct hw_interrupt_type ioapic_level_irq_type; static struct hw_interrupt_type ioapic_edge_irq_type; @@ -625,8 +741,8 @@ */ memset(&entry,0,sizeof(entry)); - entry.delivery_mode = dest_LowestPrio; - entry.dest_mode = INT_DELIVERY_MODE; + entry.delivery_mode = INT_DELIVERY_MODE; + entry.dest_mode = (INT_DEST_ADDR_MODE != 0); entry.mask = 0; /* enable IRQ */ entry.dest.logical.logical_dest = TARGET_CPUS; @@ -646,7 +762,6 @@ if (irq_trigger(idx)) { entry.trigger = 1; entry.mask = 1; - entry.dest.logical.logical_dest = TARGET_CPUS; } irq = pin_2_irq(idx, apic, pin); @@ -654,7 +769,7 @@ * skip adding the timer int on secondary nodes, which causes * a small but painful rift in the time-space continuum */ - if (clustered_apic_mode && (apic != 0) && (irq == 0)) + if (clustered_apic_logical && (apic != 0) && (irq == 0)) continue; else add_pin_to_irq(irq, apic, pin); @@ -688,8 +803,7 @@ } /* - * Set up the 8259A-master output pin as broadcast to all - * CPUs. + * Set up the 8259A-master output pin: */ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) { @@ -707,10 +821,10 @@ * We use logical delivery to get the timer IRQ * to the first CPU. */ - entry.dest_mode = INT_DELIVERY_MODE; + entry.dest_mode = (INT_DEST_ADDR_MODE != 0); entry.mask = 0; /* unmask IRQ now */ entry.dest.logical.logical_dest = TARGET_CPUS; - entry.delivery_mode = dest_LowestPrio; + entry.delivery_mode = INT_DELIVERY_MODE; entry.polarity = 0; entry.trigger = 0; entry.vector = vector; @@ -734,8 +848,9 @@ void __init UNEXPECTED_IO_APIC(void) { - printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n"); - printk(KERN_WARNING " to linux-smp@vger.kernel.org\n"); + printk(KERN_WARNING + "An unexpected IO-APIC was found. If this kernel release is less than\n" + "three months old please report this to linux-smp@vger.kernel.org\n"); } void __init print_IO_APIC(void) @@ -788,6 +903,7 @@ printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.PRQ); printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.version); if ( (reg_01.version != 0x01) && /* 82489DX IO-APICs */ + (reg_01.version != 0x02) && /* VIA */ (reg_01.version != 0x10) && /* oldest IO-APICs */ (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */ (reg_01.version != 0x13) && /* Xeon IO-APICs */ @@ -1062,7 +1178,7 @@ old_id = mp_ioapics[apic].mpc_apicid; - if (mp_ioapics[apic].mpc_apicid >= 0xf) { + if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", apic, mp_ioapics[apic].mpc_apicid); printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", @@ -1074,14 +1190,16 @@ * Sanity check, is the ID really free? Every APIC in a * system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. + * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs. */ - if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) { + if (!clustered_apic_physical && + (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", apic, mp_ioapics[apic].mpc_apicid); for (i = 0; i < 0xf; i++) if (!(phys_id_present_map & (1 << i))) break; - if (i >= 0xf) + if (i >= apic_broadcast_id) panic("Max APIC ID exceeded!\n"); printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", i); @@ -1209,6 +1327,7 @@ */ static void ack_edge_ioapic_irq(unsigned int irq) { + balance_irq(irq); if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) mask_IO_APIC_irq(irq); @@ -1248,6 +1367,7 @@ unsigned long v; int i; + balance_irq(irq); /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1304,19 +1424,6 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ } -static void set_ioapic_affinity (unsigned int irq, unsigned long mask) -{ - unsigned long flags; - /* - * Only the first 8 bits are valid. - */ - mask = mask << 24; - - spin_lock_irqsave(&ioapic_lock, flags); - __DO_ACTION(1, = mask, ) - spin_unlock_irqrestore(&ioapic_lock, flags); -} - /* * Level and edge triggered IO-APIC interrupts need different handling, * so we use two separate IRQ descriptors. Edge triggered IRQs can be diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/irq.c linux.20pre2-ac1/arch/i386/kernel/irq.c --- linux.20pre2/arch/i386/kernel/irq.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/irq.c 2002-08-13 14:05:06.000000000 +0100 @@ -170,7 +170,7 @@ p += sprintf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); + irq_stat[cpu_logical_map(j)].apic_timer_irqs); p += sprintf(p, "\n"); #endif p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); @@ -1090,7 +1090,7 @@ static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static int irq_affinity_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/longhaul.c linux.20pre2-ac1/arch/i386/kernel/longhaul.c --- linux.20pre2/arch/i386/kernel/longhaul.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/longhaul.c 2002-08-06 15:42:19.000000000 +0100 @@ -0,0 +1,699 @@ +/* + * $Id: longhaul.c,v 1.52 2002/06/26 15:33:29 db Exp $ + * + * (C) 2001 Dave Jones. + * (C) 2002 Padraig Brady. + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon datasheets & sample CPUs kindly provided by VIA. + * + * VIA have currently 3 different versions of Longhaul. + * + * +---------------------+----------+---------------------------------+ + * | Marketing name | Codename | longhaul version / features. | + * +---------------------+----------+---------------------------------+ + * | Samuel/CyrixIII | C5A | v1 : multipliers only | + * | Samuel2/C3 | C3E/C5B | v1 : multiplier only | + * | Ezra | C5C | v2 : multipliers & voltage | + * | Ezra-T | C5M/C5N | v3 : multipliers, voltage & FSB | + * +---------------------+----------+---------------------------------+ + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG + +#ifdef DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0); +#endif + +static int numscales=16, numvscales; +static int minvid, maxvid; +static int can_scale_voltage; +static int can_scale_fsb; +static int vrmrev; + + +/* Module parameters */ +static int dont_scale_voltage; +static int dont_scale_fsb; +static int current_fsb; +static int favour_fast_fsb; + +#define __hlt() __asm__ __volatile__("hlt": : :"memory") + +/* + * Clock ratio tables. + * The eblcr ones specify the ratio read from the CPU. + * The clock_ratio ones specify what to write to the CPU. + */ + +/* VIA C3 Samuel 1 & Samuel 2 (stepping 0)*/ +static int __initdata longhaul1_clock_ratio[16] = { + -1, /* 0000 -> RESERVED */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + -1, /* 0011 -> RESERVED */ + -1, /* 0100 -> RESERVED */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + -1, /* 1110 -> RESERVED */ + -1, /* 1111 -> RESERVED */ +}; + +static int __initdata samuel1_eblcr[16] = { + 50, /* 0000 -> RESERVED */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + -1, /* 0011 -> RESERVED */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + -1, /* 0111 -> RESERVED */ + -1, /* 1000 -> RESERVED */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + -1, /* 1100 -> RESERVED */ + 75, /* 1101 -> 7.5x */ + -1, /* 1110 -> RESERVED */ + 65, /* 1111 -> 6.5x */ +}; + +/* VIA C3 Samuel2 Stepping 1->15 & VIA C3 Ezra */ +static int __initdata longhaul2_clock_ratio[16] = { + 100, /* 0000 -> 10.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ +}; + +static int __initdata samuel2_eblcr[16] = { + 90, /* 0000 -> 9.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 110, /* 0111 -> 11.0x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 130, /* 1110 -> 13.0x */ + 65, /* 1111 -> 6.5x */ +}; + +static int __initdata ezra_eblcr[16] = { + 90, /* 0000 -> 9.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 50, /* 1000 -> 5.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ +}; + +/* VIA C5M. */ +static int __initdata longhaul3_clock_ratio[32] = { + 100, /* 0000 -> 10.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ + + -1, /* 0000 -> RESERVED (10.0x) */ + 110, /* 0001 -> 11.0x */ + 120, /* 0010 -> 12.0x */ + -1, /* 0011 -> RESERVED (9.0x)*/ + 105, /* 0100 -> 10.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 135, /* 0111 -> 13.5x */ + 140, /* 1000 -> 14.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 130, /* 1011 -> 13.0x */ + 145, /* 1100 -> 14.5x */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + -1, /* 1111 -> RESERVED (12.0x) */ +}; + +static int __initdata c5m_eblcr[32] = { + 90, /* 0000 -> 9.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 50, /* 1000 -> 5.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ + + -1, /* 0000 -> RESERVED (9.0x) */ + 110, /* 0001 -> 11.0x */ + 120, /* 0010 -> 12.0x */ + -1, /* 0011 -> RESERVED (10.0x)*/ + 135, /* 0100 -> 13.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 105, /* 0111 -> 10.5x */ + 130, /* 1000 -> 13.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 140, /* 1011 -> 14.0x */ + -1, /* 1100 -> RESERVED (12.0x) */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + 145, /* 1111 -> 14.5x */ +}; + +/* fsb values as defined in CPU */ +static unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 }; +/* fsb values to favour low fsb speed (lower power) */ +static unsigned int power_fsb_table[] = { 66, 100, 133, -1 }; +/* fsb values to favour high fsb speed (for e.g. if lowering CPU + freq because of heat, but want to maintain highest performance possible) */ +static unsigned int perf_fsb_table[] = { 133, 100, 66, -1 }; +static unsigned int *fsb_search_table; + +/* Voltage scales. Div by 1000 to get actual voltage. */ +static int __initdata vrm85scales[32] = { + 1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700, + 1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300, + 1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725, + 1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325, +}; + +static int __initdata mobilevrmscales[32] = { + 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, + 1600, 1550, 1500, 1450, 1500, 1350, 1300, -1, + 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, + 1075, 1050, 1025, 1000, 975, 950, 925, -1, +}; + +/* Clock ratios multiplied by 10 */ +static int clock_ratio[32]; +static int eblcr_table[32]; +static int voltage_table[32]; +static int highest_speed, lowest_speed; +static int longhaul; /* version. */ + +/* + * All integer math. + * Input: + * ratio is multiplier*10, for e.g. 15 = 1.5, 12=1.2 + * Output: + * return value is in units of fsb input parameter + */ +static unsigned int get_clock_from_ratio(int ratio, unsigned fsb) +{ + unsigned int clock=0; + + if (ratio > 0 && fsb != 0) { + clock = (ratio/10)*fsb; + if (ratio%10) + clock += (fsb/(10/(ratio%10))); + } + return clock; +} + +static unsigned int longhaul_validatespeed_fsb(unsigned int freq, unsigned fsb, unsigned int oldbest) +{ + int i; + unsigned int newclock; + unsigned int best=0; + + best = oldbest; + + /* Find closest MHz match. */ + for (i=0; i best) && (newclock <= (freq+1))) + if ((newclock>=lowest_speed) && (newclock<=highest_speed)) + best = newclock; + } + return best; +} + +/* Determine nearest speed possible for the desired fsb speed */ +static unsigned int longhaul_validatespeed (unsigned int freq) +{ + unsigned int best=0; + + if (freqhighest_speed) + freq=highest_speed; + + if (can_scale_fsb==1) { + int fsb_index; + for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++) + best = longhaul_validatespeed_fsb (freq, fsb_search_table[fsb_index], best); + } else { + /* Can only scale multiplier. */ + best = longhaul_validatespeed_fsb (freq, current_fsb, best); + } + + return best; +} + +/* + * longhaul_set_cpu_frequency() + * This gets passed a MHz value that has been preprocessed + * with longhaul_validatespeed(). + * + * Note this function is only called if a new frequency has been selected. + */ + +static void longhaul_set_cpu_frequency (unsigned int Mhz) +{ + int index; + unsigned int bestfsb=-1; + unsigned long lo, hi; + int bits=-1; + int revkey; + int vidindex, i; + + /* Find out which mult bit-pattern & FSB we want */ + for (index=0; index>18; + return eblcr_fsb_table[invalue]; + } else { + return current_fsb; + } +} + + +static int __init longhaul_get_cpu_mult (void) +{ + unsigned long invalue=0,lo, hi; + + rdmsr (0x2a, lo, hi); + invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; + if (longhaul==3) { + if (lo & (1<<27)) + invalue+=16; + } + return eblcr_table[invalue]; +} + + +static void __init longhaul_get_ranges (void) +{ + unsigned long lo, hi, invalue; + unsigned int minmult=0, maxmult=0, minfsb=0, maxfsb=0; + unsigned int multipliers[32]= { + 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, + -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 }; + unsigned int fsb_table[4] = { 133, 100, -1, 66 }; + + switch (longhaul) { + case 1: + //FIXME: fill in from datasheet + break; + + case 2 ... 3: + rdmsr (0x110a, lo, hi); + + invalue = (hi & (1<<0|1<<1|1<<2|1<<3)); + if (hi & (1<<11)) + invalue += 16; + maxmult=multipliers[invalue]; + + #if 0 /* This is MaxMhz @ Min Voltage. Ignore for now */ + invalue = (hi & (1<<16|1<<17|1<<18|1<<19)) >> 16; + if (hi & (1<<27)) + invalue += 16; + minmult = multipliers[invalue]; + #else + minmult = 3; /* as per spec */ + #endif + + if (can_scale_fsb==1) { + invalue = (hi & (1<<9|1<<10)) >> 9; + maxfsb = fsb_table[invalue]; + + invalue = (hi & (1<<25|1<<26)) >> 25; + minfsb = fsb_table[invalue]; + + dprintk (KERN_INFO "longhaul: Min FSB=%d Max FSB=%d\n", + minfsb, maxfsb); + } else { + minfsb = maxfsb = current_fsb; + } + break; + } + + highest_speed = get_clock_from_ratio(maxmult, maxfsb); + lowest_speed = get_clock_from_ratio(minmult, minfsb); + + dprintk (KERN_INFO "longhaul: MinMult(x10)=%d MaxMult(x10)=%d\n", + minmult, maxmult); + dprintk (KERN_INFO "longhaul: Lowestspeed=%d Highestspeed=%d\n", + lowest_speed, highest_speed); +} + + +static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned long hi) +{ + int revkey; + + can_scale_voltage = 1; + + minvid = (hi & (1<<20|1<<21|1<<22|1<<23|1<<24)) >> 20; /* 56:52 */ + maxvid = (hi & (1<<4|1<<5|1<<6|1<<7|1<<8)) >> 4; /* 40:36 */ + vrmrev = (lo & (1<<15))>>15; + + if (vrmrev==0) { + dprintk (KERN_INFO "longhaul: VRM 8.5 : "); + memcpy (voltage_table, vrm85scales, sizeof(voltage_table)); + numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25; + } else { + dprintk (KERN_INFO "longhaul: Mobile VRM : "); + memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table)); + numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5; + } + + /* Current voltage isn't readable at first, so we need to + set it to a known value. The spec says to use maxvid */ + revkey = (lo & 0xf)<<4; /* Rev key. */ + lo &= 0xfe0fff0f; /* Mask unneeded bits */ + lo |= (1<<9); /* EnableSoftVID */ + lo |= revkey; /* Reinsert key */ + lo |= maxvid << 20; + wrmsr (0x110a, lo, hi); + minvid = voltage_table[minvid]; + maxvid = voltage_table[maxvid]; + dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n", + maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales); +} + + +static int __init longhaul_init (void) +{ + struct cpuinfo_x86 *c = cpu_data; + unsigned int currentspeed; + static int currentmult; + unsigned long lo, hi; + int ret; + struct cpufreq_driver driver; + + if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) ) + return -ENODEV; + + switch (c->x86_model) { + case 6: /* VIA C3 Samuel C5A */ + return -ENODEV; // See line 499 + longhaul=1; + memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio)); + memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr)); + break; + + case 7: /* C5B / C5C */ + switch (c->x86_mask) { + case 0: + return -ENODEV; // See line 499 + longhaul=1; + memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio)); + memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr)); + break; + case 1 ... 15: + longhaul=2; + memcpy (clock_ratio, longhaul2_clock_ratio, sizeof(longhaul2_clock_ratio)); + memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr)); + break; + } + break; + + case 8: /* C5M/C5N */ + return -ENODEV; // Waiting on updated docs from VIA before this is usable + longhaul=3; + numscales=32; + memcpy (clock_ratio, longhaul3_clock_ratio, sizeof(longhaul3_clock_ratio)); + memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr)); + break; + + default: + printk (KERN_INFO "longhaul: Unknown VIA CPU. Contact davej@suse.de\n"); + return -ENODEV; + } + + printk (KERN_INFO "longhaul: VIA CPU detected. Longhaul version %d supported\n", longhaul); + + if (favour_fast_fsb==1) + fsb_search_table = perf_fsb_table; + else + fsb_search_table = power_fsb_table; + + current_fsb = longhaul_get_cpu_fsb(); + currentmult = longhaul_get_cpu_mult(); + currentspeed = get_clock_from_ratio(currentmult, current_fsb); + + dprintk (KERN_INFO "longhaul: CPU currently at %dMHz (%d x %d.%d)\n", + currentspeed, current_fsb, currentmult/10, currentmult%10); + + if (longhaul==2 || longhaul==3) { + rdmsr (0x110a, lo, hi); + if ((lo & (1<<0)) && (dont_scale_voltage==0)) + longhaul_setup_voltagescaling (lo, hi); + + if ((lo & (1<<1)) && (dont_scale_fsb==0) && (current_fsb==0)) + can_scale_fsb = 1; + } + + longhaul_get_ranges(); + + driver.freq.min = (unsigned int) lowest_speed * 1000; + driver.freq.max = (unsigned int) highest_speed * 1000; + driver.freq.cur = currentspeed * 1000; + driver.validate = &longhaul_validatespeed; + driver.setspeed = &longhaul_set_cpu_frequency; + + ret = cpufreq_register(driver); + + if (ret) { + longhaul = 0; + return ret; + } + + return 0; +} + + +static void __exit longhaul_exit (void) +{ + if (longhaul) + cpufreq_unregister(); +} + +MODULE_PARM (dont_scale_fsb, "i"); +MODULE_PARM (dont_scale_voltage, "i"); +MODULE_PARM (current_fsb, "i"); +MODULE_PARM (favour_fast_fsb, "i"); + +MODULE_AUTHOR ("Dave Jones "); +MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); +MODULE_LICENSE ("GPL"); + +module_init(longhaul_init); +module_exit(longhaul_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/Makefile linux.20pre2-ac1/arch/i386/kernel/Makefile --- linux.20pre2/arch/i386/kernel/Makefile 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/Makefile 2002-08-12 15:11:54.000000000 +0100 @@ -14,7 +14,7 @@ O_TARGET := kernel.o -export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o +export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ @@ -40,5 +40,11 @@ obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o acpitable.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o +obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o +obj-$(CONFIG_X86_LONGHAUL) += longhaul.o +obj-$(CONFIG_X86_SPEEDSTEP) += speedstep.o +obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o +obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o + include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/mpparse.c linux.20pre2-ac1/arch/i386/kernel/mpparse.c --- linux.20pre2/arch/i386/kernel/mpparse.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/mpparse.c 2002-08-13 14:05:11.000000000 +0100 @@ -12,6 +12,7 @@ * Maciej W. Rozycki : Bits for default MP configurations */ +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include /* Have we found an MP table */ int smp_found_config; @@ -35,18 +37,20 @@ * MP-table. */ int apic_version [MAX_APICS]; -int mp_bus_id_to_type [MAX_MP_BUSSES]; -int mp_bus_id_to_node [MAX_MP_BUSSES]; -int mp_bus_id_to_local [MAX_MP_BUSSES]; int quad_local_to_mp_bus_id [NR_CPUS/4][4]; -int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_current_pci_id; +int *mp_bus_id_to_type; +int *mp_bus_id_to_node; +int *mp_bus_id_to_local; +int *mp_bus_id_to_pci_bus; +int max_mp_busses; +int max_irq_sources; /* I/O APIC entries */ struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; /* # of MP IRQ source entries */ -struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; +struct mpc_config_intsrc *mp_irqs; /* MP IRQ source entries */ int mp_irq_entries; @@ -64,6 +68,16 @@ /* Bitmask of physically existing CPUs */ unsigned long phys_cpu_present_map; +unsigned long logical_cpu_present_map; + +unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC; +unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL; +unsigned char int_delivery_mode = dest_LowestPrio; +unsigned char clustered_apic_mode = 0; +unsigned char esr_disable = 0; + +unsigned char raw_phys_apicid[NR_CPUS] = { 0 }; + /* * Intel MP BIOS table parsing routines: @@ -146,8 +160,8 @@ if (!(m->mpc_cpuflag & CPU_ENABLED)) return; - logical_apicid = m->mpc_apicid; - if (clustered_apic_mode) { + logical_apicid = 0x01; + if (clustered_apic_logical) { quad = translation_table[mpc_record]->trans_quad; logical_apicid = (quad << 4) + (m->mpc_apicid ? m->mpc_apicid << 1 : 1); @@ -223,15 +237,14 @@ if (m->mpc_apicid > MAX_APICS) { printk("Processor #%d INVALID. (Max ID: %d).\n", m->mpc_apicid, MAX_APICS); + --num_processors; return; } ver = m->mpc_apicver; - if (clustered_apic_mode) { - phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad); - } else { - phys_cpu_present_map |= 1 << m->mpc_apicid; - } + logical_cpu_present_map |= 1 << (num_processors-1); + phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid); + /* * Validate version */ @@ -240,6 +253,7 @@ ver = 0x10; } apic_version[m->mpc_apicid] = ver; + raw_phys_apicid[num_processors - 1] = m->mpc_apicid; } static void __init MP_bus_info (struct mpc_config_bus *m) @@ -250,7 +264,7 @@ memcpy(str, m->mpc_bustype, 6); str[6] = 0; - if (clustered_apic_mode) { + if (clustered_apic_logical) { quad = translation_table[mpc_record]->trans_quad; mp_bus_id_to_node[m->mpc_busid] = quad; mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local; @@ -304,7 +318,7 @@ m->mpc_irqtype, m->mpc_irqflag & 3, (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus, m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq); - if (++mp_irq_entries == MAX_IRQ_SOURCES) + if (++mp_irq_entries == max_irq_sources) panic("Max # of irq sources exceeded!!\n"); } @@ -394,9 +408,17 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) { - char str[16]; + char oem[16], prod[14]; int count=sizeof(*mpc); unsigned char *mpt=((unsigned char *)mpc)+count; + int num_bus = 0; + int num_irq = 0; + unsigned char *bus_data; + int xapic = 0; + int numaq = 0; + static const char *mode_names[] = { + "Flat", "Clustered Logical", "Clustered Physical", "???" + }; if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) { panic("SMP mptable: bad signature [%c%c%c%c]!\n", @@ -419,13 +441,21 @@ printk(KERN_ERR "SMP mptable: null local APIC address!\n"); return 0; } - memcpy(str,mpc->mpc_oem,8); - str[8]=0; - printk("OEM ID: %s ",str); - - memcpy(str,mpc->mpc_productid,12); - str[12]=0; - printk("Product ID: %s ",str); + memcpy(oem,mpc->mpc_oem,8); + oem[8]=0; + printk("OEM ID: %s ",oem); + + memcpy(prod,mpc->mpc_productid,12); + prod[12]=0; + printk("Product ID: %s ",prod); + + /* + * Can't recognize Summit xAPICs at present, so use the OEM ID. + */ + if (!strncmp(oem, "IBM ENSW", 8) && (!strncmp(prod, "NF 6000R", 8) || !strncmp(prod, "VIGIL SMP", 9))) + xapic = 2; + else if (!strncmp(oem, "IBM NUMA", 8)) + numaq = 1; printk("APIC at: 0x%lX\n",mpc->mpc_lapic); @@ -435,16 +465,77 @@ if (!have_acpi_tables) mp_lapic_addr = mpc->mpc_lapic; - if (clustered_apic_mode && mpc->mpc_oemptr) { + if (clustered_apic_logical && mpc->mpc_oemptr) { /* We need to process the oem mpc tables to tell us which quad things are in ... */ mpc_record = 0; smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize); mpc_record = 0; } + /* Pre-scan to determine the number of bus and + * interrupts records we have + */ + while (count < mpc->mpc_length) { + switch (*mpt) { + case MP_PROCESSOR: + mpt += sizeof(struct mpc_config_processor); + count += sizeof(struct mpc_config_processor); + break; + case MP_BUS: + ++num_bus; + mpt += sizeof(struct mpc_config_bus); + count += sizeof(struct mpc_config_bus); + break; + case MP_INTSRC: + ++num_irq; + mpt += sizeof(struct mpc_config_intsrc); + count += sizeof(struct mpc_config_intsrc); + break; + case MP_IOAPIC: + mpt += sizeof(struct mpc_config_ioapic); + count += sizeof(struct mpc_config_ioapic); + break; + case MP_LINTSRC: + mpt += sizeof(struct mpc_config_lintsrc); + count += sizeof(struct mpc_config_lintsrc); + break; + default: + count = mpc->mpc_length; + break; + } + } + /* + * Paranoia: Allocate one extra of both the number of busses and number + * of irqs, and make sure that we have at least 4 interrupts per PCI + * slot. But some machines do not report very many busses, so we need + * to fall back on the older defaults. + */ + ++num_bus; + max_mp_busses = max(num_bus, MAX_MP_BUSSES); + if (num_irq < (4 * max_mp_busses)) + num_irq = 4 * num_bus; /* 4 intr/PCI slot */ + ++num_irq; + max_irq_sources = max(num_irq, MAX_IRQ_SOURCES); + + count = (max_mp_busses * sizeof(int)) * 4; + count += (max_irq_sources * sizeof(struct mpc_config_intsrc)); + bus_data = alloc_bootmem(count); + if (!bus_data) { + printk(KERN_ERR "SMP mptable: out of memory!\n"); + return 0; + } + mp_bus_id_to_type = (int *)&bus_data[0]; + mp_bus_id_to_node = (int *)&bus_data[(max_mp_busses * sizeof(int))]; + mp_bus_id_to_local = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 2]; + mp_bus_id_to_pci_bus = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 3]; + mp_irqs = (struct mpc_config_intsrc *)&bus_data[(max_mp_busses * sizeof(int)) * 4]; + memset(mp_bus_id_to_pci_bus, -1, max_mp_busses); + /* * Now process the configuration blocks. */ + count = sizeof(*mpc); + mpt = ((unsigned char *)mpc)+count; while (count < mpc->mpc_length) { switch(*mpt) { case MP_PROCESSOR: @@ -504,6 +595,20 @@ } ++mpc_record; } + if (xapic || numaq) { + if (numaq) + xapic = 0; /* NUMA-Q boxes never had xAPICs */ + clustered_apic_mode = (u8)(xapic | numaq); + esr_disable = 1; + apic_broadcast_id = (xapic ? APIC_BROADCAST_ID_XAPIC : APIC_BROADCAST_ID_APIC); + int_dest_addr_mode = (xapic ? APIC_DEST_PHYSICAL : APIC_DEST_LOGICAL); + int_delivery_mode = (xapic ? dest_Fixed : dest_LowestPrio); + phys_cpu_present_map = logical_cpu_present_map; + /* There isnt a single clock source on these boxen */ + disable_tsc(); + } + printk("Enabling APIC mode: %s. Using %d I/O APICs\n", + mode_names[clustered_apic_mode], nr_ioapics); if (!num_processors) printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; @@ -799,18 +904,16 @@ * there is a real-mode segmented pointer pointing to the * 4K EBDA area at 0x40E, calculate and scan it here. * - * NOTE! There are Linux loaders that will corrupt the EBDA + * NOTE! There were Linux loaders that will corrupt the EBDA * area, and as such this kind of SMP config may be less * trustworthy, simply because the SMP table may have been - * stomped on during early boot. These loaders are buggy and - * should be fixed. + * stomped on during early boot. Thankfully the bootloaders + * now honour the EBDA. */ address = *(unsigned short *)phys_to_virt(0x40E); address <<= 4; smp_scan_config(address, 0x1000); - if (smp_found_config) - printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n"); } #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/nmi.c linux.20pre2-ac1/arch/i386/kernel/nmi.c --- linux.20pre2/arch/i386/kernel/nmi.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/nmi.c 2002-08-06 15:42:19.000000000 +0100 @@ -343,7 +343,7 @@ */ int sum, cpu = smp_processor_id(); - sum = apic_timer_irqs[cpu]; + sum = irq_stat[cpu].apic_timer_irqs; if (last_irq_sums[cpu] == sum) { /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/p4-clockmod.c linux.20pre2-ac1/arch/i386/kernel/p4-clockmod.c --- linux.20pre2/arch/i386/kernel/p4-clockmod.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/p4-clockmod.c 2002-08-06 15:42:19.000000000 +0100 @@ -0,0 +1,233 @@ +/* + * Pentium 4/Xeon CPU on demand clock modulation/speed scaling + * (C) 2002 Zwane Mwaikambo + * (C) 2002 Tora T. Engstad + * (C) 2002 Arjan van de Ven + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + * Date Errata Description + * 20020525 N44, O17 12.5% or 25% DC causes lockup + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* i'll be submitting a patch to lkml for this */ +#ifndef MSR_IA32_THERM_CONTROL +#define MSR_IA32_THERM_CONTROL 0x19a +#endif +#ifndef MSR_IA32_THERM_STATUS +#define MSR_IA32_THERM_STATUS 0x19c +#endif + +#define PFX "cpufreq: " + +/* + * Duty Cycle (3bits), note DC_DISABLE is not specified in + * intel docs i just use it to mean disable + */ +enum { + DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT, + DC_64PT, DC_75PT, DC_88PT, DC_DISABLE +}; + +static int cycle_table[8][2] = { + {13, DC_DFLT }, + {25, DC_25PT }, + {38, DC_38PT }, + {50, DC_50PT }, + {64, DC_64PT }, + {75, DC_75PT }, + {88, DC_88PT }, + {100, DC_DISABLE} }; + +static int has_N44_O17_errata; +static int stock_freq; +MODULE_PARM(stock_freq, "i"); + +static unsigned int cpufreq_p4_initialised; + +static int cpufreq_p4_validatedc(unsigned int percent, unsigned int *pct) +{ + u32 l, h; + int dc = DC_DISABLE, cpu = smp_processor_id(); + int i; + + /* FYI: Thermal monitor takes precedence and does a 50% DC modulation + * so we'll just return the thermal throttled settings to keep everybody + * happy. returning -EBUSY would have been better. + * + * I disagree; if we want to set the percentage LOWER than the thermal throttle + * we should allow that so that it takes effect once the thermal throttle situation + * ends -- Arjan + */ + + rdmsr(MSR_IA32_THERM_STATUS, l, h); + if (l & 0x01) { + printk(KERN_INFO PFX "CPU#%d currently thermal throttled\n", cpu); + if (percent > 50) + goto done; + dc = DC_50PT; + *pct = 50; + goto done; + } + + dc = DC_DFLT; + *pct = 13; + + + /* look up the closest (but lower) duty cycle in the table */ + for (i=0; i<8; i++) + if (percent <= cycle_table[i][0]) { + dc = cycle_table[i][1]; + *pct = cycle_table[i][0]; + break; + } + + + if (has_N44_O17_errata && (dc == DC_25PT || dc == DC_DFLT)) { + dc = DC_38PT; + *pct = 38; + } + +done: + return dc; +} + +static int cpufreq_p4_setdc(unsigned int percent) +{ + u32 l, h; + int pct, dc, cpu = smp_processor_id(); + + dc = cpufreq_p4_validatedc(percent, &pct); + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + + if (dc == DC_DISABLE) { + printk(KERN_INFO PFX "CPU#%d disabling modulation\n", cpu); + wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + } else { + printk(KERN_INFO PFX "CPU#%d setting duty cycle to %d%%\n", cpu, pct); + /* bits 63 - 5 : reserved + * bit 4 : enable/disable + * bits 3-1 : duty cycle + * bit 0 : reserved + */ + l = (l & ~14); + l = l | (1<<4) | ((dc & 0x7)<<1); + wrmsr(MSR_IA32_THERM_CONTROL, l, h); + } + + return 0; +} + +static unsigned int cpufreq_p4_validate_speed(unsigned int khz) +{ + unsigned int percent, valid_percent, valid_khz; + + percent = (khz * 100) / stock_freq; + cpufreq_p4_validatedc(percent, &valid_percent); + valid_khz = (stock_freq * valid_percent) / 100; + + return valid_khz; +} + +static void cpufreq_p4_set_cpuspeed(unsigned int khz) +{ + unsigned int percent; + + percent = (khz * 100) / stock_freq; + cpufreq_p4_setdc(percent); +} + +int __init cpufreq_p4_init(void) +{ + u32 l, h; + struct cpuinfo_x86 *c = cpu_data; + int cpu = smp_processor_id(); + int cpuid; + int ret; + struct cpufreq_driver driver; + + /* + * THERM_CONTROL is architectural for IA32 now, so + * we can rely on the capability checks + */ + if (c->x86_vendor != X86_VENDOR_INTEL) + return -ENODEV; + + if (!test_bit(X86_FEATURE_ACPI, c->x86_capability) || + !test_bit(X86_FEATURE_ACC, c->x86_capability)) + return -ENODEV; + + /* Errata workarounds */ + cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; + switch (cpuid) { + case 0x0f07: + case 0x0f0a: + case 0x0f11: + case 0x0f12: + has_N44_O17_errata = 1; + default: + break; + } + + printk(KERN_INFO PFX "CPU#%d P4/Xeon(TM) CPU On-Demand Clock Modulation available\n", cpu); + + stock_freq = cpu_khz; /* ugg :( */ + + if (!stock_freq) + return -ENODEV; + + driver.freq.cur=cpu_khz; + driver.freq.min=cpu_khz/10; + driver.freq.max=stock_freq; + driver.validate=&cpufreq_p4_validate_speed; + driver.setspeed=&cpufreq_p4_set_cpuspeed; + + ret = cpufreq_register(driver); + if (ret) + return ret; + + cpufreq_p4_initialised = 1; + + return 0; +} + + +void __exit cpufreq_p4_exit(void) +{ + u32 l, h; + + if (cpufreq_p4_initialised) { + cpufreq_unregister(); + /* return back to a non modulated state */ + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + cpufreq_p4_initialised = 0; + } +} + +MODULE_AUTHOR ("Zwane Mwaikambo "); +MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_p4_init); +module_exit(cpufreq_p4_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/pci-i386.c linux.20pre2-ac1/arch/i386/kernel/pci-i386.c --- linux.20pre2/arch/i386/kernel/pci-i386.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/pci-i386.c 2002-08-13 16:40:45.000000000 +0100 @@ -303,7 +303,7 @@ pcibios_assign_resources(); } -int pcibios_enable_resources(struct pci_dev *dev) +int pcibios_enable_resources(struct pci_dev *dev, int mask) { u16 cmd, old_cmd; int idx; @@ -312,6 +312,10 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; for(idx=0; idx<6; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1<resource[idx]; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/pci-i386.h linux.20pre2-ac1/arch/i386/kernel/pci-i386.h --- linux.20pre2/arch/i386/kernel/pci-i386.h 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/pci-i386.h 2002-08-06 15:42:19.000000000 +0100 @@ -29,7 +29,7 @@ extern unsigned int pcibios_max_latency; void pcibios_resource_survey(void); -int pcibios_enable_resources(struct pci_dev *); +int pcibios_enable_resources(struct pci_dev *, int); /* pci-pc.c */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/pci-irq.c linux.20pre2-ac1/arch/i386/kernel/pci-irq.c --- linux.20pre2/arch/i386/kernel/pci-irq.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/pci-irq.c 2002-08-06 15:42:19.000000000 +0100 @@ -22,6 +22,8 @@ #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) #define PIRQ_VERSION 0x0100 +int broken_hp_bios_irq9; + static struct irq_routing_table *pirq_table; /* @@ -596,6 +598,15 @@ DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs); mask &= pcibios_irq_mask; + /* Work around broken HP Pavilion Notebooks which assign USB to + IRQ 9 even though it is actually wired to IRQ 11 */ + + if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) { + dev->irq = 11; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); + r->set(pirq_router_dev, dev, pirq, 11); + } + /* * Find the best IRQ to assign: use the one * reported by the device if possible. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/pci-pc.c linux.20pre2-ac1/arch/i386/kernel/pci-pc.c --- linux.20pre2/arch/i386/kernel/pci-pc.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/pci-pc.c 2002-08-13 22:37:18.000000000 +0100 @@ -54,11 +54,11 @@ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */ +static int pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */ { unsigned long flags; - if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if (bus > 255 || dev > 31 || fn > 7 || reg > 255) return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); @@ -82,11 +82,11 @@ return 0; } -static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */ +static int pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */ { unsigned long flags; - if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if (bus > 255 || dev > 31 || fn > 7 || reg > 255) return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); @@ -110,7 +110,69 @@ return 0; } -#else /* !CONFIG_MULTIQUAD */ +static int pci_conf1_read_mq_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + int result; + u32 data; + + result = pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, &data); + + *value = (u8)data; + + return result; +} + +static int pci_conf1_read_mq_config_word(struct pci_dev *dev, int where, u16 *value) +{ + int result; + u32 data; + + result = pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, &data); + + *value = (u16)data; + + return result; +} + +static int pci_conf1_read_mq_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + if (!value) + return -EINVAL; + + return pci_conf1_mq_read(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); +} + +static int pci_conf1_write_mq_config_byte(struct pci_dev *dev, int where, u8 value) +{ + return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 1, value); +} + +static int pci_conf1_write_mq_config_word(struct pci_dev *dev, int where, u16 value) +{ + return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 2, value); +} + +static int pci_conf1_write_mq_config_dword(struct pci_dev *dev, int where, u32 value) +{ + return pci_conf1_mq_write(0, dev->bus->number, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), where, 4, value); +} + +static struct pci_ops pci_direct_mq_conf1 = { + pci_conf1_read_mq_config_byte, + pci_conf1_read_mq_config_word, + pci_conf1_read_mq_config_dword, + pci_conf1_write_mq_config_byte, + pci_conf1_write_mq_config_word, + pci_conf1_write_mq_config_dword +}; + +#endif /* !CONFIG_MULTIQUAD */ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) @@ -118,7 +180,7 @@ { unsigned long flags; - if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if (bus > 255 || dev > 31 || fn > 7 || reg > 255) return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); @@ -146,7 +208,7 @@ { unsigned long flags; - if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); @@ -170,8 +232,6 @@ return 0; } -#endif /* CONFIG_MULTIQUAD */ - #undef PCI_CONF1_ADDRESS static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) @@ -179,9 +239,6 @@ int result; u32 data; - if (!value) - return -EINVAL; - result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 1, &data); @@ -195,9 +252,6 @@ int result; u32 data; - if (!value) - return -EINVAL; - result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 2, &data); @@ -208,9 +262,6 @@ static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - if (!value) - return -EINVAL; - return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 4, value); } @@ -253,7 +304,7 @@ { unsigned long flags; - if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if (bus > 255 || dev > 31 || fn > 7 || reg > 255) return -EINVAL; if (dev & 0x10) @@ -287,7 +338,7 @@ { unsigned long flags; - if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) return -EINVAL; if (dev & 0x10) @@ -423,6 +474,12 @@ __restore_flags(flags); printk(KERN_INFO "PCI: Using configuration type 1\n"); request_region(0xCF8, 8, "PCI conf1"); + +#ifdef CONFIG_MULTIQUAD + /* Multi-Quad has an extended PCI Conf1 */ + if(clustered_apic_mode) + return &pci_direct_mq_conf1; +#endif return &pci_direct_conf1; } outl (tmp, 0xCF8); @@ -640,7 +697,7 @@ unsigned long flags; unsigned long bx = ((bus << 8) | (dev << 3) | fn); - if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if (bus > 255 || dev > 31 || fn > 7 || reg > 255) return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); @@ -695,7 +752,7 @@ unsigned long flags; unsigned long bx = ((bus << 8) | (dev << 3) | fn); - if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if ((bus > 255 || dev > 31 || fn > 7 || reg > 255)) return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); @@ -750,7 +807,7 @@ u32 data; if (!value) - return -EINVAL; + BUG(); result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 1, &data); @@ -766,7 +823,7 @@ u32 data; if (!value) - return -EINVAL; + BUG(); result = pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 2, &data); @@ -779,7 +836,7 @@ static int pci_bios_read_config_dword(struct pci_dev *dev, int where, u32 *value) { if (!value) - return -EINVAL; + BUG(); return pci_bios_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 4, value); @@ -1227,6 +1284,11 @@ pci_read_config_byte(d, PCI_REVISION_ID, &revision); if (d->device == PCI_DEVICE_ID_VIA_8367_0) { + /* fix pci bus latency issues resulted by NB bios error + it appears on bug free^Wreduced kt266x's bios forces + NB latency to zero */ + pci_write_config_byte(d, PCI_LATENCY_TIMER, 0); + where = 0x95; /* the memory write queue timer register is different for the KT266x's: 0x95 not 0x55 */ } else if (d->device == PCI_DEVICE_ID_VIA_8363_0 && @@ -1281,6 +1343,11 @@ * both PCI BIOS and direct access, with a preference for direct. */ +#ifdef CONFIG_PCI_DIRECT + struct pci_ops *tmp = NULL; +#endif + + #ifdef CONFIG_PCI_BIOS if ((pci_probe & PCI_PROBE_BIOS) && ((pci_root_ops = pci_find_bios()))) { @@ -1293,7 +1360,8 @@ #ifdef CONFIG_PCI_DIRECT if ((pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2)) - && (pci_root_ops = pci_check_direct())) { + && (tmp = pci_check_direct())) { + pci_root_ops = tmp; if (pci_root_ops == &pci_direct_conf1) { pci_config_read = pci_conf1_read; pci_config_write = pci_conf1_write; @@ -1393,11 +1461,11 @@ return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; } -int pcibios_enable_device(struct pci_dev *dev) +int pcibios_enable_device(struct pci_dev *dev, int mask) { int err; - if ((err = pcibios_enable_resources(dev)) < 0) + if ((err = pcibios_enable_resources(dev, mask)) < 0) return err; pcibios_enable_irq(dev); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/pci-visws.c linux.20pre2-ac1/arch/i386/kernel/pci-visws.c --- linux.20pre2/arch/i386/kernel/pci-visws.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/pci-visws.c 2002-08-06 15:42:19.000000000 +0100 @@ -131,9 +131,9 @@ return str; } -int pcibios_enable_device(struct pci_dev *dev) +int pcibios_enable_device(struct pci_dev *dev, int mask) { - return pcibios_enable_resources(dev); + return pcibios_enable_resources(dev, mask); } void __init pcibios_penalize_isa_irq(irq) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/powernow-k6.c linux.20pre2-ac1/arch/i386/kernel/powernow-k6.c --- linux.20pre2/arch/i386/kernel/powernow-k6.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/powernow-k6.c 2002-08-06 15:42:19.000000000 +0100 @@ -0,0 +1,123 @@ +/* + * $Id: powernow-k6.c,v 1.18 2002/06/12 14:37:27 db Exp $ + * This file is part of Powertweak Linux (http://www.powertweak.org) + * and is shared with the Linux Kernel module. + * + * (C) 2000, 2001 Dave Jones, Arjan van de Ven, Janne Pänkälä. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * Version $Id: powernow-k6.c,v 1.18 2002/06/12 14:37:27 db Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long cpu_khz=350000; + +/* Clock ratio multiplied by 10 */ +static int clock_ratio[8] = { + 45, /* 000 -> 4.5x */ + 50, /* 001 -> 5.0x */ + 40, /* 010 -> 4.0x */ + 55, /* 011 -> 5.5x */ + 20, /* 100 -> 2.0x */ + 30, /* 101 -> 3.0x */ + 60, /* 110 -> 6.0x */ + 35 /* 111 -> 3.5x */ +}; + +static unsigned int clock_bogomips[8]; + +static unsigned int busfreq; +unsigned int minfreq,maxfreq; + +void set_cpu_frequency_K6(unsigned int Mhz) +{ + int i; + unsigned int best=200; /* safe initial values */ + unsigned int besti=4; + unsigned long outvalue=0,invalue=0; + unsigned long msrval; + + /* Find out which bit-pattern we want */ + + for (i=0;i<8;i++) { + unsigned int newclock; + newclock = (clock_ratio[i]*busfreq/10); + if ((newclock > best) && (newclock <= (Mhz+1))) { + /* +1 is for compensating rounding errors */ + best = newclock; + besti = i; + } + } + + /* "besti" now contains the bitpattern of the new multiplier. + we now need to transform it to the BVC format, see AMD#23446 */ + + outvalue = (1<<12) | (1<<10) | (1<<9) | (besti<<5); + + msrval = 0xFFF1; /* FIXME!! we should check if 0xfff0 is available */ + wrmsr(0xC0000086,msrval,0); /* enable the PowerNow port */ + invalue=inl(0xfff8); + invalue = invalue & 15; + outvalue = outvalue | invalue; + outl(outvalue ,0xFFF8); + msrval = 0xFFF0; + wrmsr(0xC0000086,msrval,0); /* disable it again */ + + /* now adjust bogomips */ + if (!clock_bogomips[besti]) { + /*scale_bogomips(clock_ratio[besti]);*/ + clock_bogomips[besti] = loops_per_jiffy; + } else { + loops_per_jiffy = clock_bogomips[besti]; + } +} + +static int get_cpu_multiplier(void) +{ + unsigned long invalue=0,msrval; + + + msrval = 0xFFF1; /* FIXME!! we should check if 0xfff0 is available */ + wrmsr(0xC0000086, msrval,0 ); /* enable the PowerNow port */ + invalue=inl(0xfff8); + msrval = 0xFFF0; + wrmsr(0xC0000086, msrval,0 ); /* disable it again */ + + printk("Clock ratio is %i\n",clock_ratio[(invalue >> 5)&7]); + return clock_ratio[(invalue >> 5)&7]; +} + +int PowerNow_k6plus_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) || + ((c->x86_model != 12) && (c->x86_model != 13))) + return -ENODEV; + + busfreq = cpu_khz / get_cpu_multiplier() / 100; + //cpufreq_init(0, 0, 0); + return 0; +} + +void PowerNow_k6plus_exit(void) +{ +} + +MODULE_AUTHOR ("Arjan van de Ven , Dave Jones "); +MODULE_DESCRIPTION ("Longhaul driver for AMD K6-2+ / K6-3+ processors."); + +MODULE_LICENSE ("GPL"); +module_init(PowerNow_k6plus_init); +module_exit(PowerNow_k6plus_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/process.c linux.20pre2-ac1/arch/i386/kernel/process.c --- linux.20pre2/arch/i386/kernel/process.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/process.c 2002-08-13 19:00:14.000000000 +0100 @@ -124,15 +124,12 @@ void cpu_idle (void) { /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - current->counter = -100; while (1) { void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; - while (!current->need_resched) + if (!current->need_resched) idle(); schedule(); check_pgt_cache(); @@ -187,7 +184,7 @@ } /* we will leave sorting out the final value when we are ready to reboot, since we might not - have set up boot_cpu_id or smp_num_cpu */ + have set up boot_cpu_physical_apicid or smp_num_cpu */ break; #endif } @@ -253,7 +250,7 @@ 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ 0x74, 0x02, /* jz f */ - 0x0f, 0x08, /* invd */ + 0x0f, 0x09, /* wbinvd */ 0x24, 0x10, /* f: andb $0x10,al */ 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ }; @@ -697,15 +694,17 @@ asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs)); /* - * Restore %fs and %gs. + * Restore %fs and %gs if needed. */ - loadsegment(fs, next->fs); - loadsegment(gs, next->gs); + if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) { + loadsegment(fs, next->fs); + loadsegment(gs, next->gs); + } /* * Now maybe reload the debug registers */ - if (next->debugreg[7]){ + if (unlikely(next->debugreg[7])) { loaddebug(next, 0); loaddebug(next, 1); loaddebug(next, 2); @@ -715,7 +714,7 @@ loaddebug(next, 7); } - if (prev->ioperm || next->ioperm) { + if (unlikely(prev->ioperm || next->ioperm)) { if (next->ioperm) { /* * 4 cachelines copy ... not good, but not that diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/semaphore.c linux.20pre2-ac1/arch/i386/kernel/semaphore.c --- linux.20pre2/arch/i386/kernel/semaphore.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/semaphore.c 2002-08-06 15:42:19.000000000 +0100 @@ -262,31 +262,30 @@ */ #if defined(CONFIG_SMP) asm( -" -.align 4 -.globl __write_lock_failed -__write_lock_failed: - " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) -1: rep; nop - cmpl $" RW_LOCK_BIAS_STR ",(%eax) - jne 1b - - " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) - jnz __write_lock_failed - ret - - -.align 4 -.globl __read_lock_failed -__read_lock_failed: - lock ; incl (%eax) -1: rep; nop - cmpl $1,(%eax) - js 1b +".text\n" +".align 4\n" +".globl __write_lock_failed\n" +"__write_lock_failed:\n\t" + LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax)\n" +"1: rep; nop\n\t" + "cmpl $" RW_LOCK_BIAS_STR ",(%eax)\n\t" + "jne 1b\n\t" + LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax)\n\t" + "jnz __write_lock_failed\n\t" + "ret" +); - lock ; decl (%eax) - js __read_lock_failed - ret -" +asm( +".text\n" +".align 4\n" +".globl __read_lock_failed\n" +"__read_lock_failed:\n\t" + LOCK "incl (%eax)\n" +"1: rep; nop\n\t" + "cmpl $1,(%eax)\n\t" + "js 1b\n\t" + LOCK "decl (%eax)\n\t" + "js __read_lock_failed\n\t" + "ret" ); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/setup.c linux.20pre2-ac1/arch/i386/kernel/setup.c --- linux.20pre2/arch/i386/kernel/setup.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/setup.c 2002-08-13 18:55:16.000000000 +0100 @@ -71,13 +71,6 @@ * CacheSize bug workaround updates for AMD, Intel & VIA Cyrix. * Dave Jones , September, October 2001. * - * Short-term fix for a conflicting cache attribute bug in the kernel - * that is exposed by advanced speculative caching on new AMD Athlon - * processors. - * Richard Brunner and Mark Langsdorf - * , June 2002 - * Adapted to work with uniprocessor APIC by Bryan O'Sullivan - * , June 2002. */ /* @@ -171,8 +164,6 @@ extern int root_mountflags; extern char _text, _etext, _edata, _end; -static int have_cpuid_p(void) __init; - static int disable_x86_serial_nr __initdata = 1; static int disable_x86_fxsr __initdata = 0; static int disable_x86_ht __initdata = 0; @@ -181,12 +172,6 @@ int enable_acpi_smp_table; -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -int disable_adv_spec_cache __initdata = 1; -#else -int disable_adv_spec_cache __initdata = 0; -#endif /* CONFIG_AGP */ - /* * This is set up by the setup-routine at boot-time */ @@ -745,41 +730,6 @@ } /* setup_memory_region */ -int __init amd_adv_spec_cache_feature(void) -{ - char vendor_id[16]; - int ident; - int family, model; - - /* Must have CPUID */ - if(!have_cpuid_p()) - goto donthave; - if(cpuid_eax(0)<1) - goto donthave; - - /* Must be x86 architecture */ - cpuid(0, &ident, - (int *)&vendor_id[0], - (int *)&vendor_id[8], - (int *)&vendor_id[4]); - - if (memcmp(vendor_id, "AuthenticAMD", 12)) - goto donthave; - - ident = cpuid_eax(1); - family = (ident >> 8) & 0xf; - model = (ident >> 4) & 0xf; - if (((family == 6) && (model >= 6)) || (family == 15)) { - printk(KERN_INFO "Advanced speculative caching feature present\n"); - return 1; - } - -donthave: - printk(KERN_INFO "Advanced speculative caching feature not present\n"); - return 0; -} - - static void __init parse_cmdline_early (char ** cmdline_p) { char c = ' ', *to = command_line, *from = COMMAND_LINE; @@ -845,17 +795,6 @@ */ else if (!memcmp(from, "highmem=", 8)) highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; - /* - * unsafe-gart-alias overrides the short-term fix for a - * conflicting cache attribute bug in the kernel that is - * exposed by advanced speculative caching in newer AMD - * Athlon processors. Overriding the fix will allow - * higher performance but the kernel bug can cause system - * lock-ups if the system uses an AGP card. unsafe-gart-alias - * can be turned on for higher performance in servers. - */ - else if (!memcmp(from, "unsafe-gart-alias", 17)) - disable_adv_spec_cache = 0; nextchar: c = *(from++); if (!c) @@ -885,7 +824,6 @@ #ifndef CONFIG_HIGHIO blk_nohighio = 1; #endif - ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; @@ -1124,14 +1062,6 @@ #ifdef CONFIG_SMP smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ #endif - /* - * short-term fix for a conflicting cache attribute bug in the - * kernel that is exposed by advanced speculative caching on - * newer AMD Athlon processors. - */ - if (disable_adv_spec_cache && amd_adv_spec_cache_feature()) - clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability); - paging_init(); #ifdef CONFIG_X86_LOCAL_APIC /* @@ -1201,26 +1131,50 @@ } __setup("cachesize=", cachesize_setup); - #ifndef CONFIG_X86_TSC + static int tsc_disable __initdata = 0; -static int __init tsc_setup(char *str) +void disable_tsc(void) { - tsc_disable = 1; + if(tsc_disable == 0) + { + printk(KERN_INFO "Disabling use of TSC for time counting.\n"); + tsc_disable = 1; + } +} + +/* Disable TSC on processor and also for get time of day */ + +static int __init notsc_setup(char *str) +{ + tsc_disable = 2; return 1; } -__setup("notsc", tsc_setup); -#endif +__setup("notsc", notsc_setup); -static int __init highio_setup(char *str) +/* Allow TSC use but don't use it for gettimeofday */ + +static int __init badtsc_setup(char *str) { - printk("i386: disabling HIGHMEM block I/O\n"); - blk_nohighio = 1; + tsc_disable = 1; return 1; } -__setup("nohighio", highio_setup); + +__setup("badtsc", badtsc_setup); + +#else + +#define tsc_disable 0 + +void disable_tsc(void) +{ + panic("Time stamp counter required by this kernel, but not supported by the hardware.\n"); +} + +#endif + static int __init get_model_name(struct cpuinfo_x86 *c) { @@ -1308,31 +1262,6 @@ l2size, ecx & 0xFF); } - -/*======================================================================= - * amd_adv_spec_cache_disable - * Setting a special MSR big that disables a small part of advanced - * speculative caching as part of a short-term fix for a conflicting cache - * attribute bug in the kernel that is exposed by advanced speculative - * caching in newer AMD Athlon processors. - =======================================================================*/ -static void amd_adv_spec_cache_disable(void) -{ - printk(KERN_INFO "Disabling advanced speculative caching\n"); - - __asm__ __volatile__ ( - " movl $0x9c5a203a,%%edi \n" /* msr enable */ - " movl $0xc0011022,%%ecx \n" /* msr addr */ - " rdmsr \n" /* get reg val */ - " orl $0x00010000,%%eax \n" /* set bit 16 */ - " wrmsr \n" /* put it back */ - " xorl %%edi, %%edi \n" /* clear msr enable */ - : /* no outputs */ - : /* no inputs, either */ - : "%eax","%ecx","%edx","%edi" /* clobbered regs */ ); -} - - /* * B step AMD K6 before B 9730xxxx have hardware bugs that can cause * misexecution of code under Linux. Owners of such processors should @@ -1466,21 +1395,10 @@ * to enable SSE on Palomino/Morgan CPU's. * If the BIOS didn't enable it already, enable it * here. - * - * Avoiding the use of 4MB/2MB pages along with - * setting a special MSR bit that disables a small - * part of advanced speculative caching as part of a - * short-term fix for a conflicting cache attribute - * bug in the kernel that is exposed by advanced - * speculative caching in newer AMD Atlon processors. - * - * If we cleared the PSE bit earlier as part - * of the workaround for this problem, we need - * to clear it again, as our caller may have - * clobbered it if uniprocessor APIC is enabled. */ - if (c->x86_model >= 6) { - if (!cpu_has_xmm) { + if (c->x86_model == 6 || c->x86_model == 7) { + if (!test_bit(X86_FEATURE_XMM, + &c->x86_capability)) { printk(KERN_INFO "Enabling Disabled K7/SSE Support...\n"); rdmsr(MSR_K7_HWCR, l, h); @@ -1489,18 +1407,6 @@ set_bit(X86_FEATURE_XMM, &c->x86_capability); } - if (disable_adv_spec_cache && - amd_adv_spec_cache_feature()) { - clear_bit(X86_FEATURE_PSE, - &c->x86_capability); - amd_adv_spec_cache_disable(); - } - } - break; - case 15: - if (disable_adv_spec_cache && amd_adv_spec_cache_feature()) { - clear_bit(X86_FEATURE_PSE, &c->x86_capability); - amd_adv_spec_cache_disable(); } break; @@ -1547,11 +1453,9 @@ } /* - * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in - * order to identify the Cyrix CPU model after we're out of setup.c - * - * Actually since bugs.h doesn't even reference this perhaps someone should - * fix the documentation ??? + * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in + * order to identify the Cyrix CPU model after we're out of the + * initial setup. */ static unsigned char Cx86_dir0_msb __initdata = 0; @@ -2355,6 +2259,20 @@ } } } + + /* Intel PIII Tualatin. This comes in two flavours. + * One has 256kb of cache, the other 512. We have no way + * to determine which, so we use a boottime override + * for the 512kb model, and assume 256 otherwise. + */ + if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) && + (c->x86_model == 11) && (l2 == 0)) + l2 = 256; + + /* Allow user to override all this if necessary. */ + if (cachesize_override != -1) + l2 = cachesize_override; + if ( l1i || l1d ) printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n", l1i, l1d); @@ -2855,10 +2773,8 @@ */ /* TSC disabled? */ -#ifndef CONFIG_X86_TSC - if ( tsc_disable ) + if ( tsc_disable > 1 ) clear_bit(X86_FEATURE_TSC, &c->x86_capability); -#endif /* HT disabled? */ if (disable_x86_ht) @@ -2914,17 +2830,31 @@ boot_cpu_data.x86_capability[2], boot_cpu_data.x86_capability[3]); } + + /* * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c */ -void __init dodgy_tsc(void) +int __init select_tsc(void) { get_cpu_vendor(&boot_cpu_data); if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX || boot_cpu_data.x86_vendor == X86_VENDOR_NSC ) init_cyrix(&boot_cpu_data); + + /* Cyclone needs to be added */ + + /* Is it disabled ? */ + if(tsc_disable) + return TSC_NONE; + + /* Does it exist ? */ + if(!cpu_has_tsc) + return TSC_NONE; + + return TSC_CPU; } @@ -2971,6 +2901,7 @@ * applications want to get the raw CPUID data, they should access * /dev/cpu//cpuid instead. */ + extern int phys_proc_id[NR_CPUS]; static char *x86_cap_flags[] = { /* Intel-defined */ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", @@ -3028,6 +2959,11 @@ /* Cache size */ if (c->x86_cache_size >= 0) seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); + +#ifdef CONFIG_SMP + seq_printf(m, "physical id\t: %d\n",phys_proc_id[n]); + seq_printf(m, "siblings\t: %d\n",smp_num_siblings); +#endif /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); @@ -3100,14 +3036,12 @@ if (cpu_has_vme || cpu_has_tsc || cpu_has_de) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); -#ifndef CONFIG_X86_TSC - if (tsc_disable && cpu_has_tsc) { + if (tsc_disable > 1 && cpu_has_tsc) { printk(KERN_NOTICE "Disabling TSC...\n"); /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); set_in_cr4(X86_CR4_TSD); } -#endif __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); __asm__ __volatile__("lidt %0": "=m" (idt_descr)); @@ -3132,9 +3066,10 @@ load_TR(nr); load_LDT(&init_mm); - /* - * Clear all 6 debug registers: - */ + /* Clear %fs and %gs. */ + asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); + + /* Clear all 6 debug registers: */ #define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/smpboot.c linux.20pre2-ac1/arch/i386/kernel/smpboot.c --- linux.20pre2/arch/i386/kernel/smpboot.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/smpboot.c 2002-08-09 11:24:14.000000000 +0100 @@ -58,7 +58,7 @@ /* Number of siblings per CPU package */ int smp_num_siblings = 1; -int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ +int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ /* Bitmask of currently online CPUs */ unsigned long cpu_online_map; @@ -365,7 +365,7 @@ * (This works even if the APIC is not enabled.) */ phys_id = GET_APIC_ID(apic_read(APIC_ID)); - cpuid = current->processor; + cpuid = cpu(); if (test_and_set_bit(cpuid, &cpu_online_map)) { printk("huh, phys CPU#%d, CPU#%d already present??\n", phys_id, cpuid); @@ -435,6 +435,7 @@ */ smp_store_cpu_info(cpuid); + disable_APIC_timer(); /* * Allow the master to continue. */ @@ -465,6 +466,7 @@ smp_callin(); while (!atomic_read(&smp_commenced)) rep_nop(); + enable_APIC_timer(); /* * low-memory mappings have been cleared, flush them from * the local TLBs too. @@ -509,59 +511,28 @@ return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } -/* which physical APIC ID maps to which logical CPU number */ -volatile int physical_apicid_2_cpu[MAX_APICID]; /* which logical CPU number maps to which physical APIC ID */ -volatile int cpu_2_physical_apicid[NR_CPUS]; +volatile u8 cpu_2_physical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; -/* which logical APIC ID maps to which logical CPU number */ -volatile int logical_apicid_2_cpu[MAX_APICID]; /* which logical CPU number maps to which logical APIC ID */ -volatile int cpu_2_logical_apicid[NR_CPUS]; +volatile u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; -static inline void init_cpu_to_apicid(void) -/* Initialize all maps between cpu number and apicids */ -{ - int apicid, cpu; - - for (apicid = 0; apicid < MAX_APICID; apicid++) { - physical_apicid_2_cpu[apicid] = -1; - logical_apicid_2_cpu[apicid] = -1; - } - for (cpu = 0; cpu < NR_CPUS; cpu++) { - cpu_2_physical_apicid[cpu] = -1; - cpu_2_logical_apicid[cpu] = -1; - } -} - -static inline void map_cpu_to_boot_apicid(int cpu, int apicid) +static inline void map_cpu_to_boot_apicid(int cpu, int phys_apicid, int log_apicid) /* - * set up a mapping between cpu and apicid. Uses logical apicids for multiquad, - * else physical apic ids + * set up a mapping between cpu and apicids. */ { - if (clustered_apic_mode) { - logical_apicid_2_cpu[apicid] = cpu; - cpu_2_logical_apicid[cpu] = apicid; - } else { - physical_apicid_2_cpu[apicid] = cpu; - cpu_2_physical_apicid[cpu] = apicid; - } + cpu_2_logical_apicid[cpu] = (u8) log_apicid; + cpu_2_physical_apicid[cpu] = (u8) phys_apicid; } -static inline void unmap_cpu_to_boot_apicid(int cpu, int apicid) +static inline void unmap_cpu_to_boot_apicid(int cpu) /* - * undo a mapping between cpu and apicid. Uses logical apicids for multiquad, - * else physical apic ids + * undo a mapping between cpu and apicids. */ { - if (clustered_apic_mode) { - logical_apicid_2_cpu[apicid] = -1; - cpu_2_logical_apicid[cpu] = -1; - } else { - physical_apicid_2_cpu[apicid] = -1; - cpu_2_physical_apicid[cpu] = -1; - } + cpu_2_logical_apicid[cpu] = BAD_APICID; + cpu_2_physical_apicid[cpu] = BAD_APICID; } #if APIC_DEBUG @@ -775,17 +746,13 @@ extern unsigned long cpu_initialized; -static void __init do_boot_cpu (int apicid) -/* - * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad - * (ie clustered apic addressing mode), this is a LOGICAL apic ID. - */ +static void __init do_boot_cpu (int phys_apicid, int log_apicid) { struct task_struct *idle; unsigned long boot_error = 0; int timeout, cpu; unsigned long start_eip; - unsigned short nmi_high, nmi_low; + unsigned short nmi_high = 0, nmi_low = 0; cpu = ++cpucount; /* @@ -803,22 +770,19 @@ if (!idle) panic("No idle process for CPU %d", cpu); - idle->processor = cpu; - idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ + init_idle(idle, cpu); - map_cpu_to_boot_apicid(cpu, apicid); + map_cpu_to_boot_apicid(cpu, phys_apicid, log_apicid); idle->thread.eip = (unsigned long) start_secondary; - del_from_runqueue(idle); unhash_process(idle); - init_tasks[cpu] = idle; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); /* So we see what's up */ - printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); + printk("Booting processor %d/%d eip %lx\n", cpu, log_apicid, start_eip); stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); /* @@ -830,7 +794,7 @@ Dprintk("Setting warm reset code and vector.\n"); - if (clustered_apic_mode) { + if (clustered_apic_logical) { /* stash the current NMI vector, so we can put things back */ nmi_high = *((volatile unsigned short *) TRAMPOLINE_HIGH); nmi_low = *((volatile unsigned short *) TRAMPOLINE_LOW); @@ -847,7 +811,7 @@ /* * Be paranoid about clearing APIC errors. */ - if (!clustered_apic_mode && APIC_INTEGRATED(apic_version[apicid])) { + if (!clustered_apic_mode && APIC_INTEGRATED(apic_version[phys_apicid])) { apic_read_around(APIC_SPIV); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); @@ -862,10 +826,10 @@ * Starting actual IPI sequence... */ - if (clustered_apic_mode) - boot_error = wakeup_secondary_via_NMI(apicid); + if (clustered_apic_logical) + boot_error = wakeup_secondary_via_NMI(log_apicid); else - boot_error = wakeup_secondary_via_INIT(apicid, start_eip); + boot_error = wakeup_secondary_via_INIT(phys_apicid, start_eip); if (!boot_error) { /* @@ -901,13 +865,13 @@ printk("Not responding.\n"); #if APIC_DEBUG if (!clustered_apic_mode) - inquire_remote_apic(apicid); + inquire_remote_apic(phys_apicid); #endif } } if (boot_error) { /* Try to put things back the way they were before ... */ - unmap_cpu_to_boot_apicid(cpu, apicid); + unmap_cpu_to_boot_apicid(cpu); clear_bit(cpu, &cpu_callout_map); /* was set here (do_boot_cpu()) */ clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */ clear_bit(cpu, &cpu_online_map); /* was set in smp_callin() */ @@ -917,7 +881,7 @@ /* mark "stuck" area as not stuck */ *((volatile unsigned long *)phys_to_virt(8192)) = 0; - if(clustered_apic_mode) { + if (clustered_apic_logical) { printk("Restoring NMI vector\n"); *((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high; *((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low; @@ -925,6 +889,7 @@ } cycles_t cacheflush_time; +unsigned long cache_decay_ticks; static void smp_tune_scheduling (void) { @@ -958,9 +923,13 @@ cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth; } + cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000; + printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", (long)cacheflush_time/(cpu_khz/1000), ((long)cacheflush_time*100/(cpu_khz/1000)) % 100); + printk("task migration cache decay timeout: %ld msecs.\n", + (cache_decay_ticks + 1) * 1000 / HZ); } /* @@ -971,17 +940,19 @@ extern int prof_old_multiplier[NR_CPUS]; extern int prof_counter[NR_CPUS]; -static int boot_cpu_logical_apicid; +#ifdef CONFIG_MULTIQUAD /* Where the IO area was mapped on multiquad, always 0 otherwise */ void *xquad_portio; +#endif int cpu_sibling_map[NR_CPUS] __cacheline_aligned; void __init smp_boot_cpus(void) { - int apicid, cpu, bit; + int phys_apicid, log_apicid, cpu, bit; - if (clustered_apic_mode && (numnodes > 1)) { +#ifdef CONFIG_MULTIQUAD + if (clustered_apic_logical && (numnodes > 1)) { printk("Remapping cross-quad port I/O for %d quads\n", numnodes); printk("xquad_portio vaddr 0x%08lx, len %08lx\n", @@ -990,6 +961,7 @@ xquad_portio = ioremap (XQUAD_PORTIO_BASE, numnodes * XQUAD_PORTIO_LEN); } +#endif #ifdef CONFIG_MTRR /* Must be done before other processors booted */ @@ -1006,8 +978,6 @@ prof_multiplier[cpu] = 1; } - init_cpu_to_apicid(); - /* * Setup boot CPU information */ @@ -1019,12 +989,16 @@ * We have the boot CPU online for sure. */ set_bit(0, &cpu_online_map); - boot_cpu_logical_apicid = logical_smp_processor_id(); - map_cpu_to_boot_apicid(0, boot_cpu_apicid); + if (clustered_apic_physical) + boot_cpu_logical_apicid = physical_to_logical_apicid(boot_cpu_physical_apicid); + else if (clustered_apic_logical) + boot_cpu_logical_apicid = logical_smp_processor_id(); + else + boot_cpu_logical_apicid = 0x01; + map_cpu_to_boot_apicid(0, boot_cpu_physical_apicid, boot_cpu_logical_apicid); global_irq_holder = 0; - current->processor = 0; - init_idle(); + current->cpu = 0; smp_tune_scheduling(); /* @@ -1103,28 +1077,36 @@ */ Dprintk("CPU present map: %lx\n", phys_cpu_present_map); + cpu = 1; for (bit = 0; bit < NR_CPUS; bit++) { - apicid = cpu_present_to_apicid(bit); + if (!(phys_cpu_present_map & (1UL << bit))) + continue; + if ((max_cpus >= 0) && (max_cpus <= cpucount+1)) + continue; + phys_apicid = raw_phys_apicid[bit]; /* * Don't even attempt to start the boot CPU! */ - if (apicid == boot_cpu_apicid) - continue; - - if (!(phys_cpu_present_map & (1 << bit))) - continue; - if ((max_cpus >= 0) && (max_cpus <= cpucount+1)) + if (phys_apicid == boot_cpu_physical_apicid) continue; + if (clustered_apic_physical) + log_apicid = physical_to_logical_apicid(phys_apicid); + else if (clustered_apic_logical) + log_apicid = ((bit >> 2) << 4) | (1 << (bit & 0x3)); + else + log_apicid = 1u << cpu; - do_boot_cpu(apicid); + do_boot_cpu(phys_apicid, log_apicid); /* * Make sure we unmap all failed CPUs */ - if ((boot_apicid_to_cpu(apicid) == -1) && - (phys_cpu_present_map & (1 << bit))) + if ((cpu_to_physical_apicid(bit) == BAD_APICID) && + (phys_cpu_present_map & (1ul << bit))) printk("CPU #%d not responding - cannot use it.\n", - apicid); + bit); + else + ++cpu; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/smp.c linux.20pre2-ac1/arch/i386/kernel/smp.c --- linux.20pre2/arch/i386/kernel/smp.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/smp.c 2002-08-13 14:05:23.000000000 +0100 @@ -115,7 +115,7 @@ static inline int __prepare_ICR (unsigned int shortcut, int vector) { - return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL; + return APIC_DM_FIXED | shortcut | vector | INT_DEST_ADDR_MODE; } static inline int __prepare_ICR2 (unsigned int mask) @@ -214,7 +214,9 @@ /* * prepare target chip field */ - cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu)); + cfg = __prepare_ICR2(clustered_apic_physical ? + cpu_to_physical_apicid(query_cpu) : + cpu_to_logical_apicid(query_cpu)); apic_write_around(APIC_ICR2, cfg); /* @@ -493,13 +495,23 @@ * it goes straight through and wastes no time serializing * anything. Worst case is that we lose a reschedule ... */ - void smp_send_reschedule(int cpu) { send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR); } /* + * this function sends a reschedule IPI to all (other) CPUs. + * This should only be used if some 'global' task became runnable, + * such as a RT task, that must be handled now. The first CPU + * that manages to grab the task will run it. + */ +void smp_send_reschedule_all(void) +{ + send_IPI_allbutself(RESCHEDULE_VECTOR); +} + +/* * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/speedstep.c linux.20pre2-ac1/arch/i386/kernel/speedstep.c --- linux.20pre2/arch/i386/kernel/speedstep.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/speedstep.c 2002-08-06 15:42:19.000000000 +0100 @@ -0,0 +1,693 @@ +/* + * $Id: speedstep.c,v 1.34 2002/07/07 12:29:13 db Exp $ + * + * (C) 2001 Dave Jones, Arjan van de ven. + * (C) 2002 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon reverse engineered information, and on Intel documentation + * for chipsets ICH2-M and ICH3-M. + * + * Many thanks to Ducrot Bruno for finding and fixing the last + * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler + * for extensive testing. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + * + * Version $Id: speedstep.c,v 1.34 2002/07/07 12:29:13 db Exp $ + */ + + +/********************************************************************* + * SPEEDSTEP - DEFINITIONS * + *********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* speedstep_chipset: + * It is necessary to know which chipset is used. As accesses to + * this device occur at various places in this module, we need a + * static struct pci_dev * pointing to that device. + */ +static unsigned int speedstep_chipset; +static struct pci_dev *speedstep_chipset_dev; + +#define SPEEDSTEP_CHIPSET_ICH2M 0x00000002 +#define SPEEDSTEP_CHIPSET_ICH3M 0x00000003 +//#define SPEEDSTEP_CHIPSET_PIIX4 0x00000004 + + +/* speedstep_processor + */ +static unsigned int speedstep_processor; + +#define SPEEDSTEP_PROCESSOR_PIII_C 0x00000001 /* Coppermine core */ +#define SPEEDSTEP_PROCESSOR_PIII_T 0x00000002 /* Tulatin core */ +#define SPEEDSTEP_PROCESSOR_P4M 0x00000003 /* P4-M with 100 MHz FSB */ + + +/* speedstep_[low,high]_freq + * There are only two frequency states for each processor. Values + * are in kHz for the time being. + */ +static unsigned int speedstep_low_freq; +static unsigned int speedstep_high_freq; + + +/* DEBUG + * Undefine it if you do not want verbose debug output + */ +#define SPEEDSTEP_DEBUG + +#ifdef SPEEDSTEP_DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0); +#endif + + + +/********************************************************************* + * LOW LEVEL CHIPSET INTERFACE * + *********************************************************************/ + +/** + * speedstep_get_frequency - read the current SpeedStep state + * @freq: current processor frequency in kHz + * + * Tries to read the SpeedStep state. Returns -EIO when there has been + * trouble to read the status or write to the control register, -EINVAL + * on an unsupported chipset, and zero on success. + */ +static int speedstep_get_frequency (unsigned int *freq) +{ + u32 pmbase; + u8 value; + + if (!speedstep_chipset_dev || !freq) + return -EINVAL; + + switch (speedstep_chipset) { + case SPEEDSTEP_CHIPSET_ICH2M: + case SPEEDSTEP_CHIPSET_ICH3M: + /* get PMBASE */ + pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); + if (!(pmbase & 0x01)) + return -EIO; + + pmbase &= 0xFFFFFFFE; + if (!pmbase) + return -EIO; + + /* read state */ + local_irq_disable(); + value = inb(pmbase + 0x50); + local_irq_enable(); + + dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + *freq = (value & 0x01) ? speedstep_low_freq : \ + speedstep_high_freq; + return 0; + + } + + printk (KERN_ERR "cpufreq: setting CPU frequency on this chipset unsupported.\n"); + return -EINVAL; +} + + +/** + * speedstep_set_frequency - set the SpeedStep state + * @freq: new processor frequency in kHz + * + * Tries to change the SpeedStep state. + */ +void speedstep_set_frequency (unsigned int freq) +{ + u32 pmbase; + u8 pm2_blk; + u8 value; + unsigned long flags; + + if (!speedstep_chipset_dev || !freq) { + printk(KERN_ERR "cpufreq: unknown chipset or state\n"); + return; + } + + switch (speedstep_chipset) { + case SPEEDSTEP_CHIPSET_ICH2M: + case SPEEDSTEP_CHIPSET_ICH3M: + /* get PMBASE */ + pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); + if (!(pmbase & 0x01)) + return; + + pmbase &= 0xFFFFFFFE; + if (!pmbase) + return; + + /* read state */ + local_irq_disable(); + value = inb(pmbase + 0x50); + local_irq_enable(); + + dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + /* write new state, but only if indeed a transition + * is necessary */ + if (freq == ((value & 0x01) ? speedstep_low_freq : \ + speedstep_high_freq)) + return; + + value = (freq == speedstep_high_freq) ? 0x00 : 0x01; + + dprintk(KERN_DEBUG "cpufreq: writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); + + /* Disable IRQs */ + local_irq_save(flags); + local_irq_disable(); + + /* Disable bus master arbitration */ + pm2_blk = inb(pmbase + 0x20); + pm2_blk |= 0x01; + outb(pm2_blk, (pmbase + 0x20)); + + /* Actual transition */ + outb(value, (pmbase + 0x50)); + + /* Restore bus master arbitration */ + pm2_blk &= 0xfe; + outb(pm2_blk, (pmbase + 0x20)); + + /* Enable IRQs */ + local_irq_enable(); + local_irq_restore(flags); + + /* check if transition was sucessful */ + local_irq_disable(); + value = inb(pmbase + 0x50); + local_irq_enable(); + + dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + if (freq == ((value & 0x01) ? speedstep_low_freq : \ + speedstep_high_freq)) { + dprintk (KERN_INFO "cpufreq: change to %u MHz succeded\n", (freq / 1000)); + return; + } + + printk (KERN_ERR "cpufreq: change failed - I/O error\n"); + return; + } + + printk (KERN_ERR "cpufreq: setting CPU frequency on this chipset unsupported.\n"); + return; +} + + +/** + * speedstep_activate - activate SpeedStep control in the chipset + * + * Tries to activate the SpeedStep status and control registers. + * Returns -EINVAL on an unsupported chipset, and zero on success. + */ +static int speedstep_activate (void) +{ + if (!speedstep_chipset_dev) + return -EINVAL; + + switch (speedstep_chipset) { + case SPEEDSTEP_CHIPSET_ICH2M: + case SPEEDSTEP_CHIPSET_ICH3M: + { + u16 value = 0; + + pci_read_config_word(speedstep_chipset_dev, + 0x00A0, &value); + if (!(value & 0x08)) { + value |= 0x08; + dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n"); + pci_write_config_word(speedstep_chipset_dev, + 0x00A0, value); + } + + return 0; + } +/* case SPEEDSTEP_CHIPSET_PIIX4: + { + printk (KERN_ERR "cpufreq: SpeedStep (TM) on PIIX4 not yet supported.\n"); + return -EINVAL; + }*/ + } + + printk (KERN_ERR "cpufreq: SpeedStep (TM) on this chipset unsupported.\n"); + return -EINVAL; +} + + +/** + * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic + * + * Detects PIIX4, ICH2-M and ICH3-M so far. The pci_dev points to + * the LPC bridge / PM module which contains all power-management + * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected + * chipset, or zero on failure. + */ +static unsigned int speedstep_detect_chipset (void) +{ + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801CA_12, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return SPEEDSTEP_CHIPSET_ICH3M; + + + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801BA_10, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return SPEEDSTEP_CHIPSET_ICH2M; + + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); +// if (speedstep_chipset_dev) +// return SPEEDSTEP_CHIPSET_PIIX4; + + return 0; +} + + + +/********************************************************************* + * LOW LEVEL PROCESSOR INTERFACE * + *********************************************************************/ + + +/** + * pentium6_get_fsb - read the FSB on Intel PIII + * + * Returns the Front Side Bus speed of a Pentium III processor (in MHz). + */ +static inline unsigned int pentium6_get_fsb (void) +{ + /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */ + struct { + unsigned int value; /* Front Side Bus speed in MHz */ + u8 bitmap; /* power on configuration bits [18: 19] + (in MSR 0x2a) */ + } msr_decode_fsb [] = { + { 66, 0x0 }, + { 100, 0x2 }, + { 133, 0x1 }, + { 0, 0xff} + }; + u32 msr_lo, msr_hi; + int i = 0; + + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); + + msr_lo &= 0x00c0000; + msr_lo >>= 18; + + while (msr_lo != msr_decode_fsb[i].bitmap) { + if (msr_decode_fsb[i].bitmap == 0xff) + return -EINVAL; + i++; + } + + return msr_decode_fsb[i].value; +} + + +/** + * pentium6_get_ratio - read the frequency multiplier on Intel PIII + * + * Detects the current processor frequency multiplier ratio. + * Returns 10 times the value to properly manage .5 settings. + */ +static inline unsigned int pentium6_get_ratio(void) +{ + /* Intel processor frequency multipliers: + * See table 14 of p3_ds.pdf and table 22 of 29834003.pdf + */ + struct { + unsigned int ratio; /* Frequency Multiplier (x10) */ + u8 bitmap; /* power on configuration bits + [27, 25:22] (in MSR 0x2a) */ + } msr_decode_mult [] = { + { 30, 0x01 }, + { 35, 0x05 }, + { 40, 0x02 }, + { 45, 0x06 }, + { 50, 0x00 }, + { 55, 0x04 }, + { 60, 0x0b }, + { 65, 0x0f }, + { 70, 0x09 }, + { 75, 0x0d }, + { 80, 0x0a }, + { 85, 0x26 }, + { 90, 0x20 }, + { 100, 0x2b }, + { 0, 0xff } /* error or unknown value */ + }; + u32 msr_lo, msr_hi; + int i = 0; + struct cpuinfo_x86 *c = cpu_data; + + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); + + /* decode value */ + if ((c->x86_model == 0x08) && (c->x86_mask == 0x01)) + /* different on early Coppermine PIII */ + msr_lo &= 0x03c00000; + else + msr_lo &= 0x0bc00000; + + msr_lo >>= 22; + while (msr_lo != msr_decode_mult[i].bitmap) { + if (msr_decode_mult[i].bitmap == 0xff) + return -EINVAL; + i++; + } + + return msr_decode_mult[i].ratio; +} + + +/** + * pentium4_get_frequency - get the core frequency for P4-Ms + * + * Should return the core frequency for P4-Ms. + */ +static inline unsigned int pentium4_get_frequency(void) +{ + u32 msr_lo, msr_hi; + + rdmsr(0x2c, msr_lo, msr_hi); + + dprintk(KERN_DEBUG "cpufreq: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); + + /* Don't trust unseen values yet, except in the MHz field + */ + if (msr_hi || ((msr_lo & 0x00FFFFFF) != 0x300511)) { + printk(KERN_INFO "cpufreq: Due to incomplete documentation, please send a mail to devel@brodo.de\n"); + printk(KERN_INFO "with a dmesg of a boot while on ac-power, and one of a boot on battery-power.\n"); + printk(KERN_INFO "Thanks in advance.\n"); + return 0; + } + + /* It seems that the frequency is equal to the + * value in bits 24:31 (in 100 MHz). + */ + msr_lo >>= 24; + return (msr_lo * 100); +} + + +/** + * speedstep_detect_processor - detect Intel SpeedStep-capable processors. + * + * Returns the SPEEDSTEP_PROCESSOR_-number for the detected chipset, + * or zero on failure. + */ +static unsigned int speedstep_detect_processor (void) +{ + struct cpuinfo_x86 *c = cpu_data; + u32 ebx; + int check = 0; + + if ((c->x86_vendor != X86_VENDOR_INTEL) || ((c->x86 != 6) && (c->x86 != 0xF))) + return 0; + + if (c->x86 == 0xF) { + /* Intel Pentium 4 Mobile P4-M */ + if (c->x86_model != 2) + return 0; + + if (c->x86_mask != 4) + return 0; /* all those seem to support Enhanced + SpeedStep */ + + return SPEEDSTEP_PROCESSOR_P4M; + } + + switch (c->x86_model) { + case 0x0B: /* Intel PIII [Tulatin] */ + /* cpuid_ebx(1) is 0x04 for desktop PIII, + 0x06 for mobile PIII-M */ + ebx = cpuid_ebx(0x00000001); + + ebx &= 0x000000FF; + if (ebx != 0x06) + return 0; + + /* So far all PIII-M processors support SpeedStep. See + * Intel's 24540628.pdf of March 2002 + */ + + return SPEEDSTEP_PROCESSOR_PIII_T; + + case 0x08: /* Intel PIII [Coppermine] */ + /* all mobile PIII Coppermines have FSB 100 MHz */ + if (pentium6_get_fsb() != 100) + return 0; + + /* Unfortunatey, no information exists on how to check + * whether the processor is capable of SpeedStep. On + * processors that don't support it, doing such + * transitions might be harmful. So the user has to + * override this safety abort. + */ + +/* ---> */ check = 1; /* remove this line to enable SpeedStep. */ + /* See the comment above on why this check + * is necessary - Sorry for the inconvenience! + */ + + if (check) { + printk(KERN_INFO "cpufreq: Intel PIII (Coppermine) detected. If you are sure this is a\n"); + printk(KERN_INFO "cpufreq: SpeedStep capable processor, please remove line %u in\n", (__LINE__ - 7)); + printk(KERN_INFO "cpufreq: linux/arch/i386/kernel/cpufreq/speedstep.c.\n"); + return 0; + } + + return SPEEDSTEP_PROCESSOR_PIII_C; + + default: + return 0; + } +} + + + +/********************************************************************* + * HIGH LEVEL FUNCTIONS * + *********************************************************************/ + + +/** + * speedstep_detect_speeds - detects low and high CPU frequencies. + * + * Detects the low and high CPU frequencies in kHz. Returns 0 on + * success or -EINVAL / -EIO on problems. + */ +static int speedstep_detect_speeds (void) +{ + switch (speedstep_processor) { + case SPEEDSTEP_PROCESSOR_PIII_C: + case SPEEDSTEP_PROCESSOR_PIII_T: + { + unsigned int state; + unsigned int fsb; + int i = 0; + int result; + + fsb = pentium6_get_fsb(); + + for (i=0; i<2; i++) { + /* read the current state */ + result = speedstep_get_frequency(&state); + if (result) + return result; + + /* save the correct value, and switch to other */ + if (state == speedstep_low_freq) { + speedstep_low_freq = + pentium6_get_ratio() * fsb * 100; + speedstep_set_frequency(speedstep_high_freq); + } else { + speedstep_high_freq = + pentium6_get_ratio() * fsb * 100; + speedstep_set_frequency(speedstep_low_freq); + } + } + + if (!speedstep_low_freq || !speedstep_high_freq) + return -EIO; + else + return 0; + } + case SPEEDSTEP_PROCESSOR_P4M: + { + unsigned int state; + int i = 0; + int result; + + for (i=0; i<2; i++) { + /* read the current state */ + result = speedstep_get_frequency(&state); + if (result) + return result; + + /* save the correct value, and switch to other */ + if (state == speedstep_low_freq) { + speedstep_low_freq = + pentium4_get_frequency() * 1000; + speedstep_set_frequency(speedstep_high_freq); + } else { + speedstep_high_freq = + pentium4_get_frequency() * 1000; + speedstep_set_frequency(speedstep_low_freq); + } + } + + if (!speedstep_low_freq || !speedstep_high_freq) + return -EIO; + else + return 0; + } + } + return -EINVAL; +} + + +/** + * speedstep_validate_frequency - validates the CPU frequency to be set + * @kHz: suggested new CPU frequency + * + * Makes sure the CPU frequency to be set is valid. + */ +unsigned int speedstep_validate_frequency(unsigned int kHz) +{ + if (((int) (kHz - speedstep_low_freq)) < + ((int) (speedstep_high_freq - kHz))) + return speedstep_low_freq; + else + return speedstep_high_freq; +} + + +/** + * speedstep_init - initializes the SpeedStep CPUFreq driver + * + * Initializes the SpeedStep support. Returns -ENODEV on unsupported + * devices, -EINVAL on problems during initiatization, and zero on + * success. + */ +static int __init speedstep_init(void) +{ + int result; + unsigned int speed; + struct cpufreq_driver driver; + + printk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) support $Revision: 1.34 $\n"); + + /* detect processor */ + speedstep_processor = speedstep_detect_processor(); + + /* detect chipset */ + speedstep_chipset = speedstep_detect_chipset(); + if ((!speedstep_chipset) || (!speedstep_processor)) { + printk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this %s not (yet) available.\n", speedstep_processor ? "chipset" : "processor"); + return -ENODEV; + } + + /* startup values, correct ones will be detected later */ + speedstep_low_freq = 1; + speedstep_high_freq = 2; + + /* define method to be used */ + dprintk(KERN_DEBUG "cpufreq: chipset 0x%x - processor 0x%x\n", + speedstep_chipset, speedstep_processor); + + /* activate speedstep support */ + result = speedstep_activate(); + if (result) { + speedstep_chipset = 0; + return result; + } + + /* detect low and high frequency */ + result = speedstep_detect_speeds(); + if (result) { + speedstep_chipset = 0; + return result; + } + + /* get current speed setting */ + result = speedstep_get_frequency(&speed); + if (result) { + speedstep_chipset = 0; + return result; + } + + dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", + (speed == speedstep_low_freq) ? "low" : "high", + (speed / 1000)); + + /* initialization of main "cpufreq" code*/ + driver.freq.min = speedstep_low_freq; + driver.freq.max = speedstep_high_freq; + driver.freq.cur = speed; + driver.validate = &speedstep_validate_frequency; + driver.setspeed = &speedstep_set_frequency; + + result = cpufreq_register(driver); + if (result) { + speedstep_chipset = 0; + return result; + } + + return 0; +} + + +/** + * speedstep_exit - unregisters SpeedStep support + * + * Unregisters SpeedStep support. + */ +static void __exit speedstep_exit(void) +{ + if (speedstep_chipset) + cpufreq_unregister(); +} + + + +MODULE_AUTHOR ("Dave Jones , Dominik Brodowski "); +MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors."); +MODULE_LICENSE ("GPL"); +module_init(speedstep_init); +module_exit(speedstep_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/time.c linux.20pre2-ac1/arch/i386/kernel/time.c --- linux.20pre2/arch/i386/kernel/time.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/time.c 2002-08-12 15:17:04.000000000 +0100 @@ -31,6 +31,7 @@ */ #include +#include #include #include #include @@ -116,6 +117,8 @@ spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; +EXPORT_SYMBOL(i8253_lock); + extern spinlock_t i8259A_lock; #ifndef CONFIG_X86_TSC @@ -666,51 +669,61 @@ * moaned if you have the only one in the world - you fix it! */ - dodgy_tsc(); - - if (cpu_has_tsc) { - unsigned long tsc_quotient = calibrate_tsc(); - if (tsc_quotient) { - fast_gettimeoffset_quotient = tsc_quotient; - use_tsc = 1; - /* - * We could be more selective here I suspect - * and just enable this for the next intel chips ? - */ - x86_udelay_tsc = 1; + switch (select_tsc()) + { + case TSC_NONE: + setup_irq(0, &irq0); + break; + case TSC_CPU: + { + unsigned long tsc_quotient = calibrate_tsc(); + if (tsc_quotient) { + fast_gettimeoffset_quotient = tsc_quotient; + use_tsc = 1; + /* + * We could be more selective here I suspect + * and just enable this for the next intel chips ? + */ + x86_udelay_tsc = 1; #ifndef do_gettimeoffset - do_gettimeoffset = do_fast_gettimeoffset; + do_gettimeoffset = do_fast_gettimeoffset; #endif - /* report CPU clock rate in Hz. - * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = - * clock/second. Our precision is about 100 ppm. - */ - { unsigned long eax=0, edx=1000; - __asm__("divl %2" - :"=a" (cpu_khz), "=d" (edx) - :"r" (tsc_quotient), - "0" (eax), "1" (edx)); - printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); + /* report CPU clock rate in Hz. + * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = + * clock/second. Our precision is about 100 ppm. + */ + { unsigned long eax=0, edx=1000; + __asm__("divl %2" + :"=a" (cpu_khz), "=d" (edx) + :"r" (tsc_quotient), + "0" (eax), "1" (edx)); + printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); + } } + setup_irq(0, &irq0); + break; } - } - + case TSC_CYCLONE: + /* To be added */ + setup_irq(0, &irq0); + break; #ifdef CONFIG_VISWS - printk("Starting Cobalt Timer system clock\n"); + case TSC_VISWS: + printk("Starting Cobalt Timer system clock\n"); - /* Set the countdown value */ - co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); + /* Set the countdown value */ + co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); - /* Start the timer */ - co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); + /* Start the timer */ + co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); - /* Enable (unmask) the timer interrupt */ - co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); + /* Enable (unmask) the timer interrupt */ + co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); - /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ - setup_irq(CO_IRQ_TIMER, &irq0); -#else - setup_irq(0, &irq0); + /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ + setup_irq(CO_IRQ_TIMER, &irq0); + break; #endif + } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/trampoline.S linux.20pre2-ac1/arch/i386/kernel/trampoline.S --- linux.20pre2/arch/i386/kernel/trampoline.S 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/trampoline.S 2002-08-06 15:42:19.000000000 +0100 @@ -36,9 +36,7 @@ ENTRY(trampoline_data) r_base = . -#ifdef CONFIG_MULTIQUAD - wbinvd -#endif /* CONFIG_MULTIQUAD */ + wbinvd # Needed for NUMA-Q should be harmless for others mov %cs, %ax # Code and data in the same place mov %ax, %ds diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/kernel/traps.c linux.20pre2-ac1/arch/i386/kernel/traps.c --- linux.20pre2/arch/i386/kernel/traps.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/kernel/traps.c 2002-08-13 14:05:33.000000000 +0100 @@ -284,6 +284,20 @@ void die(const char * str, struct pt_regs * regs, long err) { +#ifdef CONFIG_PNPBIOS + if (regs->xcs == 0x60 || regs->xcs == 0x68) + { + extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; + extern u32 pnp_bios_is_utter_crap; + pnp_bios_is_utter_crap = 1; + printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n"); + __asm__ volatile( + "movl %0, %%esp\n\t" + "jmp %1\n\t" + : "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip)); + panic("do_trap: can't hit this"); + } +#endif console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); @@ -313,8 +327,13 @@ static void inline do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs * regs, long error_code, siginfo_t *info) { - if (vm86 && regs->eflags & VM_MASK) - goto vm86_trap; + if (regs->eflags & VM_MASK) { + if (vm86) + goto vm86_trap; + else + goto trap_signal; + } + if (!(regs->xcs & 3)) goto kernel_trap; @@ -522,10 +541,15 @@ { unsigned int condition; struct task_struct *tsk = current; + unsigned long eip = regs->eip; siginfo_t info; __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); + /* If the user set TF, it's simplest to clear it right away. */ + if ((eip >=PAGE_OFFSET) && (regs->eflags & TF_MASK)) + goto clear_TF; + /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/i386/mm/fault.c linux.20pre2-ac1/arch/i386/mm/fault.c --- linux.20pre2/arch/i386/mm/fault.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/i386/mm/fault.c 2002-08-06 15:42:19.000000000 +0100 @@ -76,9 +76,7 @@ return 1; check_stack: - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (expand_stack(vma, start) == 0) + if (!expand_stack(vma, start)) goto good_area; bad_area: @@ -86,8 +84,7 @@ out_of_memory: if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); goto survive; } goto bad_area; @@ -336,8 +333,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ia64/defconfig linux.20pre2-ac1/arch/ia64/defconfig --- linux.20pre2/arch/ia64/defconfig 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/ia64/defconfig 2002-08-06 15:42:21.000000000 +0100 @@ -672,7 +672,6 @@ # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_EFI_PARTITION=y -# CONFIG_DEVFS_GUID is not set # CONFIG_LDM_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ia64/ia32/sys_ia32.c linux.20pre2-ac1/arch/ia64/ia32/sys_ia32.c --- linux.20pre2/arch/ia64/ia32/sys_ia32.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/ia64/ia32/sys_ia32.c 2002-08-06 15:42:21.000000000 +0100 @@ -3693,7 +3693,11 @@ return result; } -struct dqblk32 { +extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr); + +#ifdef CONFIG_QIFACE_COMPAT +#ifdef CONFIG_QIFACE_V1 +struct user_dqblk32 { __u32 dqb_bhardlimit; __u32 dqb_bsoftlimit; __u32 dqb_curblocks; @@ -3703,49 +3707,82 @@ __kernel_time_t32 dqb_btime; __kernel_time_t32 dqb_itime; }; +typedef struct v1c_mem_dqblk comp_dqblk_t; -asmlinkage long -sys32_quotactl (int cmd, unsigned int special, int id, struct dqblk32 *addr) +#define Q_COMP_GETQUOTA Q_V1_GETQUOTA +#define Q_COMP_SETQUOTA Q_V1_SETQUOTA +#define Q_COMP_SETQLIM Q_V1_SETQLIM +#define Q_COMP_SETUSE Q_V1_SETUSE +#else +struct user_dqblk32 { + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u64 dqb_curspace; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v2c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V2_GETQUOTA +#define Q_COMP_SETQUOTA Q_V2_SETQUOTA +#define Q_COMP_SETQLIM Q_V2_SETQLIM +#define Q_COMP_SETUSE Q_V2_SETUSE +#endif + +asmlinkage long sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) { - extern asmlinkage long sys_quotactl (int, const char *, int, caddr_t); int cmds = cmd >> SUBCMDSHIFT; + long err; + comp_dqblk_t d; mm_segment_t old_fs; - struct dqblk d; char *spec; - long err; - + switch (cmds) { - case Q_GETQUOTA: - break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, addr, sizeof(struct dqblk32))) - return -EFAULT; - d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; - break; - default: - return sys_quotactl(cmd, (void *) A(special), id, (caddr_t) addr); + case Q_COMP_GETQUOTA: + break; + case Q_COMP_SETQUOTA: + case Q_COMP_SETUSE: + case Q_COMP_SETQLIM: + if (copy_from_user(&d, (struct user_dqblk32 *)addr, + sizeof (struct user_dqblk32))) + return -EFAULT; + d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime; + break; + default: + return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr); } - spec = getname32((void *) A(special)); + spec = getname (special); err = PTR_ERR(spec); - if (IS_ERR(spec)) + if (IS_ERR(spec)) return err; + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d); + set_fs (old_fs); + putname (spec); + if (err) return err; - old_fs = get_fs (); - set_fs(KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); - set_fs(old_fs); - putname(spec); - if (cmds == Q_GETQUOTA) { + if (cmds == Q_COMP_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct dqblk32 *)&d)->dqb_itime = i; - ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user(addr, &d, sizeof(struct dqblk32))) + ((struct user_dqblk32 *)&d)->dqb_itime = i; + ((struct user_dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct user_dqblk32 *)addr, &d, + sizeof (struct user_dqblk32))) return -EFAULT; } - return err; + return 0; +} + +#else +/* No conversion needed for new interface */ +asmlinkage long sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) +{ + return sys_quotactl(cmd, special, id, addr); } +#endif asmlinkage long sys32_sched_rr_get_interval (pid_t pid, struct timespec32 *interval) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ia64/kernel/efivars.c linux.20pre2-ac1/arch/ia64/kernel/efivars.c --- linux.20pre2/arch/ia64/kernel/efivars.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/ia64/kernel/efivars.c 2002-08-06 15:42:21.000000000 +0100 @@ -29,6 +29,9 @@ * * Changelog: * + * 25 Mar 2002 - Matt Domsch + * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse() + * * 12 Feb 2002 - Matt Domsch * use list_for_each_safe when deleting vars. * remove ifdef CONFIG_SMP around include @@ -70,7 +73,7 @@ MODULE_DESCRIPTION("/proc interface to EFI Variables"); MODULE_LICENSE("GPL"); -#define EFIVARS_VERSION "0.04 2002-Feb-12" +#define EFIVARS_VERSION "0.05 2002-Mar-26" static int efivar_read(char *page, char **start, off_t off, @@ -141,20 +144,6 @@ return len; } - -static void -uuid_unparse(efi_guid_t *guid, char *out) -{ - sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - guid->data1, guid->data2, guid->data3, - guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3], - guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); -} - - - - - /* * efivar_create_proc_entry() * Requires: @@ -197,7 +186,7 @@ private variables from another's. */ *(short_name + strlen(short_name)) = '-'; - uuid_unparse(vendor_guid, short_name + strlen(short_name)); + efi_guid_unparse(vendor_guid, short_name + strlen(short_name)); /* Create the entry in proc */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ia64/kernel/irq.c linux.20pre2-ac1/arch/ia64/kernel/irq.c --- linux.20pre2/arch/ia64/kernel/irq.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/ia64/kernel/irq.c 2002-08-06 15:42:21.000000000 +0100 @@ -172,7 +172,7 @@ p += sprintf(p, "LOC: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); + irq_stat[cpu_logical_map(j)].apic_timer_irqs); p += sprintf(p, "\n"); #endif p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ia64/kernel/mca.c linux.20pre2-ac1/arch/ia64/kernel/mca.c --- linux.20pre2/arch/ia64/kernel/mca.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/ia64/kernel/mca.c 2002-08-06 15:42:21.000000000 +0100 @@ -3,6 +3,9 @@ * Purpose: Generic MCA handling layer * * Updated for latest kernel + * Copyright (C) 2002 Dell Computer Corporation + * Copyright (C) Matt Domsch (Matt_Domsch@dell.com) + * * Copyright (C) 2002 Intel * Copyright (C) Jenna Hall (jenna.s.hall@intel.com) * @@ -15,6 +18,8 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * + * 02/03/25 M. Domsch GUID cleanups + * * 02/01/04 J. Hall Aligned MCA stack to 16 bytes, added platform vs. CPU * error flag, set SAL default return values, changed * error record structure to linked list, added init call @@ -348,17 +353,13 @@ verify_guid (efi_guid_t *test, efi_guid_t *target) { int rc; + char out[40]; - if ((rc = memcmp((void *)test, (void *)target, sizeof(efi_guid_t)))) { - IA64_MCA_DEBUG("ia64_mca_print: invalid guid = " - "{ %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " - "%#02x, %#02x, %#02x, %#02x, } } \n ", - test->data1, test->data2, test->data3, test->data4[0], - test->data4[1], test->data4[2], test->data4[3], - test->data4[4], test->data4[5], test->data4[6], - test->data4[7]); + if ((rc = efi_guidcmp(*test, *target))) { + IA64_MCA_DEBUG(KERN_DEBUG + "verify_guid: invalid GUID = %s\n", + efi_guid_unparse(test, out)); } - return rc; } @@ -856,11 +857,8 @@ void ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc) { - printk("GUID = { %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " - "%#02x, %#02x, %#02x, %#02x, } } \n ", p_guid->data1, - p_guid->data2, p_guid->data3, p_guid->data4[0], p_guid->data4[1], - p_guid->data4[2], p_guid->data4[3], p_guid->data4[4], - p_guid->data4[5], p_guid->data4[6], p_guid->data4[7]); + char out[40]; + printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out)); } static void @@ -1754,7 +1752,7 @@ ia64_log_prt_section_header(slsh, prfunc); #endif // MCA_PRT_XTRA_DATA for test only @FVL - if (verify_guid((void *)&slsh->guid, (void *)&(SAL_PROC_DEV_ERR_SECT_GUID))) { + if (verify_guid(&slsh->guid, &(SAL_PROC_DEV_ERR_SECT_GUID))) { IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); continue; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ia64/kernel/perfmon.c linux.20pre2-ac1/arch/ia64/kernel/perfmon.c --- linux.20pre2/arch/ia64/kernel/perfmon.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/ia64/kernel/perfmon.c 2002-08-06 15:42:21.000000000 +0100 @@ -387,34 +387,8 @@ return ia64_get_itc(); } -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long -uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - DBprintk(("[%d] uv2kva(%lx-->%lx)\n", current->pid, adr, ret)); - return ret; -} - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long pfm_kvirt_to_pa(unsigned long adr) @@ -424,21 +398,19 @@ return pa; } - static void * pfm_rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; + unsigned long adr; + size=PAGE_ALIGN(size); mem=vmalloc(size); if (mem) { - //printk("perfmon: CPU%d pfm_rvmalloc(%ld)=%p\n", smp_processor_id(), size, mem); memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr=(unsigned long) mem; while (size > 0) { - page = pfm_kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -449,13 +421,12 @@ static void pfm_rvfree(void *mem, unsigned long size) { - unsigned long adr, page = 0; + unsigned long adr; if (mem) { adr=(unsigned long) mem; - while (size > 0) { - page = pfm_kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ia64/mm/fault.c linux.20pre2-ac1/arch/ia64/mm/fault.c --- linux.20pre2/arch/ia64/mm/fault.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/ia64/mm/fault.c 2002-08-06 15:42:21.000000000 +0100 @@ -119,8 +119,6 @@ check_expansion: if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) { - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (rgn_index(address) != rgn_index(vma->vm_start) || rgn_offset(address) >= RGN_MAP_LIMIT) goto bad_area; @@ -196,8 +194,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/m68k/mm/fault.c linux.20pre2-ac1/arch/m68k/mm/fault.c --- linux.20pre2/arch/m68k/mm/fault.c 2002-08-13 13:58:36.000000000 +0100 +++ linux.20pre2-ac1/arch/m68k/mm/fault.c 2002-08-06 15:42:21.000000000 +0100 @@ -181,8 +181,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/mips/config.in linux.20pre2-ac1/arch/mips/config.in --- linux.20pre2/arch/mips/config.in 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/mips/config.in 2002-08-06 15:42:19.000000000 +0100 @@ -631,6 +631,7 @@ if [ "$CONFIG_SMP" != "y" ]; then bool 'Run uncached' CONFIG_MIPS_UNCACHED fi +dep_bool 'Morse code panics' CONFIG_PANIC_MORSE $CONFIG_DEBUG $CONFIG_PC_KEYB endmenu source lib/Config.in diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/mips/mm/fault.c linux.20pre2-ac1/arch/mips/mm/fault.c --- linux.20pre2/arch/mips/mm/fault.c 2002-08-13 13:58:34.000000000 +0100 +++ linux.20pre2-ac1/arch/mips/mm/fault.c 2002-08-06 15:42:19.000000000 +0100 @@ -111,8 +111,6 @@ goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, address)) goto bad_area; /* @@ -213,8 +211,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/mips64/mm/fault.c linux.20pre2-ac1/arch/mips64/mm/fault.c --- linux.20pre2/arch/mips64/mm/fault.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/mips64/mm/fault.c 2002-08-06 15:42:22.000000000 +0100 @@ -135,8 +135,6 @@ goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, address)) goto bad_area; /* @@ -238,8 +236,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/parisc/config.in linux.20pre2-ac1/arch/parisc/config.in --- linux.20pre2/arch/parisc/config.in 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/parisc/config.in 2002-08-13 15:14:13.000000000 +0100 @@ -16,98 +16,106 @@ endmenu mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ] ; then + bool 'Set version information on all module symbols' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment +comment 'Processor type' +choice 'Processor family' \ + "PA7000/PA7100 CONFIG_PA7100 \ + PA7200 CONFIG_PA7200 \ + PA7100LC/PA7300LC CONFIG_PA7100LC \ + PA8x00 CONFIG_PA8X00" PA7000 + +if [ "$CONFIG_PA8X00" = "y" ] ; then + define_bool CONFIG_PA20 y + bool '64-bit kernel' CONFIG_PARISC64 + dep_bool '32-bit PDC' CONFIG_PDC_NARROW $CONFIG_PARISC64 +else + define_bool CONFIG_PA11 y +fi +endmenu + +mainmenu_option next_comment comment 'General options' -# bool 'Symmetric multi-processing support' CONFIG_SMP -define_bool CONFIG_SMP n +bool 'Symmetric multi-processing support' CONFIG_SMP +bool 'Chassis LCD and LED support' CONFIG_CHASSIS_LCD_LED bool 'Kernel Debugger support' CONFIG_KWDB # define_bool CONFIG_KWDB n -# bool 'GSC/Gecko bus support' CONFIG_GSC y -define_bool CONFIG_GSC y - -bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO y -bool 'LASI I/O support' CONFIG_GSC_LASI y - -bool 'PCI bus support' CONFIG_PCI y +bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO +bool 'VSC/GSC/HSC bus support' CONFIG_GSC +dep_bool ' Lasi I/O support' CONFIG_GSC_LASI $CONFIG_GSC +dep_bool ' Wax I/O support' CONFIG_GSC_WAX $CONFIG_GSC + +dep_bool 'EISA support' CONFIG_EISA $CONFIG_GSC +define_bool CONFIG_ISA $CONFIG_EISA +bool 'PCI support' CONFIG_PCI if [ "$CONFIG_PCI" = "y" ]; then - bool 'GSCtoPCI/DINO PCI support' CONFIG_GSC_DINO y - bool 'LBA/Elroy PCI support' CONFIG_PCI_LBA n -fi + dep_bool ' GSCtoPCI/Dino PCI support' CONFIG_GSC_DINO $CONFIG_GSC + bool ' LBA/Elroy PCI support' CONFIG_PCI_LBA + define_bool CONFIG_IOSAPIC $CONFIG_PCI_LBA + define_bool CONFIG_IOMMU_SBA $CONFIG_PCI_LBA -if [ "$CONFIG_PCI_LBA" = "y" ]; then - define_bool CONFIG_IOSAPIC y - define_bool CONFIG_IOMMU_SBA y -fi +# bool ' EPIC PCI support' CONFIG_PCI_EPIC n + bool ' SuperIO support' CONFIG_SUPERIO +fi -# -# if [ "$CONFIG_PCI_EPIC" = "y" ]; then... -# +source drivers/pci/Config.in endmenu mainmenu_option next_comment -comment 'Loadable module support' -bool 'Enable loadable module support' CONFIG_MODULES -if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all module symbols' CONFIG_MODVERSIONS - bool 'Kernel module loader' CONFIG_KMOD -fi -endmenu - -mainmenu_option next_comment comment 'General setup' +bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM +define_bool CONFIG_KCORE_ELF y tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA -fi + +# anyone want to get ACPI working on PA/RISC? +define_bool CONFIG_PM n endmenu -##source drivers/parport/Config.in -mainmenu_option next_comment -comment 'Parallel port support' +source drivers/parport/Config.in -tristate 'Parallel port support' CONFIG_PARPORT -if [ "$CONFIG_PARPORT" != "n" ]; then - if [ "$CONFIG_PCI" = "y" ]; then - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT - if [ "$CONFIG_PARPORT_PC" != "n" ]; then - bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO - fi - fi - fi - if [ "$CONFIG_GSC_LASI" = "y" ]; then - dep_tristate ' LASI/ASP builtin parallel-port' CONFIG_PARPORT_GSC $CONFIG_PARPORT - else - define_tristate CONFIG_PARPORT_GSC n - fi +source drivers/block/Config.in - # If exactly one hardware type is selected then parport will optimise away - # support for loading any others. Defeat this if the user is keen. - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER +source drivers/md/Config.in - bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284 +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in fi -endmenu +if [ "$CONFIG_SUPERIO" = "y" ]; then + mainmenu_option next_comment + comment 'ATA/IDE/MFM/RLL support' -source drivers/block/Config.in + tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE -if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in + if [ "$CONFIG_IDE" != "n" ]; then + source drivers/ide/Config.in + else + define_bool CONFIG_BLK_DEV_IDE_MODES n + define_bool CONFIG_BLK_DEV_HD n + fi + endmenu fi mainmenu_option next_comment @@ -116,90 +124,70 @@ tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then - comment 'SCSI support type (disk, tape, CDrom)' - - dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then - int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 - fi - - dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI - if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR - int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 - fi - dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI - - comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' - bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN - bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS - - mainmenu_option next_comment - comment 'SCSI low-level drivers' - if [ "$CONFIG_GSC_LASI" = "y" ]; then - dep_tristate 'Lasi SCSI support' CONFIG_SCSI_LASI $CONFIG_SCSI - dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_SCSI - fi - if [ "$CONFIG_PCI" = "y" ]; then - dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI - fi - if [ "$CONFIG_SCSI_ZALON" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then - int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 - int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 - int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 - bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE - bool ' use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED - fi - endmenu + source drivers/scsi/Config.in fi endmenu if [ "$CONFIG_NET" = "y" ]; then - mainmenu_option next_comment - comment 'Network device support' + mainmenu_option next_comment + comment 'Network device support' - bool 'Network device support' CONFIG_NETDEVICES + bool 'Network device support' CONFIG_NETDEVICES - if [ "$CONFIG_NETDEVICES" = "y" ]; then - if [ "$CONFIG_GSC_LASI" = "y" ]; then - tristate 'Lasi ethernet' CONFIG_LASI_82596 - fi - source drivers/net/Config.in - fi - endmenu + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi + fi + endmenu fi +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in source drivers/char/Config.in +source drivers/hil/Config.in + +source drivers/media/Config.in source fs/Config.in +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + source drivers/video/Config.in + + bool 'STI console' CONFIG_STI_CONSOLE + if [ "$CONFIG_GSC_PS2" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + if [ "$CONFIG_STI_CONSOLE" = "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + define_bool CONFIG_FBCON y + define_bool CONFIG_FBCON_FONT y +# define_bool CONFIG_FBCON_FONTWIDTH8_ONLY n + define_bool CONFIG_FONT_8x8 y + define_bool CONFIG_FONT_8x16 y + define_bool CONFIG_FONT_6x11 y + define_bool CONFIG_FONT_SUN12x22 y + fi + endmenu +fi + mainmenu_option next_comment -comment 'Sound Drivers' +comment 'Sound' + tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then source drivers/sound/Config.in fi endmenu -if [ "$CONFIG_VT" = "y" ]; then - mainmenu_option next_comment - comment 'Console drivers' - source drivers/video/Config.in - -# bool 'IODC console' CONFIG_IODC_CONSOLE - bool 'STI console' CONFIG_STI_CONSOLE - if [ "$CONFIG_IODC_CONSOLE" = "n" ]; then - if [ "$CONFIG_GSC_PS2" = "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y - fi - fi - if [ "$CONFIG_STI_CONSOLE" = "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y - fi - endmenu +if [ "$CONFIG_SUPERIO" = "y" ]; then + source drivers/usb/Config.in fi -# endmenu mainmenu_option next_comment comment 'Kernel hacking' diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/parisc/kernel/lasimap.map linux.20pre2-ac1/arch/parisc/kernel/lasimap.map --- linux.20pre2/arch/parisc/kernel/lasimap.map 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/arch/parisc/kernel/lasimap.map 1970-01-01 01:00:00.000000000 +0100 @@ -1,322 +0,0 @@ -# HP 712 kernel keymap. This uses 7 modifier combinations. - -keymaps 0-2,4-5,8,12 -# ie, plain, Shift, AltGr, Control, Control+Shift, Alt and Control+Alt - - -# Change the above line into -# keymaps 0-2,4-6,8,12 -# in case you want the entries -# altgr control keycode 83 = Boot -# altgr control keycode 111 = Boot -# below. -# -# In fact AltGr is used very little, and one more keymap can -# be saved by mapping AltGr to Alt (and adapting a few entries): -# keycode 100 = Alt -# -keycode 1 = F9 F19 Console_21 - control keycode 1 = F9 - alt keycode 1 = Console_9 - control alt keycode 1 = Console_9 -keycode 2 = -keycode 3 = F5 F15 Console_17 - control keycode 3 = F5 - alt keycode 3 = Console_5 - control alt keycode 3 = Console_5 -keycode 4 = F3 F13 Console_15 - control keycode 4 = F3 - alt keycode 4 = Console_3 - control alt keycode 4 = Console_3 -keycode 5 = F1 F11 Console_13 - control keycode 5 = F1 - alt keycode 5 = Console_1 - control alt keycode 5 = Console_1 -keycode 6 = F2 F12 Console_14 - control keycode 6 = F2 - alt keycode 6 = Console_2 - control alt keycode 6 = Console_2 -keycode 7 = F12 F12 Console_24 - control keycode 7 = F12 - alt keycode 7 = Console_12 - control alt keycode 7 = Console_12 -keycode 8 = -keycode 9 = F10 F20 Console_22 - control keycode 9 = F10 - alt keycode 9 = Console_10 - control alt keycode 9 = Console_10 -keycode 10 = F8 F18 Console_20 - control keycode 10 = F8 - alt keycode 10 = Console_8 - control alt keycode 10 = Console_8 -keycode 11 = F6 F16 Console_18 - control keycode 11 = F6 - alt keycode 11 = Console_6 - control alt keycode 11 = Console_6 -keycode 12 = F4 F14 Console_16 - control keycode 12 = F4 - alt keycode 12 = Console_4 - control alt keycode 12 = Console_4 -keycode 13 = Tab Tab - alt keycode 13 = Meta_Tab -keycode 14 = grave asciitilde - control keycode 14 = nul - alt keycode 14 = Meta_grave -keycode 15 = -keycode 16 = -keycode 17 = Alt -keycode 18 = Shift -keycode 19 = -keycode 20 = Control -keycode 21 = q -keycode 22 = one exclam exclam -keycode 23 = -keycode 24 = -keycode 25 = -keycode 26 = z -keycode 27 = s -keycode 28 = a - altgr keycode 28 = Hex_A -keycode 29 = w -keycode 30 = two at at -keycode 31 = -keycode 32 = -keycode 33 = c - altgr keycode 46 = Hex_C -keycode 34 = x -keycode 35 = d - altgr keycode 35 = Hex_D -keycode 36 = e - altgr keycode 36 = Hex_E -keycode 37 = four dollar -keycode 38 = three numbersign -keycode 39 = -keycode 40 = -keycode 41 = -keycode 42 = v -keycode 43 = f - altgr keycode 43 = Hex_F -keycode 44 = t -keycode 45 = r -keycode 46 = five percent -keycode 47 = -keycode 48 = -keycode 49 = n -keycode 50 = b - altgr keycode 50 = Hex_B -keycode 51 = h -keycode 52 = g -keycode 53 = y -keycode 54 = six asciicircum -keycode 55 = -keycode 56 = -keycode 57 = -keycode 58 = m -keycode 59 = j -keycode 60 = u -keycode 61 = seven ampersand -keycode 62 = eight asterisk asterisk -keycode 63 = -keycode 64 = -keycode 65 = comma less - alt keycode 65 = Meta_comma -keycode 66 = k -keycode 67 = i -keycode 68 = o -keycode 69 = zero parenright bracketright -keycode 70 = nine parenleft bracketleft -keycode 71 = -keycode 72 = -keycode 73 = period greater - control keycode 73 = Compose - alt keycode 73 = Meta_period -keycode 74 = slash question - control keycode 74 = Delete - alt keycode 53 = Meta_slash -keycode 75 = l -keycode 76 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 77 = p -keycode 78 = minus underscore -keycode 79 = -keycode 80 = -keycode 81 = -keycode 82 = apostrophe quotedbl - control keycode 82 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 83 = -keycode 84 = bracketleft braceleft - control keycode 84 = Escape - alt keycode 26 = Meta_bracketleft -keycode 85 = equal plus -keycode 86 = -keycode 87 = -keycode 88 = Caps_Lock -keycode 88 = -keycode 89 = -keycode 89 = -keycode 89 = -keycode 90 = Return - alt keycode 90 = Meta_Control_m -keycode 91 = bracketright braceright asciitilde - control keycode 91 = Control_bracketright - alt keycode 91 = Meta_bracketright -keycode 92 = -keycode 93 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash -keycode 94 = -keycode 95 = -keycode 96 = -keycode 97 = -keycode 98 = -keycode 99 = -keycode 100 = -keycode 101 = -keycode 102 = BackSpace -keycode 103 = -keycode 104 = -keycode 105 = KP_1 - alt keycode 105 = Ascii_1 - altgr keycode 105 = Hex_1 -keycode 106 = -keycode 107 = KP_4 - alt keycode 107 = Ascii_4 - altgr keycode 107 = Hex_4 -keycode 108 = KP_7 - alt keycode 108 = Ascii_7 - altgr keycode 108 = Hex_7 -keycode 109 = -keycode 110 = -keycode 111 = -keycode 112 = KP_0 - alt keycode 82 = Ascii_0 - altgr keycode 82 = Hex_0 -keycode 113 = KP_Period -keycode 114 = KP_2 - alt keycode 114 = Ascii_2 - altgr keycode 114 = Hex_2 -keycode 115 = KP_5 - alt keycode 115 = Ascii_5 - altgr keycode 115 = Hex_5 -keycode 116 = KP_6 - alt keycode 116 = Ascii_6 - altgr keycode 116 = Hex_6 -keycode 117 = KP_8 - alt keycode 117 = Ascii_8 - altgr keycode 117 = Hex_8 -keycode 118 = Escape -keycode 119 = -keycode 120 = F11 -keycode 121 = KP_Add -keycode 122 = KP_3 - alt keycode 122 = Ascii_3 - altgr keycode 122 = Hex_3 -keycode 123 = KP_Subtract -keycode 124 = KP_Multiply -keycode 125 = KP_9 - alt keycode 125 = Ascii_9 - altgr keycode 125 = Hex_9 -keycode 126 = -# 131!! -keycode 127 = F7 F17 Console_19 - control keycode 127 = F7 - alt keycode 127 = Console_7 - control alt keycode 127 = Console_7 - -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ppc/kernel/pci.c linux.20pre2-ac1/arch/ppc/kernel/pci.c --- linux.20pre2/arch/ppc/kernel/pci.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/ppc/kernel/pci.c 2002-08-13 14:08:25.000000000 +0100 @@ -925,7 +925,7 @@ /* XXX FIXME - update OF device tree node interrupt property */ } -int pcibios_enable_device(struct pci_dev *dev) +int pcibios_enable_device(struct pci_dev *dev, int mask) { u16 cmd, old_cmd; int idx; @@ -938,6 +938,9 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; for (idx=0; idx<6; idx++) { + if(!(mask & (1<resource[idx]; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ppc/kernel/setup.c linux.20pre2-ac1/arch/ppc/kernel/setup.c --- linux.20pre2/arch/ppc/kernel/setup.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/ppc/kernel/setup.c 2002-08-13 14:08:40.000000000 +0100 @@ -682,14 +682,16 @@ id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2); id->csf_default = __le16_to_cpu(id->csf_default); id->dma_ultra = __le16_to_cpu(id->dma_ultra); - id->word89 = __le16_to_cpu(id->word89); - id->word90 = __le16_to_cpu(id->word90); + id->trseuc = __le16_to_cpu(id->trseuc); + id->trsEuc = __le16_to_cpu(id->trsEuc); id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); - id->word92 = __le16_to_cpu(id->word92); + id->mprc = __le16_to_cpu(id->mprc); id->hw_config = __le16_to_cpu(id->hw_config); id->acoustic = __le16_to_cpu(id->acoustic); - for (i = 0; i < 5; i++) - id->words95_99[i] = __le16_to_cpu(id->words95_99[i]); + id->msrqs = __le16_to_cpu(id->msrqs); + id->sxfert = __le16_to_cpu(id->sxfert); + id->sal = __le16_to_cpu(id->sal); + id->spg = __le32_to_cpu(id->spg); id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2); for (i = 0; i < 22; i++) id->words104_125[i] = __le16_to_cpu(id->words104_125[i]); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ppc/mm/fault.c linux.20pre2-ac1/arch/ppc/mm/fault.c --- linux.20pre2/arch/ppc/mm/fault.c 2002-08-13 13:58:34.000000000 +0100 +++ linux.20pre2-ac1/arch/ppc/mm/fault.c 2002-08-06 15:42:20.000000000 +0100 @@ -109,8 +109,6 @@ goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, address)) goto bad_area; @@ -197,8 +195,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ppc64/kernel/ioctl32.c linux.20pre2-ac1/arch/ppc64/kernel/ioctl32.c --- linux.20pre2/arch/ppc64/kernel/ioctl32.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/arch/ppc64/kernel/ioctl32.c 2002-08-06 15:42:22.000000000 +0100 @@ -4149,6 +4149,8 @@ COMPATIBLE_IOCTL(HCIDEVUP), COMPATIBLE_IOCTL(HCIDEVDOWN), COMPATIBLE_IOCTL(HCIDEVRESET), +COMPATIBLE_IOCTL(HCIDEVRESTAT), +COMPATIBLE_IOCTL(HCIGETDEVINFO), COMPATIBLE_IOCTL(HCIGETDEVLIST), COMPATIBLE_IOCTL(HCISETRAW), COMPATIBLE_IOCTL(HCISETSCAN), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ppc64/kernel/pci.c linux.20pre2-ac1/arch/ppc64/kernel/pci.c --- linux.20pre2/arch/ppc64/kernel/pci.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/arch/ppc64/kernel/pci.c 2002-08-06 15:42:22.000000000 +0100 @@ -364,7 +364,7 @@ int -pcibios_enable_resources(struct pci_dev *dev) +pcibios_enable_resources(struct pci_dev *dev, int mask) { u16 cmd, old_cmd; int idx; @@ -587,6 +587,8 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; for (idx=0; idx<6; idx++) { + if(!(mask & (1<resource[idx]; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/ppc64/kernel/setup.c linux.20pre2-ac1/arch/ppc64/kernel/setup.c --- linux.20pre2/arch/ppc64/kernel/setup.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/arch/ppc64/kernel/setup.c 2002-08-06 15:42:22.000000000 +0100 @@ -607,17 +607,19 @@ id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2); id->csf_default = __le16_to_cpu(id->csf_default); id->dma_ultra = __le16_to_cpu(id->dma_ultra); - id->word89 = __le16_to_cpu(id->word89); - id->word90 = __le16_to_cpu(id->word90); + id->trseuc = __le16_to_cpu(id->trseuc); + id->trsEuc = __le16_to_cpu(id->trsEuc); id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); - id->word92 = __le16_to_cpu(id->word92); + id->mprc = __le16_to_cpu(id->mprc); id->hw_config = __le16_to_cpu(id->hw_config); id->acoustic = __le16_to_cpu(id->acoustic); - for (i = 0; i < 5; i++) - id->words95_99[i] = __le16_to_cpu(id->words95_99[i]); + id->msrqs = __le16_to_cpu(id->msrqs); + id->sxfert = __le16_to_cpu(id->sxfert); + id->sal = __le16_to_cpu(id->sal); + id->spg = __le32_to_cpu(id->spg); id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2); - for (i = 0; i < 21; i++) - id->words104_125[i] = __le16_to_cpu(id->words104_125[i]); + for (i = 0; i < 22; i++) + id->words104_125[i] = __le16_to_cpu(id->words104_125[i]); id->last_lun = __le16_to_cpu(id->last_lun); id->word127 = __le16_to_cpu(id->word127); id->dlf = __le16_to_cpu(id->dlf); @@ -627,14 +629,14 @@ id->word156 = __le16_to_cpu(id->word156); for (i = 0; i < 3; i++) id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); - id->cfa_power=__le16_to_cpu(id->cfa_power); - for (i = 0; i < 15; i++) + id->cfa_power = __le16_to_cpu(id->cfa_power); + for (i = 0; i < 14; i++) id->words161_175[i] = __le16_to_cpu(id->words161_175[i]); - for (i = 0; i < 29; i++) + for (i = 0; i < 31; i++) id->words176_205[i] = __le16_to_cpu(id->words176_205[i]); for (i = 0; i < 48; i++) id->words206_254[i] = __le16_to_cpu(id->words206_254[i]); - id->integrity_word=__le16_to_cpu(id->integrity_word); + id->integrity_word = __le16_to_cpu(id->integrity_word); } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/s390/kernel/entry.S linux.20pre2-ac1/arch/s390/kernel/entry.S --- linux.20pre2/arch/s390/kernel/entry.S 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/s390/kernel/entry.S 2002-08-13 14:09:16.000000000 +0100 @@ -254,13 +254,14 @@ ret_from_fork: basr %r13,0 l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base + # not saving R14 here because we go to sysc_return ultimately + l %r1,BASED(.Lschedtail) + basr %r14,%r1 # call schedule_tail (unlock stuff) GET_CURRENT # load pointer to task_struct to R9 stosm 24(%r15),0x03 # reenable interrupts sr %r0,%r0 # child returns 0 st %r0,SP_R2(%r15) # store return value (change R2 on stack) - l %r1,BASED(.Lschedtail) - la %r14,BASED(sysc_return) - br %r1 # call schedule_tail, return to sysc_return + b BASED(sysc_return) # # clone, fork, vfork, exec and sigreturn need glue, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/s390/mm/fault.c linux.20pre2-ac1/arch/s390/mm/fault.c --- linux.20pre2/arch/s390/mm/fault.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/arch/s390/mm/fault.c 2002-08-06 15:42:22.000000000 +0100 @@ -293,8 +293,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/s390x/kernel/entry.S linux.20pre2-ac1/arch/s390x/kernel/entry.S --- linux.20pre2/arch/s390x/kernel/entry.S 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/s390x/kernel/entry.S 2002-08-13 14:09:33.000000000 +0100 @@ -240,11 +240,11 @@ # .globl ret_from_fork ret_from_fork: + brasl %r14,schedule_tail GET_CURRENT # load pointer to task_struct to R9 stosm 48(%r15),0x03 # reenable interrupts xc SP_R2(8,%r15),SP_R2(%r15) # child returns 0 - larl %r14,sysc_return - jg schedule_tail # return to sysc_return + j sysc_return # # clone, fork, vfork, exec and sigreturn need glue, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/s390x/kernel/linux32.c linux.20pre2-ac1/arch/s390x/kernel/linux32.c --- linux.20pre2/arch/s390x/kernel/linux32.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/arch/s390x/kernel/linux32.c 2002-08-06 15:42:22.000000000 +0100 @@ -912,64 +912,97 @@ return sys32_fcntl(fd, cmd, arg); } -struct dqblk32 { - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u32 dqb_curblocks; - __u32 dqb_ihardlimit; - __u32 dqb_isoftlimit; - __u32 dqb_curinodes; - __kernel_time_t32 dqb_btime; - __kernel_time_t32 dqb_itime; -}; - extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); -asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) +#ifdef CONFIG_QIFACE_COMPAT +#ifdef CONFIG_QIFACE_V1 +struct user_dqblk32 { + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v1c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V1_GETQUOTA +#define Q_COMP_SETQUOTA Q_V1_SETQUOTA +#define Q_COMP_SETQLIM Q_V1_SETQLIM +#define Q_COMP_SETUSE Q_V1_SETUSE +#else +struct user_dqblk32 { + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u64 dqb_curspace; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v2c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V2_GETQUOTA +#define Q_COMP_SETQUOTA Q_V2_SETQUOTA +#define Q_COMP_SETQLIM Q_V2_SETQLIM +#define Q_COMP_SETUSE Q_V2_SETUSE +#endif + +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) { int cmds = cmd >> SUBCMDSHIFT; int err; - struct dqblk d; + comp_dqblk_t d; mm_segment_t old_fs; char *spec; switch (cmds) { - case Q_GETQUOTA: - break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)addr, - sizeof (struct dqblk32))) - return -EFAULT; - d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; - break; + case Q_COMP_GETQUOTA: + break; + case Q_COMP_SETQUOTA: + case Q_COMP_SETUSE: + case Q_COMP_SETQLIM: + if (copy_from_user(&d, (struct user_dqblk32 *)addr, + sizeof (struct user_dqblk32))) + return -EFAULT; + d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime; + break; default: - return sys_quotactl(cmd, special, - id, (caddr_t)addr); + return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr); } spec = getname (special); err = PTR_ERR(spec); if (IS_ERR(spec)) return err; - old_fs = get_fs (); + old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); + err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d); set_fs (old_fs); putname (spec); if (err) return err; - if (cmds == Q_GETQUOTA) { + if (cmds == Q_COMP_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct dqblk32 *)&d)->dqb_itime = i; - ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)addr, &d, - sizeof (struct dqblk32))) + ((struct user_dqblk32 *)&d)->dqb_itime = i; + ((struct user_dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct user_dqblk32 *)addr, &d, + sizeof (struct user_dqblk32))) return -EFAULT; } return 0; } +#else +/* No conversion needed for new interface */ +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) +{ + return sys_quotactl(cmd, special, id, addr); +} +#endif + static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { int err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/s390x/mm/fault.c linux.20pre2-ac1/arch/s390x/mm/fault.c --- linux.20pre2/arch/s390x/mm/fault.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/arch/s390x/mm/fault.c 2002-08-06 15:42:22.000000000 +0100 @@ -293,8 +293,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (tsk->pid == 1) { - tsk->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sh/mm/fault.c linux.20pre2-ac1/arch/sh/mm/fault.c --- linux.20pre2/arch/sh/mm/fault.c 2002-08-13 13:58:37.000000000 +0100 +++ linux.20pre2-ac1/arch/sh/mm/fault.c 2002-08-06 15:42:21.000000000 +0100 @@ -72,8 +72,6 @@ return 1; check_stack: - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, start) == 0) goto good_area; @@ -207,8 +205,7 @@ out_of_memory: up_read(&mm->mmap_sem); if (current->pid == 1) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); down_read(&mm->mmap_sem); goto survive; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc/kernel/sunos_ioctl.c linux.20pre2-ac1/arch/sparc/kernel/sunos_ioctl.c --- linux.20pre2/arch/sparc/kernel/sunos_ioctl.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc/kernel/sunos_ioctl.c 2002-08-06 15:42:19.000000000 +0100 @@ -39,8 +39,12 @@ { int ret = -EBADF; - if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) + read_lock(¤t->files->file_lock); + if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); /* First handle an easy compat. case for tty ldisc. */ if(cmd == TIOCSETD) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc/mm/fault.c linux.20pre2-ac1/arch/sparc/mm/fault.c --- linux.20pre2/arch/sparc/mm/fault.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc/mm/fault.c 2002-08-06 15:42:19.000000000 +0100 @@ -249,8 +249,6 @@ goto bad_area; if(vma->vm_start <= address) goto good_area; - if(!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if(expand_stack(vma, address)) goto bad_area; /* @@ -496,8 +494,6 @@ goto bad_area; if(vma->vm_start <= address) goto good_area; - if(!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if(expand_stack(vma, address)) goto bad_area; good_area: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc/mm/srmmu.c linux.20pre2-ac1/arch/sparc/mm/srmmu.c --- linux.20pre2/arch/sparc/mm/srmmu.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc/mm/srmmu.c 2002-08-13 14:10:07.000000000 +0100 @@ -1994,7 +1994,7 @@ iaddr = &(insn); \ daddr = &(dest); \ *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \ - } while(0); + } while(0) static void __init patch_window_trap_handlers(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc/mm/sun4c.c linux.20pre2-ac1/arch/sparc/mm/sun4c.c --- linux.20pre2/arch/sparc/mm/sun4c.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc/mm/sun4c.c 2002-08-13 14:10:07.000000000 +0100 @@ -386,7 +386,7 @@ daddr = &(dst); \ iaddr = &(src); \ *daddr = *iaddr; \ - } while (0); + } while (0) static void __init patch_kernel_fault_handler(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc64/kernel/binfmt_elf32.c linux.20pre2-ac1/arch/sparc64/kernel/binfmt_elf32.c --- linux.20pre2/arch/sparc64/kernel/binfmt_elf32.c 2002-08-13 13:58:36.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc64/kernel/binfmt_elf32.c 2002-08-06 15:42:21.000000000 +0100 @@ -43,7 +43,7 @@ dest[34] = (unsigned int) src->tnpc; \ dest[35] = src->y; \ dest[36] = dest[37] = 0; /* XXX */ \ -} while (0); +} while(0) typedef struct { union { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc64/kernel/ioctl32.c linux.20pre2-ac1/arch/sparc64/kernel/ioctl32.c --- linux.20pre2/arch/sparc64/kernel/ioctl32.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc64/kernel/ioctl32.c 2002-08-06 15:55:18.000000000 +0100 @@ -4558,19 +4558,11 @@ COMPATIBLE_IOCTL(HCIDEVDOWN) COMPATIBLE_IOCTL(HCIDEVRESET) COMPATIBLE_IOCTL(HCIDEVRESTAT) -COMPATIBLE_IOCTL(HCIGETDEVLIST) COMPATIBLE_IOCTL(HCIGETDEVINFO) -COMPATIBLE_IOCTL(HCIGETCONNLIST) -COMPATIBLE_IOCTL(HCIGETCONNINFO) +COMPATIBLE_IOCTL(HCIGETDEVLIST) COMPATIBLE_IOCTL(HCISETRAW) COMPATIBLE_IOCTL(HCISETSCAN) COMPATIBLE_IOCTL(HCISETAUTH) -COMPATIBLE_IOCTL(HCISETENCRYPT) -COMPATIBLE_IOCTL(HCISETPTYPE) -COMPATIBLE_IOCTL(HCISETLINKPOL) -COMPATIBLE_IOCTL(HCISETLINKMODE) -COMPATIBLE_IOCTL(HCISETACLMTU) -COMPATIBLE_IOCTL(HCISETSCOMTU) COMPATIBLE_IOCTL(HCIINQUIRY) /* Misc. */ COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc64/kernel/sunos_ioctl32.c linux.20pre2-ac1/arch/sparc64/kernel/sunos_ioctl32.c --- linux.20pre2/arch/sparc64/kernel/sunos_ioctl32.c 2002-08-13 13:58:36.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc64/kernel/sunos_ioctl32.c 2002-08-06 15:42:21.000000000 +0100 @@ -100,8 +100,12 @@ if(fd >= SUNOS_NR_OPEN) goto out; - if(!fcheck(fd)) + read_lock(¤t->files->file_lock); + if(!fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); if(cmd == TIOCSETD) { mm_segment_t old_fs = get_fs(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc64/kernel/sys_sparc32.c linux.20pre2-ac1/arch/sparc64/kernel/sys_sparc32.c --- linux.20pre2/arch/sparc64/kernel/sys_sparc32.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc64/kernel/sys_sparc32.c 2002-08-06 15:55:38.000000000 +0100 @@ -888,62 +888,97 @@ return sys32_fcntl(fd, cmd, arg); } -struct dqblk32 { - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u32 dqb_curblocks; - __u32 dqb_ihardlimit; - __u32 dqb_isoftlimit; - __u32 dqb_curinodes; - __kernel_time_t32 dqb_btime; - __kernel_time_t32 dqb_itime; -}; - extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); -asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) +#ifdef CONFIG_QIFACE_COMPAT +#ifdef CONFIG_QIFACE_V1 +struct user_dqblk32 { + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v1c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V1_GETQUOTA +#define Q_COMP_SETQUOTA Q_V1_SETQUOTA +#define Q_COMP_SETQLIM Q_V1_SETQLIM +#define Q_COMP_SETUSE Q_V1_SETUSE +#else +struct user_dqblk32 { + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u64 dqb_curspace; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; +typedef struct v2c_mem_dqblk comp_dqblk_t; + +#define Q_COMP_GETQUOTA Q_V2_GETQUOTA +#define Q_COMP_SETQUOTA Q_V2_SETQUOTA +#define Q_COMP_SETQLIM Q_V2_SETQLIM +#define Q_COMP_SETUSE Q_V2_SETUSE +#endif + +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) { int cmds = cmd >> SUBCMDSHIFT; int err; - struct dqblk d; + comp_dqblk_t d; mm_segment_t old_fs; char *spec; switch (cmds) { - case Q_GETQUOTA: - break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)addr, - sizeof (struct dqblk32))) - return -EFAULT; - d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; - break; + case Q_COMP_GETQUOTA: + break; + case Q_COMP_SETQUOTA: + case Q_COMP_SETUSE: + case Q_COMP_SETQLIM: + if (copy_from_user(&d, (struct user_dqblk32 *)addr, + sizeof (struct user_dqblk32))) + return -EFAULT; + d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime; + break; default: - return sys_quotactl(cmd, special, - id, (caddr_t)addr); + return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr); } spec = getname (special); err = PTR_ERR(spec); if (IS_ERR(spec)) return err; - old_fs = get_fs (); + old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); + err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d); set_fs (old_fs); putname (spec); - if (cmds == Q_GETQUOTA) { + if (err) + return err; + if (cmds == Q_COMP_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct dqblk32 *)&d)->dqb_itime = i; - ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)addr, &d, - sizeof (struct dqblk32))) + ((struct user_dqblk32 *)&d)->dqb_itime = i; + ((struct user_dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct user_dqblk32 *)addr, &d, + sizeof (struct user_dqblk32))) return -EFAULT; } - return err; + return 0; } +#else +/* No conversion needed for new interface */ +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr) +{ + return sys_quotactl(cmd, special, id, addr); +} +#endif + static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { int err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc64/mm/fault.c linux.20pre2-ac1/arch/sparc64/mm/fault.c --- linux.20pre2/arch/sparc64/mm/fault.c 2002-08-13 13:58:36.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc64/mm/fault.c 2002-08-06 15:42:21.000000000 +0100 @@ -346,8 +346,6 @@ if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (!(fault_code & FAULT_CODE_WRITE)) { /* Non-faulting loads shouldn't expand stack. */ insn = get_fault_insn(regs, insn); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/arch/sparc64/solaris/timod.c linux.20pre2-ac1/arch/sparc64/solaris/timod.c --- linux.20pre2/arch/sparc64/solaris/timod.c 2002-08-13 13:58:36.000000000 +0100 +++ linux.20pre2-ac1/arch/sparc64/solaris/timod.c 2002-08-06 15:42:21.000000000 +0100 @@ -149,7 +149,9 @@ struct socket *sock; SOLD("wakeing socket"); + read_lock(¤t->files->file_lock); sock = ¤t->files->fd[fd]->f_dentry->d_inode->u.socket_i; + read_unlock(¤t->files->file_lock); wake_up_interruptible(&sock->wait); read_lock(&sock->sk->callback_lock); if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) @@ -163,7 +165,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = sock->pfirst; sock->pfirst = it; if (!sock->plast) @@ -177,7 +181,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg at end"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = NULL; if (sock->plast) sock->plast->next = it; @@ -355,7 +361,11 @@ (int (*)(int, unsigned long *))SYS(socketcall); int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLD("entry"); @@ -636,7 +646,11 @@ SOLD("entry"); SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p)); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL)); @@ -847,7 +861,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; @@ -914,7 +930,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/CREDITS linux.20pre2-ac1/CREDITS --- linux.20pre2/CREDITS 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/CREDITS 2002-08-14 13:50:58.000000000 +0100 @@ -1888,7 +1888,8 @@ E: pavel@ucw.cz E: pavel@suse.cz D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd -D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB +D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB, +D: x86-64 port, software suspend S: Volkova 1131 S: 198 00 Praha 9 S: Czech Republic @@ -2541,6 +2542,12 @@ S: 7000 Stuttgart 50 S: Germany +N: Andrew Rodland +E: arodland@linuxguru.net +D: That crazy morse code thing. +P: D2B1 5215 B1B9 18E0 B6AD 6ADD 4373 165F 1770 BD5C +S: Pennsylvania, USA + N: Christoph Rohland E: hans-christoph.rohland@sap.com E: ch.rohland@gmx.net diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/Changes linux.20pre2-ac1/Documentation/Changes --- linux.20pre2/Documentation/Changes 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/Documentation/Changes 2002-08-12 12:10:46.000000000 +0100 @@ -55,7 +55,7 @@ o modutils 2.4.2 # insmod -V o e2fsprogs 1.25 # tune2fs o jfsutils 1.0.12 # fsck.jfs -V -o reiserfsprogs 3.x.1b # reiserfsck 2>&1|grep reiserfsprogs +o reiserfsprogs 3.6.3 # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version @@ -225,7 +225,6 @@ version v0.99.0 or higher. Running old versions may cause problems with programs using shared memory. - Networking ========== diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/Configure.help linux.20pre2-ac1/Documentation/Configure.help --- linux.20pre2/Documentation/Configure.help 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/Documentation/Configure.help 2002-08-13 14:12:30.000000000 +0100 @@ -440,8 +440,14 @@ The initial RAM disk is a RAM disk that is loaded by the boot loader (loadlin or lilo) and that is mounted as root before the normal boot procedure. It is typically used to load modules needed to mount the - "real" root file system, etc. See - for details. + "real" root file system, etc. + + Due to a problem elsewhere in the kernel, initial RAM disks _must_ + have the file system on them created with a 1024 byte block size. + If any other value is used, the kernel will be unable to mount the + RAM disk at boot time, causing a kernel panic. + + See for details. Loopback device support CONFIG_BLK_DEV_LOOP @@ -497,7 +503,7 @@ CONFIG_BLK_DEV_UMEM Saying Y here will include support for the MM5415 family of battery backed (Non-volatile) RAM cards. - http://www.umem.com/ + The cards appear as block devices that can be partitioned into as many as 15 partitions. @@ -685,6 +691,12 @@ Support for outboard IDE disks, tape drives, and CD-ROM drives connected through a PCMCIA card. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + ide-cs.o + Include IDE/ATAPI CD-ROM support CONFIG_BLK_DEV_IDECD If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is @@ -831,6 +843,12 @@ If both this SCSI emulation and native ATAPI support are compiled into the kernel, the native support will be used. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + ide-scsi.o + Use the NOOP Elevator (WARNING) CONFIG_BLK_DEV_ELEVATOR_NOOP If you are using a raid class top-level driver above the ATA/IDE core, @@ -1081,10 +1099,10 @@ This effect can be also invoked by calling "idex=ata66" If unsure, say N. -CMD64X and CMD680 chipset support +CMD64X/CMD680 chipset support CONFIG_BLK_DEV_CMD64X Say Y here if you have an IDE controller which uses any of these - chipsets: CMD643, CMD646, CMD648, CMD649 or CMD680. + chipsets: CMD643, CMD646, CMD648 or CMD680. CY82C693 chipset support CONFIG_BLK_DEV_CY82C693 @@ -1789,6 +1807,20 @@ want), say M here and read . The module will be called lvm-mod.o. +Device-mapper support +CONFIG_BLK_DEV_DM + Device-mapper is a low level volume manager. It works by allowing + people to specify mappings for ranges of logical sectors. Various + mapping types are available, in addition people may write their own + modules containing custom mappings if they wish. + + Higher level volume managers such as LVM2 use this driver. + + If you want to compile this as a module, say M here and read + . The module will be called dm-mod.o. + + If unsure, say N. + Multiple devices driver support (RAID and LVM) CONFIG_MD Support multiple physical spindles through a single logical device. @@ -1810,6 +1842,12 @@ . There you will also learn where to get the supporting user space utilities raidtools. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + md.o + If unsure, say N. Linear (append) mode @@ -1899,6 +1937,12 @@ transparent failover to the backup path(s) happens if a IO errors arrives on the primary path. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + multipath.o + If unsure, say N. Support for IDE Raid controllers @@ -1913,6 +1957,12 @@ has its own Raid drivers, which you should use if you need better performance. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + ataraid.o + Support Promise software RAID (Fasttrak(tm)) CONFIG_BLK_DEV_ATARAID_PDC Say Y or M if you have a Promise Fasttrak (tm) Raid controller @@ -2669,7 +2719,7 @@ Please note that you will need a recent version (>= 1.2.6a) of the iptables userspace program in order to use this feature. - See http://www.iptables.org/ for download instructions. + See for download instructions. If unsure, say 'N'. @@ -2828,7 +2878,7 @@ which can only be viewed through syslog. The appropriate userspace logging daemon (ulogd) may be obtained from - http://www.gnumonks.org/projects/ulogd + If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. @@ -3392,6 +3442,16 @@ a module, say M here and read . If unsure, say N. +CONFIG_SYNCLINK_CS + Enable support for the SyncLink PC Card serial adapter, running + asynchronous and HDLC communications up to 512Kbps. The port is + selectable for RS-232, V.35, RS-449, RS-530, and X.21 + + This driver may be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called synclinkmp.o. If you want to do that, say M + here. + ACP Modem (Mwave) support CONFIG_MWAVE The ACP modem (Mwave) for Linux is a WinModem. It is composed of a @@ -3625,6 +3685,16 @@ When in doubt, say N. +ACPI PCI Hotplug driver +CONFIG_HOTPLUG_PCI_ACPI + Say Y here if you have a system that supports PCI Hotplug using + ACPI. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called acpiphp.o. If you want to compile it + as a module, say M here and read . + MCA support CONFIG_MCA MicroChannel Architecture is found in some IBM PS/2 machines and @@ -4492,14 +4562,11 @@ BIOS routines contained in a ROM chip in HP PA-RISC based machines. Enabling this option will implement the linux framebuffer device and an fbcon color text console using calls to the STI BIOS routines. - The HP framebuffer device is usually planar, uses a strange memory + The HP framebuffer device is sometimes planar, using a strange memory layout, and changing the plane mask to create colored pixels - requires a call to the STI routines, so do not expect /dev/fb to - actually be useful. However, it is the best we have as far as - graphics on the HP chipsets due to lack of hardware level - documentation for the various on-board HP chipsets used in these - systems. It is sufficient for basic text console functions, - including fonts. + can require a call to the STI routines, so /dev/fb may not actually + be useful. However, on some systems packed pixel formats are supported. + It is sufficient for basic text console functions, including fonts. You should probably enable this option, unless you are having trouble getting video when booting the kernel (make sure it isn't @@ -5121,6 +5188,12 @@ Say Y here if you need PCMCIA support for your PC-style parallel ports. If unsure, say N. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + parport_cs.o + Support foreign hardware CONFIG_PARPORT_OTHER Say Y here if you want to be able to load driver modules to support @@ -5197,6 +5270,19 @@ replacement for kerneld.) Say Y here and read about configuring it in . +Kernel .config file saved in kernel image +CONFIG_IKCONFIG + This option enables the complete Linux kernel ".config" file contents + to be saved in the kernel (zipped) image file. It provides + documentation of which kernel options are used in a running kernel or + in an on-disk kernel. It can be extracted from the kernel image file + with a script and used as input to rebuild the current kernel or to + build another kernel. Since the kernel image is zipped, using this + option adds approximately 8 KB to a kernel image file. + This option is not available as a module. If you want a separate + file to save the kernel's .config contents, use 'installkernel' or 'cp' + or a similar tool, or just save it in '/lib/modules/'. + ARP daemon support CONFIG_ARPD Normally, the kernel maintains an internal cache which maps IP @@ -5425,6 +5511,12 @@ be inserted in and removed from the running kernel whenever you want). Most people won't need this and can say N. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + ipip.o + GRE tunnels over IP CONFIG_NET_IPGRE Tunneling means encapsulating data of one protocol type within @@ -5437,6 +5529,12 @@ tunneling" above). In addition, GRE allows multicast redistribution through the tunnel. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + ip_gre.o + Broadcast GRE over IP CONFIG_NET_IPGRE_BROADCAST One application of GRE/IP is to construct a broadcast WAN (Wide Area @@ -5767,6 +5865,12 @@ This driver is experimental, which means that it may not work. See the file . + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + ltpc.o + COPS LocalTalk PC card support CONFIG_COPS This allows you to use COPS AppleTalk cards to connect to LocalTalk @@ -5776,6 +5880,12 @@ networking support, above. Please read the file . + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + cops.o + Dayna firmware support CONFIG_COPS_DAYNA Support COPS compatible cards with Dayna style firmware (Dayna @@ -6206,6 +6316,12 @@ This is a Logical Link Layer protocol used for X.25 connections over Ethernet, using ordinary Ethernet cards. +ANSI/IEEE 802.2 Data link layer User Interface SAPs (EXPERIMENTAL) +CONFIG_LLC_UI + LLC User Interface SAPs is a Linux socket interface into the LLC datalink + layer. This allows a user to create entire user space network layers tied + to a real SAP. + Frame Diverter CONFIG_NET_DIVERT The Frame Diverter allows you to divert packets from the @@ -6316,6 +6432,12 @@ the real netlink socket. This is a backward compatibility option, choose Y for now. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + netlink_dev.o + Asynchronous Transfer Mode (ATM) CONFIG_ATM ATM is a high-speed networking technology for Local Area Networks @@ -6654,6 +6776,12 @@ boards supported by this driver, and for further information on the use of this driver. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + cciss.o + SCSI tape drive support for Smart Array 5xxx CONFIG_CISS_SCSI_TAPE When enabled (Y), this option allows SCSI tape drives and SCSI medium @@ -8967,13 +9095,13 @@ Aironet 4500/4800 I365 broken support CONFIG_AIRONET4500_I365 If you have a PCMCIA Aironet 4500/4800 card which you want to use - without the standard PCMCIA cardservices provided by the pcmcia-cs + without the standard PCMCIA card provided by the pcmcia-cs package, say Y here. This is not recommended, so say N. Aironet 4500/4800 PCMCIA support CONFIG_AIRONET4500_CS Say Y here if you have a PCMCIA Aironet 4500/4800 card which you - want to use with the standard PCMCIA cardservices provided by the + want to use with the standard PCMCIA card provided by the pcmcia-cs package. This driver is also available as a module ( = code which can be @@ -9675,7 +9803,7 @@ CONFIG_NET_SCH_HTB Say Y here if you want to use the Hierarchical Token Buckets (HTB) packet scheduling algorithm for some of your network devices. See - URL http://luxik.cdi.cz/~devik/qos/htb/ for complete manual and + URL for complete manual and in-depth articles. HTB is very similar to the CBQ regarding its goals however is has @@ -10261,7 +10389,7 @@ Read linux/Documentation/networking/slicecom.txt for help on configuring and using SliceCOM interfaces. Further info on these cards - can be found at http://www.itc.hu or . + can be found at or . Support for HDLC and syncPPP protocols on MultiGate boards CONFIG_COMX_PROTO_PPP @@ -10626,6 +10754,14 @@ experience problems, you can enable this option to restore the old RX-reset behavior. If unsure, say N. +Use older RX-reset method +CONFIG_8139_OLD_RX_RESET + The 8139too driver was recently updated to contain a more rapid + reset sequence, in the face of severe receive errors. This "new" + RX-reset method should be adequate for all boards. But if you + experience problems, you can enable this option to restore the + old RX-reset behavior. If unsure, say N. + SiS 900/7016 PCI Fast Ethernet Adapter support CONFIG_SIS900 This is a driver for the Fast Ethernet PCI network cards based on @@ -12303,12 +12439,44 @@ Quota support CONFIG_QUOTA If you say Y here, you will be able to set per user limits for disk - usage (also called disk quotas). Currently, it works only for the - ext2 file system. You need additional software in order to use quota - support; for details, read the Quota mini-HOWTO, available from + usage (also called disk quotas). Currently, it works for the + ext2, ext3, and reiserfs file system. You need additional software + in order to use quota support (you can download sources from + ). For further details, read + the Quota mini-HOWTO, available from . Probably the quota support is only useful for multi user systems. If unsure, say N. +Old quota format support +CONFIG_QFMT_V1 + This quota format was (is) used by kernels earlier than 2.4.??. If + you have quota working and you don't want to convert to new quota + format say Y here. + +VFS v0 quota format support +CONFIG_QFMT_V2 + This quota format allows using quotas with 32-bit UIDs/GIDs. If you + need this functionality say Y here. Note that you will need latest + quota utilities for new quota format with this kernel. + +Compatible quota interfaces +CONFIG_QIFACE_COMPAT + This option will enable old quota interface in kernel. + If you have old quota tools (version <= 3.04) and you don't want to + upgrade them say Y here. + +Original quota interface +CONFIG_QIFACE_V1 + This is the oldest quota interface. It was used for old quota format. + If you have old quota tools and you use old quota format choose this + interface (if unsure, this interface is the best one to choose). + +VFS v0 quota interface +CONFIG_QIFACE_V2 + This quota interface was used by VFS v0 quota format. If you need + support for VFS v0 quota format (eg. you're using quota on ReiserFS) + and you don't want to upgrade quota tools, choose this interface. + Memory Technology Device (MTD) support CONFIG_MTD Memory Technology Devices are flash, RAM and similar chips, often @@ -12319,6 +12487,12 @@ them. It will also allow you to select individual drivers for particular hardware and users of MTD devices. If unsure, say N. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + mtdcore.o + MTD debugging support CONFIG_MTD_DEBUG This turns on low-level debugging for the entire MTD sub-system. @@ -12331,6 +12505,12 @@ a separate MTD device, you require this option to be enabled. If unsure, say 'Y'. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + mtdpart.o + Note, however, that you don't need this option for the DiskOnChip devices. Partitioning on NFTL 'devices' is a different - that's the 'normal' form of partitioning used on a block device. @@ -12351,6 +12531,12 @@ SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + redboot.o + Compaq bootldr partition table parsing CONFIG_MTD_BOOTLDR_PARTS The Compaq bootldr deals with multiple 'images' in flash devices @@ -12392,6 +12578,12 @@ memory chips, and also use ioctl() to obtain information about the device, or to erase parts of it. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + mtdchar.o + Caching block device access to MTD devices CONFIG_MTD_BLOCK Although most flash chips have an erase size too large to be useful @@ -12412,6 +12604,12 @@ You do not need this option for use with the DiskOnChip devices. For those, enable NFTL support (CONFIG_NFTL) instead. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + mtdblock.o + Readonly block device access to MTD devices CONFIG_MTD_BLOCK_RO This allows you to mount read-only file systems (such as cramfs) @@ -12421,6 +12619,12 @@ You do not need this option for use with the DiskOnChip devices. For those, enable NFTL support (CONFIG_NFTL) instead. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + mtdblock_ro.o + FTL (Flash Translation Layer) support CONFIG_FTL This provides support for the original Flash Translation Layer which @@ -12435,6 +12639,12 @@ permitted to copy, modify and distribute the code as you wish. Just not use it. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + ftl.o + NFTL (NAND Flash Translation Layer) support CONFIG_NFTL This provides support for the NAND Flash Translation Layer which is @@ -12449,6 +12659,12 @@ permitted to copy, modify and distribute the code as you wish. Just not use it. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + nftl.o + Write support for NFTL (EXPERIMENTAL) CONFIG_NFTL_RW If you're lucky, this will actually work. Don't whinge if it @@ -12465,6 +12681,12 @@ option. Visit for more information on CFI. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + cfi_probe.o + CFI Advanced configuration options CONFIG_MTD_CFI_ADV_OPTIONS If you need to specify a specific endianness for access to flash @@ -12557,6 +12779,12 @@ commands, including some which are not CFI-compatible and hence cannot be used with the CONFIG_MTD_CFI_INTELxxx options. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + sharp.o + AMD compatible flash chip support (non-CFI) CONFIG_MTD_AMDSTD This option enables support for flash chips using AMD-compatible @@ -12565,16 +12793,34 @@ It also works on AMD compatible chips that do conform to CFI. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + amd_flash.o + Support for RAM chips in bus mapping CONFIG_MTD_RAM This option enables basic support for RAM chips accessed through a bus mapping driver. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + map_ram.o + Support for ROM chips in bus mapping CONFIG_MTD_ROM This option enables basic support for ROM chips accessed through a bus mapping driver. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + map_rom.o + JEDEC device support CONFIG_MTD_JEDEC Enable older older JEDEC flash interface devices for self @@ -12584,6 +12830,12 @@ chips. WARNING!!!! This code does not compile and is incomplete as are the specific JEDEC devices drivers. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + jedec.o + CFI Flash device mapped on StrongARM SA11x0 CONFIG_MTD_SA1100 This enables access to the flash chips on most platforms based on @@ -12614,6 +12866,12 @@ configure the physical address and size of the flash chips on your particular board as well as the bus width. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + physmap.o + Physical start location of flash chip mapping CONFIG_MTD_PHYSMAP_START This is the physical memory location at which the flash chips @@ -12667,6 +12925,12 @@ Dual-in-line JEDEC chip. This 'mapping' driver supports that arrangement, implementing three MTD devices. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + sc520cdp.o + Flash chip mapping on Arcom Control Systems SBC-MediaGX CONFIG_MTD_SBC_GXX This provides a driver for the on-board flash of Arcom Control @@ -12764,6 +13028,12 @@ Computer. More information on the board is available at . + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + octagon-5066.o + JEDEC Flash device mapped on Tempustech VMAX SBC301 CONFIG_MTD_VMAX This provides a 'mapping' driver which supports the way in which @@ -12771,11 +13041,23 @@ Board Computer. More information on the board is available at . + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + vmax301.o + Support for NAND flash devices CONFIG_MTD_NAND This enables support for accessing all type of NAND flash devices. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + nand.o + Support for software ECC algorithm CONFIG_MTD_NAND_ECC This enables software-based ECC for use with NAND flash chips. It @@ -12801,6 +13083,12 @@ This provides an MTD device driver for the M-Systems DiskOnChip 1000 devices, which are obsolete so you probably want to say 'N'. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + doc1000.o + M-Systems Disk-On-Chip 2000 and Millennium support CONFIG_MTD_DOC2000 This provides an MTD device driver for the M-Systems DiskOnChip @@ -12816,6 +13104,12 @@ emulate a block device by using a kind of file system on the flash chips. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + doc2000.o + Alternative Disk-On-Chip Millennium support CONFIG_MTD_DOC2001 This provides an alternative MTD device driver for the M-Systems @@ -12830,6 +13124,12 @@ emulate a block device by using a kind of file system on the flash chips. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + doc2001.o + Probe for DiskOnChip devices CONFIG_MTD_DOCPROBE This isn't a real config option, it's derived. @@ -12889,6 +13189,12 @@ particularly useful on the 2.2 kernels on PPC architectures as there was limited kernel space to deal with. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + pmc551.o + PMC551 256M DRAM Bugfix CONFIG_MTD_PMC551_BUGFIX Some of Ramix's PMC551 boards with 256M configurations have invalid @@ -12907,12 +13213,24 @@ you can still use it for storage or swap by using this driver to present it to the system as a Memory Technology Device. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + slram.o + Debugging RAM test driver CONFIG_MTD_MTDRAM This enables a test MTD device driver which uses vmalloc() to provide storage. You probably want to say 'N' unless you're testing stuff. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + mtdram.o + MTDRAM erase block size in KB CONFIG_MTDRAM_ERASE_SIZE This allows you to configure the size of the erase blocks in the @@ -12955,6 +13273,12 @@ the system regardless of media presence. Device nodes created with this driver will return -ENODEV upon access. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + map_absent.o + MTD emulation using block device CONFIG_MTD_BLKMTD This driver allows a block device to appear as an MTD. It would @@ -12965,6 +13289,12 @@ Testing MTD users (eg JFFS2) on large media and media that might be removed during a write (using the floppy drive). + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + blkmtd.o + Cirrus CDB89712 evaluation board mappings CONFIG_MTD_CDB89712 This enables access to the flash or ROM chips on the CDB89712 board. @@ -12982,6 +13312,12 @@ non-CFI Intel chips (that code is in MTD CVS and should shortly be sent for inclusion in Linus' tree) + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + jedec_probe.o + BIOS flash chip on Intel L440GX boards CONFIG_MTD_L440GX Support for treating the BIOS flash chip on Intel L440GX motherboards @@ -12989,6 +13325,12 @@ BE VERY CAREFUL. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + l440gx.o + 28F160xx flash driver for LART CONFIG_MTD_LART This enables the flash driver for LART. Please note that you do @@ -13847,7 +14189,7 @@ CONFIG_USB_RTL8150 Say Y here if you have RTL8150 based usb-ethernet adapter. Send me (petkan@users.sourceforge.net) any comments you may have. - You can also check for updates at http://pegasus2.sourceforge.net/ + You can also check for updates at This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -14107,6 +14449,25 @@ If unsure, say N. +CONFIG_USB_TIGL + If you own a Texas Instruments graphing calculator and use a + TI-GRAPH LINK USB cable (aka SilverLink), then you might be + interested in this driver. + + If you enable this driver, you will be able to communicate with + your calculator through a set of device nodes under /dev. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tiglusb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you don't know what the SilverLink cable is or what a Texas + Instruments graphing calculator is, then you probably don't need this + driver. + + If unsure, say N. + Tieman Voyager USB Braille display support CONFIG_USB_BRLVOYAGER Say Y here if you want to use the Voyager USB Braille display from @@ -14588,6 +14949,36 @@ Because this option adds considerably to the size of each buffer, most people will want to say N here. +BeOS filesystem support (BeFS) (read only) +CONFIG_BEFS_FS + The BeOS File System (BeFS) is the native file system of Be, Inc's + BeOS. Notable features include support for arbitrary attributes + on files and directories, and database-like indices on selected + attributes. (Also note that this driver doesn't make those features + available at this time). It is a 64 bit filesystem, so it supports + extremely large volumes and files. + + If you use this filesystem, you should also say Y to at least one + of the NLS (native language support) options below. + + If you don't know what this is about, say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called befs.o. + +Debug BeFS +CONFIG_BEFS_DEBUG + If you say Y here, you can use the 'debug' mount option to enable + debugging output from the driver. This is unlike previous versions + of the driver, where enabling this option would turn on debugging + output automatically. + + Example: + mount -t befs /dev/hda2 /mnt -o debug + + BFS file system support CONFIG_BFS_FS Boot File System (BFS) is a file system used under SCO UnixWare to @@ -15031,13 +15422,10 @@ If you would like to include the NFSv3 server as well as the NFSv2 server, say Y here. If unsure, say Y. -Provide NFS over TCP server support DEVELOPER ONLY +Provide NFS over TCP server support EXPERIMENTAL CONFIG_NFSD_TCP - If you are a developer and want to work on fixing problems with - NFS server over TCP support, say Y here. If unsure, say N. - - Some problems can be found by looking for FIXME in - . + Enable NFS service over TCP connections. This the officially + still experimental, but seems to work well. OS/2 HPFS file system support CONFIG_HPFS_FS @@ -15386,7 +15774,7 @@ Say Y here if you would like to use hard disks under Linux which were partitioned on a Macintosh. -Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL) +Windows Logical Disk Manager (Dynamic Disk) support CONFIG_LDM_PARTITION Say Y here if you would like to use hard disks under Linux which were partitioned using Windows 2000's or XP's Logical Disk Manager. @@ -15401,8 +15789,7 @@ Normal partitions are now called Basic Disks under Windows 2000 and XP. - Technical documentation to accompany this driver is available from: - . + For a fuller description read . If unsure, say N. @@ -15475,14 +15862,9 @@ Intel EFI GUID partition support CONFIG_EFI_PARTITION Say Y here if you would like to use hard disks under Linux which - were partitioned using EFI GPT. Presently only useful on the - IA-64 platform. - -/dev/guid support (EXPERIMENTAL) -CONFIG_DEVFS_GUID - Say Y here if you would like to access disks and partitions by - their Globally Unique Identifiers (GUIDs) which will appear as - symbolic links in /dev/guid. + were partitioned using EFI GPT. This is the default partition + scheme on IA64, and can be used on other platforms when + large block device (64-bit block address) support is desired. Ultrix partition table support CONFIG_ULTRIX_PARTITION @@ -15524,6 +15906,25 @@ hard drives and ADFS-formatted floppy disks. This is experimental codes, so if you're unsure, say N. +JFS filesystem support +CONFIG_JFS_FS + This is a port of IBM's Journalling Filesystem . More information is + available in the file Documentation/filesystems/jfs.txt. + + If you do not intend to use the JFS filesystem, say N. + +JFS Debugging +CONFIG_JFS_DEBUG + If you are experiencing any problems with the JFS filesystem, say + Y here. This will result in additional debugging messages to be + written to the system log. Under normal circumstances, this + results in very little overhead. + +JFS Statistics +CONFIG_JFS_STATISTICS + Enabling this option will cause statistics from the JFS file system + to be made available to the user in the /proc/fs/jfs/ directory. + /dev/pts file system for Unix98 PTYs CONFIG_DEVPTS_FS You should say Y here if you said Y to "Unix98 PTY support" above. @@ -16305,17 +16706,36 @@ HIL keyboard support CONFIG_HIL The "Human Interface Loop" is a older, 8-channel USB-like controller - used in Hewlett Packard PA-RISC based machines. There are a few - cases where it is seen on PC/MAC architectures as well, usually also - manufactured by HP. This driver is based off MACH and BSD drivers, - and implements support for a keyboard attached to the HIL port. + used in several Hewlett Packard models. This driver is based off + MACH and BSD drivers, and implements support for a keyboard attached + to the HIL port, but not for any other types of HIL input devices + like mice or tablets. However, it has been thoroughly tested and is + stable. + Full support for the USB-like functions and non-keyboard channels of - the HIL is not provided for in this driver. There are vestiges of - mouse support in the driver, but it is probably not working. The - necessary hardware documentation to fully support the HIL controller - and interface it to the linux-input API is lacking. + the HIL is currently being added to the PA-RISC port and will + be backported to work on the m68k port as well. - Enable this option if you intend to use a HIL keyboard. + Enable this option if you intend to use a HIL keyboard as your + primary keyboard and/or do not wish to test the new HIL driver. + +HP System Device Controller support +CONFIG_HP_SDC + This option enables supports for the the "System Device Controller", + an i8042 carrying microcode to manage a few miscellanous devices + on some Hewlett Packard systems. The SDC itself contains a 10ms + resolution timer/clock capable of delivering interrupts on periodic + and one-shot basis. The SDC may also be connected to a battery-backed + real-time clock, a basic audio waveform generator, and an HP-HIL + Master Link Controller serving up to seven input devices. + + By itself this option is rather useless, but enabling it will + enable selection of drivers for the abovementioned devices. + It is, however, incompatible with the old, reliable HIL keyboard + driver, and the new HIL driver is experimental, so if you plan to + use a HIL keyboard as your primary keyboard, you may wish to + keep using that driver until the new HIL drivers have had more + testing. Include IOP (IIfx/Quadra 9x0) ADB driver CONFIG_ADB_IOP @@ -16625,6 +17045,19 @@ read . The module will be called istallion.o. +PDC software console support +CONFIG_PDC_CONSOLE + Saying Y here will enable the software based PDC console to be + used as the system console. This is useful for machines in + which the hardware based console has not been written yet. The + following steps must be competed to use the PDC console: + + 1. create the device entry (mknod /dev/ttyB0 c 60 0) + 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 + 3. Add device ttyB0 to /etc/securetty (if you want to log on as + root on this console.) + 4. Change the kernel command console parameter to: console=ttyB0 + Microgate SyncLink adapter support CONFIG_SYNCLINK Provides support for the SyncLink ISA and PCI multiprotocol serial @@ -16636,6 +17069,17 @@ The module will be called synclink.o. If you want to do that, say M here. +CONFIG_SYNCLINKMP + Enable support for the SyncLink Multiport (2 or 4 ports) + serial adapter, running asynchronous and HDLC communications up + to 2.048Mbps. Each ports is independently selectable for + RS-232, V.35, RS-449, RS-530, and X.21 + + This driver may be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called synclinkmp.o. If you want to do that, say M + here. + Synchronous HDLC line discipline support CONFIG_N_HDLC Allows synchronous HDLC communications with tty device drivers that @@ -16763,6 +17207,10 @@ doing that; to actually get it to happen you need to pass the option "console=lp0" to the kernel at boot time. + Note that kernel messages can get lost if the printer is out of + paper (or off, or unplugged, or too busy..), but this behaviour + can be changed. See drivers/char/lp.c (do this at your own risk). + If the printer is out of paper (or off, or unplugged, or too busy..) the kernel will stall until the printer is ready again. By defining CONSOLE_LP_STRICT to 0 (at your own risk) you @@ -17650,7 +18098,134 @@ determined automatically, so you need to specify it here ONLY if running a DEC Alpha, otherwise this setting has no effect. -Double Talk PC internal speech card support +Speakup console speech output for Linux +CONFIG_SPEAKUP + Choosing this Option will include support for console speech output. + + Speakup provides access to Linux for the visually impaired community. + It does this by sending console output to a number of different + hardware speech synthesizers. It provides access to Linux by Making + screen review functions available such as are used in comercial screen + review packages for the MSDOS and MSWINDOWS world. + + The drivers supplied under this option are not standard devices in the + /dev/ sence of the meaning. They can be thought of as a video card + for the blind. They are used by speakup and only speakup. + + For more information about speakup and its drivers check out + , or read the Documentation in + linux/Documentation/speakup. + + The currently supported synthesizers are: + Accent PC internal synthesizer. + Accent SA external Accent synthesizer. + Apollo II external synthesizer. + Audapter external synthesizer. + Braille 'N Speak external synthesizer. + Dectalk Express and external synthesizers. + DoubleTalk PC Internal synthesizer, + LiteTalk/DoubleTalk-LT external serial synthesizers, + Speakout external synthesizer, + Transport external synthesizer. + + If you do not have one of these synths, say 'N' to this option. + +Default synthesizer for Speakup +CONFIG_SPEAKUP_DEFAULT + This option specifies which synthesizer Speakup should use by + default at boot time. + Valid values are: none, acntpc, acntsa, apolo, audptr, bns, decext, + dectlk dtlk, ltlk, spkout, txprt + + You can choose an alternatively compiled-in synthesizer at boot time + by using the speakup_synth kernel command line option, + I.E. speakup_synth=dtlk. + +Use Speakup keymap by default +CONFIG_SPEAKUP_KEYMAP + If this option is enabled, then a modified US keymap which includes + Speakup's screen review commands will be used by default. + +DoubleTalk driver for speakup. +CONFIG_SPEAKUP_DTLK + The DoubleTalk synthesizer is made by RC Systems. It is an internal + ISA card which uses no interrupts. Do not confuse this driver with + the standard DoubleTalk driver included in the kernel. + + If you don't have a DoubleTalk card say 'N' here. + +LiteTalk/DoubleTalk-LT driver for speakup. +CONFIG_SPEAKUP_LTLK + This driver is for the LiteTalk synthesizer made by MicroTalk or the + DoubleTalk-LT synthesizer made by RC Systems. These are serial + drivers for those external synths. + + If you don't have a LiteTalk or DoubleTalk-LT, say 'N' here. + +Speakout driver for speakup. +CONFIG_SPEAKUP_SPKOUT + This driver is for the Speakout external serial synthesizer made by + GW Micro. + + If you don't have a Speakout, say 'N' here. + +Accent PC driver for speakup. +CONFIG_SPEAKUP_ACNTPC + This driver is for the Accent PC internal synthesizer made by Aicom + Corp. + + If you Don't have an Accent PC, say 'N' here. + +Accent SA driver for speakup. +CONFIG_SPEAKUP_ACNTSA + This driver is for the Accent SA external synthesizer made by Aicom + Corp. + + If you Don't have an Accent SA, say 'N' here. + +Apollo II driver for speakup. +CONFIG_SPEAKUP_APOLO + This driver is for the Apollo II external synthesizer made + by Dolphin Computer Access limited. + + If you Don't have an Apollo II, say 'N' here. + +Audapter Speech System driver for speakup. +CONFIG_SPEAKUP_AUDPTR + This driver is for the Audapter external synthesizer made by + Personal Data System Inc. + + If you Don't have an Audapter, say 'N' here. + +Braille 'N Speak driver for speakup. +CONFIG_SPEAKUP_BNS + This driver is for the Braille 'N Speak external synthesizer made by + Blazie Engineering. + + If you Don't have a bns, say 'N' here. + +Dectalk Express driver for speakup. +CONFIG_SPEAKUP_DECTLK + This driver is for the Dectalk Express external synthesizer made by + Digital Equipment Corp. + + If you Don't have a Dectalk Express, say 'N' here. + +Dectalk External driver for speakup. +CONFIG_SPEAKUP_DECEXT + This driver is for the older Dectalk external synthesizer made by + Digital Equipment Corp. + + If you Don't have a Dectalk external, say 'N' here. + +Transport driver for speakup. +CONFIG_SPEAKUP_TXPRT + This driver is for the Artic Transport external synthesizer made by + Artic Technologies. + + If you Don't have a Transport, say 'N' here. + +Double Talk PC internal speech card support CONFIG_DTLK This driver is for the DoubleTalk PC, a speech synthesizer manufactured by RC Systems (). It is also @@ -18186,6 +18761,12 @@ Toshiba Linux utilities web site at: . + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + toshiba.o + Say Y if you intend to run this kernel on a Toshiba portable. Say N otherwise. @@ -18202,6 +18783,12 @@ You can force loading on unsupported models by passing the parameter `force=1' to the module. Use at your own risk. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + i8k.o + For more information on this driver and for utilities that make use of the module see the I8K Linux Utilities web site at: . @@ -18237,6 +18824,12 @@ MSR accesses are directed to a specific CPU on multi-processor systems. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + msr.o + /dev/cpu/*/cpuid - CPU information support CONFIG_X86_CPUID This device gives processes access to the x86 CPUID instruction to @@ -18244,6 +18837,12 @@ with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to /dev/cpu/31/cpuid. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + cpuid.o + SBC-60XX Watchdog Timer CONFIG_60XX_WDT This driver can be used with the watchdog timer found on some @@ -21843,7 +22442,7 @@ CU824: VMEBus Board with PCI extension with MPC8240 CPU - Manufacturer: MicroSys GmbH, http://www.microsys.de/ + Manufacturer: MicroSys GmbH, Date of Release: early 2001 (?) End of life: - URL: @@ -22793,6 +23392,12 @@ supported by this driver, and for further information on the use of this driver. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + cpqarray.o + Show crashed user process info CONFIG_PROCESS_DEBUG Say Y to print all process fault locations to the console. This is @@ -24848,6 +25453,14 @@ of the BUG call as well as the EIP and oops trace. This aids debugging but costs about 70-100K of memory. +Morse code panics +CONFIG_PANIC_MORSE + Say Y here to receive panic messages in morse code on your keyboard LEDs, and + optionally the PC speaker, if available. + The kernel param "panicblink" controls this feature, set it to 0 to disable, + 1 for LEDs only, 2 for pc speaker, or 3 for both. If you disable this option, + then you will receive a steady blink on the LEDs instead. + Include kgdb kernel debugger CONFIG_KGDB Include in-kernel hooks for kgdb, the Linux kernel source level @@ -24881,9 +25494,11 @@ U2/Uturn I/O MMU CONFIG_IOMMU_CCIO - Say Y here to enable DMA management routines for the first - generation of PA-RISC cache-coherent machines. Programs the - U2/Uturn chip in "Virtual Mode" and use the I/O MMU. + The U2/UTurn is a bus converter with io mmu present in the Cxxx, D, + J, K, and R class machines. Compiling this driver into the kernel will + not hurt anything, removing it will reduce your kernel by about 14k. + + If unsure, say Y. LBA/Elroy PCI support CONFIG_PCI_LBA @@ -25215,7 +25830,7 @@ ethernet interface does, including firewalling, bridging, and of course IP traffic. You will need the 'vconfig' tool from the VLAN project in order to effectively use VLANs. See the VLAN web page for more - information: http://www.candelatech.com/~greear/vlan.html If unsure, + information: If unsure, you can safely say 'N'. ARC console support @@ -25292,7 +25907,7 @@ Slave has its own LEDs CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS - Enable if the slave has it's own LEDs. + Enable if the slave has its own LEDs. ATA/IDE support CONFIG_ETRAX_IDE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/filesystems/00-INDEX linux.20pre2-ac1/Documentation/filesystems/00-INDEX --- linux.20pre2/Documentation/filesystems/00-INDEX 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/Documentation/filesystems/00-INDEX 2002-08-13 14:12:44.000000000 +0100 @@ -24,6 +24,8 @@ - info and mount options for the OS/2 HPFS. isofs.txt - info and mount options for the ISO 9660 (CDROM) filesystem. +jfs.txt + - info and mount options for the JFS filesystem. ncpfs.txt - info on Novell Netware(tm) filesystem using NCP protocol. ntfs.txt diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/filesystems/jfs.txt linux.20pre2-ac1/Documentation/filesystems/jfs.txt --- linux.20pre2/Documentation/filesystems/jfs.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/filesystems/jfs.txt 2002-08-06 18:01:05.000000000 +0100 @@ -0,0 +1,43 @@ +IBM's Journaled File System (JFS) for Linux + +JFS Homepage: http://oss.software.ibm.com/jfs/ + +Team members +------------ +Steve Best sbest@us.ibm.com +Dave Kleikamp shaggy@austin.ibm.com +Barry Arndt barndt@us.ibm.com +Christoph Hellwig hch@infradead.org + +The following mount options are supported: + +iocharset=name Character set to use for converting from Unicode to + ASCII. The default is compiled into the kernel as + CONFIG_NLS_DEFAULT. Use iocharset=utf8 for UTF8 + translations. This requires CONFIG_NLS_UTF8 to be set + in the kernel .config file. + +resize=value Resize the volume to blocks. JFS only supports + growing a volume, not shrinking it. This option is only + valid during a remount, when the volume is mounted + read-write. The resize keyword with no value will grow + the volume to the full size of the partition. + +JFS TODO list: + +Plans for our near term development items + + - enhance support for logfile on dedicated partition + - get access control list functionality operational + - get extended attributes functionality operational + +Longer term work items + + - implement defrag utility, for online defragmenting + - add quota support + - add support for block sizes (512,1024,2048) + +Please send bugs, comments, cards and letters to linuxjfs@us.ibm.com. + +The JFS mailing list can be subscribed to by using the link labeled +"Mail list Subscribe" at our web page http://oss.software.ibm.com/jfs/. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/filesystems/proc.txt linux.20pre2-ac1/Documentation/filesystems/proc.txt --- linux.20pre2/Documentation/filesystems/proc.txt 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/Documentation/filesystems/proc.txt 2002-08-06 15:42:22.000000000 +0100 @@ -708,36 +708,26 @@ used ones is far behind, you've encountered a peak in your usage of file handles and you don't need to increase the maximum. -inode-state, inode-nr and inode-max ------------------------------------ - -As with file handles, the kernel allocates the inode structures dynamically, -but can't free them yet. - -The value in inode-max denotes the maximum number of inode handlers. This -value should be 3 to 4 times larger than the value in file-max, since stdin, -stdout, and network sockets also need an inode struct to handle them. If you -regularly run out of inodes, you should increase this value. +inode-state and inode-nr +------------------------ The file inode-nr contains the first two items from inode-state, so we'll skip to that file... -inode-state contains three actual numbers and four dummy values. The numbers -are nr_inodes, nr_free_inodes, and preshrink (in order of appearance). +inode-state contains two actual numbers and five dummy values. The numbers +are nr_inodes and nr_free_inodes (in order of appearance). nr_inodes ~~~~~~~~~ -Denotes the number of inodes the system has allocated. This can be slightly -more than inode-max because Linux allocates them one pageful at a time. +Denotes the number of inodes the system has allocated. This number will +grow and shrink dynamically. nr_free_inodes -------------- -Represents the number of free inodes and preshrink is nonzero when nr_inodes -is greater than inode-max and the system needs to prune the inode list instead -of allocating more. - +Represents the number of free inodes. Ie. The number of inuse inodes is +(nr_inodes - nr_free_inodes). super-nr and super-max ---------------------- diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/filesystems/ramfs.txt linux.20pre2-ac1/Documentation/filesystems/ramfs.txt --- linux.20pre2/Documentation/filesystems/ramfs.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/filesystems/ramfs.txt 2002-08-06 15:42:23.000000000 +0100 @@ -0,0 +1,47 @@ + ramfs - An automatically resizing memory based filesystem + + + Ramfs is a file system which keeps all files in RAM. It allows read + and write access. In contrast to RAM disks, which get allocated a + fixed amount of RAM, ramfs grows and shrinks to accommodate the + files it contains. + + You can mount the ramfs with: + mount -t ramfs none /mnt/wherever + + Then just create and use files. When the filesystem is unmounted, all + its contents are lost. + + NOTE! This filesystem is probably most useful not as a real + filesystem, but as an example of how virtual filesystems can be + written. + +Resource limits: + +By default a ramfs will be limited to using half of (physical) memory +for storing file contents, a bit over that when the metadata is +included. The resource usage limits of ramfs can be controlled with +the following mount options: + + maxsize=NNN + Sets the maximum allowed memory usage of the +filesystem to NNN kilobytes. This will be rounded down to a multiple +of the page size. The default is half of physical memory. NB. unlike +most of the other limits, setting this to zero does *not* mean no +limit, but will actually limit the size of the filesystem data to zero +pages. There might be a use for this in some perverse situation. + + maxfilesize=NNN + Sets the maximum size of a single file on the +filesystem to NNN kilobytes. This will be rounded down to a multiple +of the page size. If NNN=0 there is no limit. The default is no limit. + + maxdentries=NNN + Sets the maximum number of directory entries (hard +links) on the filesystem to NNN. If NNN=0 there is no limit. By +default this is set to maxsize/4. + + maxinodes=NNN + Sets the maximum number of inodes (i.e. distinct +files) on the filesystem to NNN. If NNN=0 there is no limit. The +default is no limit (but there can never be more inodes than dentries). diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/initrd.txt linux.20pre2-ac1/Documentation/initrd.txt --- linux.20pre2/Documentation/initrd.txt 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/Documentation/initrd.txt 2002-08-06 15:42:27.000000000 +0100 @@ -115,8 +115,12 @@ 1) make sure loopback block devices are configured into the kernel 2) create an empty file system of the appropriate size, e.g. # dd if=/dev/zero of=initrd bs=300k count=1 - # mke2fs -F -m0 initrd + # mke2fs -F -m0 -b 1024 initrd (if space is critical, you may want to use the Minix FS instead of Ext2) + (Note that due to a problem elsewhere in the kernel, you _must_ use a + 1024-byte blocksize when creating your file system. If any other + value is used, the kernel will be unable to mount the initrd at boot + time, causing a kernel panic.) 3) mount the file system, e.g. # mount -t ext2 -o loop initrd /mnt 4) create the console device (not necessary if using devfs, but it can't diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/isapnp.txt linux.20pre2-ac1/Documentation/isapnp.txt --- linux.20pre2/Documentation/isapnp.txt 2002-08-13 13:58:39.000000000 +0100 +++ linux.20pre2-ac1/Documentation/isapnp.txt 2002-08-06 15:42:28.000000000 +0100 @@ -29,6 +29,7 @@ poke - poke configuration byte to selected register pokew - poke configuration word to selected register poked - poke configuration dword to selected register +allow_dma0 - allow dma channel 0 during auto activation: 0=off, 1=on Explanation: - variable begins with zero diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/ldm.txt linux.20pre2-ac1/Documentation/ldm.txt --- linux.20pre2/Documentation/ldm.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/ldm.txt 2002-08-11 21:08:42.000000000 +0100 @@ -0,0 +1,102 @@ + + LDM - Logical Disk Manager (Dynamic Disks) + ------------------------------------------ + +Overview +-------- + +Windows 2000 and XP use a new partitioning scheme. It is a complete +replacement for the MSDOS style partitions. It stores its information in a +1MiB journalled database at the end of the physical disk. The size of +partitions is limited only by disk space. The maximum number of partitions is +nearly 2000. + +Any partitions created under the LDM are called "Dynamic Disks". There are no +longer any primary or extended partitions. Normal MSDOS style partitions are +now known as Basic Disks. + +If you wish to use Spanned, Striped, Mirrored or RAID 5 Volumes, you must use +Dynamic Disks. The journalling allows Windows to make changes to these +partitions and filesystems without the need to reboot. + +Once the LDM driver has divided up the disk, you can use the MD driver to +assemble any multi-partition volumes, e.g. Stripes, RAID5. + +To prevent legacy applications from repartitioning the disk, the LDM creates a +dummy MSDOS partition containing one disk-sized partition. + + +Example +------- + +Below we have a 50MiB disk, divided into seven partitions. +N.B. The missing 1MiB at the end of the disk is where the LDM database is + stored. + + Device | Offset Bytes Sectors MiB | Size Bytes Sectors MiB + -------+----------------------------+--------------------------- + hda | 0 0 0 | 52428800 102400 50 + hda1 | 51380224 100352 49 | 1048576 2048 1 + hda2 | 16384 32 0 | 6979584 13632 6 + hda3 | 6995968 13664 6 | 10485760 20480 10 + hda4 | 17481728 34144 16 | 4194304 8192 4 + hda5 | 21676032 42336 20 | 5242880 10240 5 + hda6 | 26918912 52576 25 | 10485760 20480 10 + hda7 | 37404672 73056 35 | 13959168 27264 13 + +The LDM Database may not store the partitions in the order that they appear on +disk, but the driver will sort them. + +When Linux boots, you will see something like: + +Partition check: + hda: [LDM] hda1 hda2 hda3 hda4 hda5 hda6 hda7 + + +Compiling LDM Support +--------------------- + +To enable LDM, choose the following two options: + + "Advanced partition selection" CONFIG_PARTITION_ADVANCED + "Windows Logical Disk Manager (Dynamic Disk) support" CONFIG_LDM_PARTITION + +If you believe the driver isn't working as it should, you can enable the extra +debugging code. This will produce a LOT of output. The option is: + + "Windows LDM extra logging" CONFIG_LDM_DEBUG + +N.B. The partition code cannot be compiled as a module. + +As with all the partition code, if the driver doesn't see signs of its type of +partition, it will pass control to another driver, so there is no harm in +enabling it. + +If you have Dynamic Disks but don't enable the driver, then all you will see +is a dummy MSDOS partition filling the whole disk. You won't be able to mount +any of the volumes on the disk. + + +Booting +------- + +If you enable LDM support, then lilo is capable of booting from any of the +discovered partitions. However, grub does not understand the LDM partitioning +and cannot boot from a Dynamic Disk. + + +More Documentation +------------------ + +There is an Overview of the LDM online together with complete Technical +Documentation. It can also be downloaded in html. + + http://linux-ntfs.sourceforge.net/ldm/index.html + http://linux-ntfs.sourceforge.net/downloads.html + +If you have any LDM questions that aren't answered on the website, email me. + +Cheers, + FlatCap - Richard Russon + ldm@flatcap.org + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/sched-coding.txt linux.20pre2-ac1/Documentation/sched-coding.txt --- linux.20pre2/Documentation/sched-coding.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/sched-coding.txt 2002-08-06 15:42:28.000000000 +0100 @@ -0,0 +1,126 @@ + Reference for various scheduler-related methods in the O(1) scheduler + Robert Love , MontaVista Software + + +Note most of these methods are local to kernel/sched.c - this is by design. +The scheduler is meant to be self-contained and abstracted away. This document +is primarily for understanding the scheduler, not interfacing to it. Some of +the discussed interfaces, however, are general process/scheduling methods. +They are typically defined in include/linux/sched.h. + + +Main Scheduling Methods +----------------------- + +void load_balance(runqueue_t *this_rq, int idle) + Attempts to pull tasks from one cpu to another to balance cpu usage, + if needed. This method is called explicitly if the runqueues are + inbalanced or periodically by the timer tick. Prior to calling, + the current runqueue must be locked and interrupts disabled. + +void schedule() + The main scheduling function. Upon return, the highest priority + process will be active. + + +Locking +------- + +Each runqueue has its own lock, rq->lock. When multiple runqueues need +to be locked, lock acquires must be ordered by ascending &runqueue value. + +A specific runqueue is locked via + + task_rq_lock(task_t pid, unsigned long *flags) + +which disables preemption, disables interrupts, and locks the runqueue pid is +running on. Likewise, + + task_rq_unlock(task_t pid, unsigned long *flags) + +unlocks the runqueue pid is running on, restores interrupts to their previous +state, and reenables preemption. + +The routines + + double_rq_lock(runqueue_t *rq1, runqueue_t *rq2) + +and + + double_rq_unlock(runqueue_t *rq1, runqueue_t rq2) + +safely lock and unlock, respectively, the two specified runqueues. They do +not, however, disable and restore interrupts. Users are required to do so +manually before and after calls. + + +Values +------ + +MAX_PRIO + The maximum priority of the system, stored in the task as task->prio. + Lower priorities are higher. Normal (non-RT) priorities range from + MAX_RT_PRIO to (MAX_PRIO - 1). +MAX_RT_PRIO + The maximum real-time priority of the system. Valid RT priorities + range from 0 to (MAX_RT_PRIO - 1). +MAX_USER_RT_PRIO + The maximum real-time priority that is exported to user-space. Should + always be equal to or less than MAX_RT_PRIO. Setting it less allows + kernel threads to have higher priorities than any user-space task. +MIN_TIMESLICE +MAX_TIMESLICE + Respectively, the minimum and maximum timeslices (quanta) of a process. + +Data +---- + +struct runqueue + The main per-CPU runqueue data structure. +struct task_struct + The main per-process data structure. + + +General Methods +--------------- + +cpu_rq(cpu) + Returns the runqueue of the specified cpu. +this_rq() + Returns the runqueue of the current cpu. +task_rq(pid) + Returns the runqueue which holds the specified pid. +cpu_curr(cpu) + Returns the task currently running on the given cpu. +rt_task(pid) + Returns true if pid is real-time, false if not. + + +Process Control Methods +----------------------- + +void set_user_nice(task_t *p, long nice) + Sets the "nice" value of task p to the given value. +int setscheduler(pid_t pid, int policy, struct sched_param *param) + Sets the scheduling policy and parameters for the given pid. +void set_cpus_allowed(task_t *p, unsigned long new_mask) + Sets a given task's CPU affinity and migrates it to a proper cpu. + Callers must have a valid reference to the task and assure the + task not exit prematurely. No locks can be held during the call. +set_task_state(tsk, state_value) + Sets the given task's state to the given value. +set_current_state(state_value) + Sets the current task's state to the given value. +void set_tsk_need_resched(struct task_struct *tsk) + Sets need_resched in the given task. +void clear_tsk_need_resched(struct task_struct *tsk) + Clears need_resched in the given task. +void set_need_resched() + Sets need_resched in the current task. +void clear_need_resched() + Clears need_resched in the current task. +int need_resched() + Returns true if need_resched is set in the current task, false + otherwise. +yield() + Place the current process at the end of the runqueue and call schedule. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/sched-design.txt linux.20pre2-ac1/Documentation/sched-design.txt --- linux.20pre2/Documentation/sched-design.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/sched-design.txt 2002-08-06 15:42:28.000000000 +0100 @@ -0,0 +1,165 @@ + Goals, Design and Implementation of the + new ultra-scalable O(1) scheduler + + + This is an edited version of an email Ingo Molnar sent to + lkml on 4 Jan 2002. It describes the goals, design, and + implementation of Ingo's new ultra-scalable O(1) scheduler. + Last Updated: 18 April 2002. + + +Goal +==== + +The main goal of the new scheduler is to keep all the good things we know +and love about the current Linux scheduler: + + - good interactive performance even during high load: if the user + types or clicks then the system must react instantly and must execute + the user tasks smoothly, even during considerable background load. + + - good scheduling/wakeup performance with 1-2 runnable processes. + + - fairness: no process should stay without any timeslice for any + unreasonable amount of time. No process should get an unjustly high + amount of CPU time. + + - priorities: less important tasks can be started with lower priority, + more important tasks with higher priority. + + - SMP efficiency: no CPU should stay idle if there is work to do. + + - SMP affinity: processes which run on one CPU should stay affine to + that CPU. Processes should not bounce between CPUs too frequently. + + - plus additional scheduler features: RT scheduling, CPU binding. + +and the goal is also to add a few new things: + + - fully O(1) scheduling. Are you tired of the recalculation loop + blowing the L1 cache away every now and then? Do you think the goodness + loop is taking a bit too long to finish if there are lots of runnable + processes? This new scheduler takes no prisoners: wakeup(), schedule(), + the timer interrupt are all O(1) algorithms. There is no recalculation + loop. There is no goodness loop either. + + - 'perfect' SMP scalability. With the new scheduler there is no 'big' + runqueue_lock anymore - it's all per-CPU runqueues and locks - two + tasks on two separate CPUs can wake up, schedule and context-switch + completely in parallel, without any interlocking. All + scheduling-relevant data is structured for maximum scalability. + + - better SMP affinity. The old scheduler has a particular weakness that + causes the random bouncing of tasks between CPUs if/when higher + priority/interactive tasks, this was observed and reported by many + people. The reason is that the timeslice recalculation loop first needs + every currently running task to consume its timeslice. But when this + happens on eg. an 8-way system, then this property starves an + increasing number of CPUs from executing any process. Once the last + task that has a timeslice left has finished using up that timeslice, + the recalculation loop is triggered and other CPUs can start executing + tasks again - after having idled around for a number of timer ticks. + The more CPUs, the worse this effect. + + Furthermore, this same effect causes the bouncing effect as well: + whenever there is such a 'timeslice squeeze' of the global runqueue, + idle processors start executing tasks which are not affine to that CPU. + (because the affine tasks have finished off their timeslices already.) + + The new scheduler solves this problem by distributing timeslices on a + per-CPU basis, without having any global synchronization or + recalculation. + + - batch scheduling. A significant proportion of computing-intensive tasks + benefit from batch-scheduling, where timeslices are long and processes + are roundrobin scheduled. The new scheduler does such batch-scheduling + of the lowest priority tasks - so nice +19 jobs will get + 'batch-scheduled' automatically. With this scheduler, nice +19 jobs are + in essence SCHED_IDLE, from an interactiveness point of view. + + - handle extreme loads more smoothly, without breakdown and scheduling + storms. + + - O(1) RT scheduling. For those RT folks who are paranoid about the + O(nr_running) property of the goodness loop and the recalculation loop. + + - run fork()ed children before the parent. Andrea has pointed out the + advantages of this a few months ago, but patches for this feature + do not work with the old scheduler as well as they should, + because idle processes often steal the new child before the fork()ing + CPU gets to execute it. + + +Design +====== + +the core of the new scheduler are the following mechanizms: + + - *two*, priority-ordered 'priority arrays' per CPU. There is an 'active' + array and an 'expired' array. The active array contains all tasks that + are affine to this CPU and have timeslices left. The expired array + contains all tasks which have used up their timeslices - but this array + is kept sorted as well. The active and expired array is not accessed + directly, it's accessed through two pointers in the per-CPU runqueue + structure. If all active tasks are used up then we 'switch' the two + pointers and from now on the ready-to-go (former-) expired array is the + active array - and the empty active array serves as the new collector + for expired tasks. + + - there is a 64-bit bitmap cache for array indices. Finding the highest + priority task is thus a matter of two x86 BSFL bit-search instructions. + +the split-array solution enables us to have an arbitrary number of active +and expired tasks, and the recalculation of timeslices can be done +immediately when the timeslice expires. Because the arrays are always +access through the pointers in the runqueue, switching the two arrays can +be done very quickly. + +this is a hybride priority-list approach coupled with roundrobin +scheduling and the array-switch method of distributing timeslices. + + - there is a per-task 'load estimator'. + +one of the toughest things to get right is good interactive feel during +heavy system load. While playing with various scheduler variants i found +that the best interactive feel is achieved not by 'boosting' interactive +tasks, but by 'punishing' tasks that want to use more CPU time than there +is available. This method is also much easier to do in an O(1) fashion. + +to establish the actual 'load' the task contributes to the system, a +complex-looking but pretty accurate method is used: there is a 4-entry +'history' ringbuffer of the task's activities during the last 4 seconds. +This ringbuffer is operated without much overhead. The entries tell the +scheduler a pretty accurate load-history of the task: has it used up more +CPU time or less during the past N seconds. [the size '4' and the interval +of 4x 1 seconds was found by lots of experimentation - this part is +flexible and can be changed in both directions.] + +the penalty a task gets for generating more load than the CPU can handle +is a priority decrease - there is a maximum amount to this penalty +relative to their static priority, so even fully CPU-bound tasks will +observe each other's priorities, and will share the CPU accordingly. + +the SMP load-balancer can be extended/switched with additional parallel +computing and cache hierarchy concepts: NUMA scheduling, multi-core CPUs +can be supported easily by changing the load-balancer. Right now it's +tuned for my SMP systems. + +i skipped the prev->mm == next->mm advantage - no workload i know of shows +any sensitivity to this. It can be added back by sacrificing O(1) +schedule() [the current and one-lower priority list can be searched for a +that->mm == current->mm condition], but costs a fair number of cycles +during a number of important workloads, so i wanted to avoid this as much +as possible. + +- the SMP idle-task startup code was still racy and the new scheduler +triggered this. So i streamlined the idle-setup code a bit. We do not call +into schedule() before all processors have started up fully and all idle +threads are in place. + +- the patch also cleans up a number of aspects of sched.c - moves code +into other areas of the kernel where it's appropriate, and simplifies +certain code paths and data constructs. As a result, the new scheduler's +code is smaller than the old one. + + Ingo diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/speakup/DefaultKeyAssignments linux.20pre2-ac1/Documentation/speakup/DefaultKeyAssignments --- linux.20pre2/Documentation/speakup/DefaultKeyAssignments 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/speakup/DefaultKeyAssignments 2002-08-06 15:42:28.000000000 +0100 @@ -0,0 +1,45 @@ +This file is intended to give you an overview of the default keys used +by speakup for it's review functions. You may change them to be +anything you want but that will take some familiarity with key +mapping. + +We have remapped the insert or zero key on the keypad to act as a +shift key. Well, actually as an altgr key. So in the following list +InsKeyPad-period means hold down the insert key like a shift key and +hit the keypad period. + +KeyPad-8 Say current Line +InsKeyPad-8 say from top of screen to reading cursor. +KeyPad-7 Say Previous Line (UP one line) +KeyPad-9 Say Next Line (down one line) +KeyPad-5 Say Current Word +InsKeyPad-5 Spell Current Word +KeyPad-4 Say Previous Word (left one word) +InsKeyPad-4 say from left edge of line to reading cursor. +KeyPad-6 Say Next Word (right one word) +InsKeyPad-6 Say from reading cursor to right edge of line. +KeyPad-2 Say Current Letter +InsKeyPad-2 say current letter phonetically +KeyPad-1 Say Previous Character (left one letter) +KeyPad-3 Say Next Character (right one letter) +KeyPad-plus Say Entire Screen +InsKeyPad-plus Say from reading cursor line to bottom of screen. +KeyPad-Minus Park reading cursor (toggle) +InsKeyPad-minus Say character hex and decimal value. +KeyPad-period Say Position (current line, position and console) +InsKeyPad-period say colour attributes of current position. +InsKeyPad-9 Move reading cursor to top of screen (insert pgup) +InsKeyPad-3 Move reading cursor to bottom of screen (insert pgdn) +InsKeyPad-7 Move reading cursor to left edge of screen (insert home) +InsKeyPad-1 Move reading cursor to right edge of screen (insert end) +KeyPad-Enter Shut Up (until another key is hit) and sync reading cursor +InsKeyPad-Enter Shut Up (until toggled back on) and sync cursors +InsKeyPad-star n go to line (y) or column (x). Where 'n' is any + allowed value for the row or column for your current screen. +KeyPad-/ Mark and Cut screen region. +InsKeyPad-/ Paste screen region into any console. + +Hitting any key while speakup is outputting speech will quiet the +synth until it has caught up with what is being printed on the +console. + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/speakup/INSTALLATION linux.20pre2-ac1/Documentation/speakup/INSTALLATION --- linux.20pre2/Documentation/speakup/INSTALLATION 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/speakup/INSTALLATION 2002-08-06 15:42:28.000000000 +0100 @@ -0,0 +1,108 @@ +This document assumes you have had some experience with kernel +compilation and installation. If you have not, I recommend you get +the kernel source and read the README and various documents in the +linux/Documentation directory. In particular the Changes file to make +sure you have the appropriate utilities needed for installing a 2.2.xx +or 2.4xx kernel. It isn't as difficult as you might think. The +kernel README is intimidating the first time but once you get the +steps down, it's really pretty easy. Getting through the "make +config" is the tedious bit. + +The first thing to do is to place a copy of the tarball in the /usr/src +directory which is the directory the linux tree is located in as well. +Next untar speakup by typing: + +tar zxf speakup-1.00.tar.gz +cd speakup-1.00 +./install + +Note the dot-slash before the install. This will copy the speakup +directory to the kernel tree and apply the various patches and +components to the appropriate kernel files. Depending on how +experienced you are with kernel compiling and hacking will determine +whether you should bother looking at any failed patches. If this +happens, you should probably write to the speakup mailing list for +help or myself. + +If all of the patch hunks apply successfully then just continue with +the standard steps to compile the kernel with: + +make mrproper +make config + +When you get to the section console speech output, answer 'y' to the +CONFIG_SPEAKUP prompt. You will be given a submenu with the list of +synthesizers which are currently supported. You can include as many +synths in the kernel as you wish but remember each one takes up kernel +space. You can only choose one of the synths as the default or none, +so just type dtlk or whatever is the correct string for the +synthesizer you have. You will also be asked if you wish to build-in +a speakup key map. If you do not say 'y' to this option you will need +to load a speakup map at boot time with whichever mechanism your +distribution uses for loading key maps. + +We have placed the speakup configuration options in make config just +after the vga console choice. For the DoubleTalk PC driver included +by Jim Van Zandt. I recommend you say no to that option. I have not +tried configuring them both in, but I wouldn't be at all surprised if +it didn't work. + +If all goes well up to this point you can continue with the compiling +process by doing: + +make dep >dep.file 2>&1 & +make bzImage >cc.file 2>&1 & +make modules >mod.file 2>&1 & + +I always redirect output to the files dep.file and cc.file so I can +look over the compilation record to make sure there are no errors and +warnings. + +Okay, you are ready to install the newly compiled kernel. Make sure +you make an linux.old entry in your lilo.conf file so you can recover +if it blows up. next as root run "make modules_install" to install +whatever modules you compiled and move the bzImage from +/usr/src/linux/arch/i386/boot to wherever your kernel lives. Also +move the System.map from /usr/src/linux to where your System.map +lives. On our systems we use debian so we create an vmlinuz-speakup +and System.map-speakup in our /boot directory and set the symbolic +links vmlinuz and System.map in the root (/) directory to point to the +images. Now type lilo to tell lilo to build the new booter file and +install it. + +As of version 0.07, the keymap for speakup is automatically built in +at compile time. If you have other keymaps installed at boot time, +you might want to consider removing them before you reboot the system. + +If everything has gone OK up until now, cross your fingers and type: + +shutdown -r now + +Your system should start talking to you as soon as it starts booting. +It will talk and talk and ... well, you might want to hit the +keypad-enter key to tell it to shut up. You should also read the +DefaultKeyAssignments file to learn the various review functions +available. + +As of v-0.10 the speakup configuration options are in the +/proc/speakup subtree. The individual options should be fairly +obvious by their names such as rate, volume, punc_level and so forth. +You can manipulate them by cat'ing or echoing new values to them such +as: + +echo 9 >/proc/speakup/rate + +You can see what the current values are by cat'ing those files to the console: + +cat /proc/speakup/rate + +I have probably managed to overlook a whole whack of things because +this is the, enter version number here, draft. Don't worry we'll get +it right eventually. If you like the package you really should get on +the mailing list and start participating in it's development. + + Kirk + +email: kirk@braille.uwo.ca +phone: (519) 679-6845 (home) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/speakup/keymap-tutorial linux.20pre2-ac1/Documentation/speakup/keymap-tutorial --- linux.20pre2/Documentation/speakup/keymap-tutorial 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/speakup/keymap-tutorial 2002-08-06 15:42:28.000000000 +0100 @@ -0,0 +1,140 @@ + Speakup Keymap Tutorial + +This is meant to be a basic tutorial on how to change the Linux keymap +file to assign speakup review functions to desired keys. It is not +intended to be a replacement for the loadkeys(8) or keymap(5) man +pages. + +The basic lay-out of the keymap file is a series of lines with the +following fields. The keyword keycode indicates this is the start of +a new key assignment. It is then followed by a number which +represents the actual key on the keyboard. That number is followed by +the equals '=' operator and finally a list of keywords representing +key names such as keypad5. Each line can have quite a few key +functions on it. They are interpreted by loadkeys in order and +assigned to key shift states depending on the order they are +encountered. So for example, the first value after the equals is the +keys unshifted state, while the second is the keys shifted state. If +you wish to learn the order they are interpreted in read the +loadkeys(8) and keymap(5) man pages. + +You can have subsequent lines which are indented and start with +another keyword for the various shifted states. This way you can +assign some of the states without having to specify them all in order +up until you get to the one you want to assign. + +In speakup, we have assigned the insert key on the number pad to the +altgr keyword. This is not required; you could choose any other +shifted state keyword. We used altgr because it typically represents +the right hand alt key. In Linux each shift key is separate and +independent, so the left shift and the right shift keys are not +necessarily the same. The altgr key is not really used for anything +important, so we steel it. + +Here are the default key assignments for the number eight on the +keypad: + +keycode 72 = KP_8 + alt keycode 72 = Ascii_8 + +As you can see, the first line starts with keycode followed by 72 +which is the actual number assigned to the key when the keyboard port +is read. The KP_8 after the equal sign, is the symbolic representation +of the function called when that key is hit. + +The second line is the same format except it starts with the keyword +alt which is indented. That means that the function at the end of +that line Ascii_8 is applied to the alt-shifted eight key. + +Now here are the speakup assignments for that key: + +keycode 72 = 0x0d0a + altgr keycode 72 = 0x0d20 +#keycode 72 = KP_8 + alt keycode 72 = Ascii_8 + +Notice that the only thing which has changed on the first line is the +function called when the key is struck. It is a hexadecimal number +identifying the function called in a look up table. It is not a +symbolic representation yet because that means we need to change the +loadkeys program to understand our symbolic names. We will do this in +the future but for now it is more expedient to just use the table +indices. You will find a table at the bottom of this document +listing the review functions and their corresponding hex lookups. + +The 0x0d0a in the first line above is speakup's say line function. +The second line ends with 0x0d20 which is speakup's read from top of +screen to reading cursor line. + +The third line is the original key assignment commented out with a +number-sign '#' at the beginning. I do that so I can easily find the +keys I want to affect by symbolic name. Otherwise I would need to +keep a look up table for all the keycodes. I recommend you do this as +well or you'll be very sorry at some point in the future. + +The forth line is just the standard key assignment for the left hand +alt key. + +Now let's say we want to design a different keyboard layout. I'll use +an example for the JAWS style keypad because I've specifically been +asked to help with that. JAWS uses the eight on the keypad to move up +a line or the speakup function to read previous line. JAWS also uses +the keypad_8 key in a shifted mode to read the current line. I +apologize if these are not quite right. It has been a long time since +I used JAWS. So we would have the following two lines: + +keycode 72 = 0x0d0b + altgr keycode 72 = 0x0d0a + +The hex value 0x0d0b in the first line is speakup's SAY_PREVIOUS_LINE +function. The 0x0d0a in the second line is the same say_line function +as we had earlier. So when the number eight is hit on the keypad +speakup will read the previous line and when the number eight is +shifted with the insert key on the keypad it will read the current +line. + +As you can tell, it is not really very difficult to reassign the keys +to different review functions. + +Once you have carefully edited the keymap file, called default.map in +the speakup distribution, you copy it into the /etc/kbd directory. +Make sure you back up the original default.map from that directory +first, if there is one. Then you run loadkeys to load the new map +into the kernel: + +loadkeys /etc/kbd/default.map + +If you wish to build your new keyboard lay-out into the kernel, after +testing it, copy the default.map file into the drivers/char directory, +with the name defkeymap.map, of your Linux source tree. Then rm the +defkeymap.c file and recompile the kernel. Because there is no +defkeymap.c `make' will rebuild it on the next compile. + +Here is a list of the available speakup review functions at this point +in time. + +SAY_CHAR 0x0d04 /* say this character */ +SAY_PREV_CHAR 0x0d05 /* say character left of this char */ +SAY_NEXT_CHAR 0x0d06 /* say char right of this char */ +SAY_WORD 0x0d07 /* say this word under reading cursor */ +SAY_PREV_WORD 0x0d08 +SAY_NEXT_WORD 0x0d09 +SAY_LINE 0x0d0a /* say this line */ +SAY_PREV_LINE 0x0d0b /* say line above this line */ +SAY_NEXT_LINE 0x0d0c +TOP_EDGE 0x0d0d /* move to top edge of screen */ +BOTTOM_EDGE 0x0d0e +LEFT_EDGE 0x0d0f +RIGHT_EDGE 0x0d10 +SAY_PHONETIC_CHAR 0x0d11 /* say this character phonetically */ +SPELL_WORD 0x0d12 /* spell this word letter by letter */ +SAY_SCREEN 0x0d14 +SAY_POSITION 0x0d1b +SPEECH_OFF 0x0d1c +SAY_ATTRIBUTES 0x0d1d +SPEAKUP_PARKED 0x0d1e +SAY_FROM_TOP 0x0d20 +SAY_TO_BOTTOM 0x0d21 +SAY_FROM_LEFT 0x0d22 +SAY_TO_RIGHT 0x0d23 + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/speakup/README linux.20pre2-ac1/Documentation/speakup/README --- linux.20pre2/Documentation/speakup/README 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/speakup/README 2002-08-06 15:42:28.000000000 +0100 @@ -0,0 +1,98 @@ +Welcome to the speakup project for the Speakup speech package for Linux. + +Speakup is written by Kirk Reiser and Andy Berdan. It is licensed +under the GPL. If you don't already know, the GPL stands for the GNU +General Public License. Which basically states that this code is free to +copy, modify and distribute to anyone interested in playing with it. +The one thing you may not do is turn any part of it into proprietary +or commercial code without the permission of the author. That's me. + +If you are interested in being involved with the development of speech +output for Linux you can subscribe to the Speakup mailing list by +sending a message to speakup-request@braille.uwo.ca with the line: subscribe. You can also subscribe by going to the speakup web page and following the links at http://www.linux-speakup.org. + +We are at a very early stage in the development of this package. +Hopefully changes will happen often and many. The current files in +this directory are: + +DefaultKeyAssignments # speakup's default review keys +INSTALLATION # for installing speakup from the tar ball. +README # this file +keymap-tutorial # a tutorial on how to layout the keyboard + +Read the INSTALLATION file to learn how to apply the patches and the +default.map for the keyboard. You should also read the Changes file. +It really has any new things I've added since last time. + +There is no documentation in any of these files to instruct you what +to do if something goes wrong with the patching or compilation. If +you would like that information you will need to subscribe to the +mailing list and ask for help, or write me kirk@braille.uwo.ca for +help. I suggest the mailing list because I will probably tire quickly +of answering the same questions over and over. You could always +decide to dig-in and take on the task, and write documentation to help +others. + +There also is a speakup reflector for the Speak Freely package, which +many of us hang out on and discuss all sorts of topics from speakup +problems to ALSA driver installation and just about anything else +you'd like to talk about. The reflector is at lwl.braille.uwo.ca:4074 +with it's lwl page at lwl.braille.uwo.ca/speakup.html. Come and join +us, it's fun! + +Acknowledgements: + +I am really very new at kernel hacking and screen review package +writing, so I have depended heavily on other folks kindness to help me +a long. No doubt I will continue to abuse them freely and others +before this is a really good speech solution for Linux. (Oh Well!, +somebody's got to do it.) + +Theodore Ts'o. He gave me a good discussion of unicode and UTF and +the like. He doesn't even remember writing me about it. + +Alan Cox. He has answered many questions about scheduling and wait +queues and timers along with code fragments and so on. I just wish I +understood it all totally. He has also helped immensely in moving +this package toward inclusion in the standard kernel tree. (Maybe next +release!) + +Martin Mares. He pointed me in the right direction to figuring out +the colour attributes and other useful tidbits. + +Paul McDermott. He really is the catalyst for me to actually get +this all working. Besides I like seeing him bounce around and get all +excited every time I have something new working. + +John Covici, He was the first person to actually attempt writing +another synthesizer driver for speakup. It was the Speakout driver so +it was also the first serial driver. + +Brian Borowski, he was the first person to actually write a speakup +function other than Andy and I. + +Jim Danley, he has more or less become my main man in helping test +code, add new features, bounce ideas off and generally become a good +friend. + +Matt Campbell, he basically rewrote the drivers to be able to include +all synths in the kernel at the same time. The distribution +maintainers appreciate him a lot as well. + +Gene Collins, he was very helpful debugging the current release prior +to its public showing. He has also worked hard educating others on +the list and writing the ALSA mini howto. + +I would also like to really thank the folks that handle the +distribution packages. I and many other people would not find access +to speakup nearly so convenient without their efforts. They include +Bill Acker, Tom Moore, Matt Campbell, Joe Norton and Joshua Lambert. + +There are probably many more I am forgetting right now. I guess I'll +just have to add you all later. + + +Happy Hacking! + + Kirk + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/sysctl/vm.txt linux.20pre2-ac1/Documentation/sysctl/vm.txt --- linux.20pre2/Documentation/sysctl/vm.txt 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/Documentation/sysctl/vm.txt 2002-08-06 15:42:27.000000000 +0100 @@ -1,4 +1,4 @@ -Documentation for /proc/sys/vm/* kernel version 2.2.10 +Documentation for /proc/sys/vm/* kernel version 2.4.19 (c) 1998, 1999, Rik van Riel For general info and legal blurb, please look in README. @@ -6,7 +6,7 @@ ============================================================== This file contains the documentation for the sysctl files in -/proc/sys/vm and is valid for Linux kernel version 2.2. +/proc/sys/vm and is valid for Linux kernel version 2.4. The files in this directory can be used to tune the operation of the virtual memory (VM) subsystem of the Linux kernel, and @@ -34,26 +34,27 @@ This file controls the operation of the bdflush kernel daemon. The source code to this struct can be found in linux/fs/buffer.c. It currently contains 9 integer values, -of which 4 are actually used by the kernel. +of which 6 are actually used by the kernel. From linux/fs/buffer.c: -------------------------------------------------------------- union bdflush_param { struct { - int nfract; /* Percentage of buffer cache dirty to + int nfract; /* Percentage of buffer cache dirty to activate bdflush */ - int dummy1; /* old "ndirty" */ + int ndirty; /* Maximum number of dirty blocks to write out per + wake-cycle */ int dummy2; /* old "nrefill" */ int dummy3; /* unused */ int interval; /* jiffies delay between kupdate flushes */ - int age_buffer; /* Time for normal buffer to age */ - int nfract_sync;/* Percentage of buffer cache dirty to + int age_buffer; /* Time for normal buffer to age before we flush it */ + int nfract_sync;/* Percentage of buffer cache dirty to activate bdflush synchronously */ - int dummy4; /* unused */ + int nfract_stop_bdflush; /* Percentage of buffer cache dirty to stop bdflush */ int dummy5; /* unused */ } b_un; unsigned int data[N_PARAM]; -} bdf_prm = {{30, 64, 64, 256, 5*HZ, 30*HZ, 60, 0, 0}}; +} bdf_prm = {{30, 500, 0, 0, 5*HZ, 30*HZ, 60, 20, 0}}; -------------------------------------------------------------- int nfract: @@ -68,6 +69,13 @@ more frequent I/O operations. The default value is 30%, the minimum is 0%, and the maximum is 100%. +int ndirty: +The second parameter (ndirty) gives the maximum number of +dirty buffers that bdflush can write to the disk in one time. +A high value will mean delayed, bursty I/O, while a small +value can lead to memory shortage when bdflush isn't woken +up often enough. + int interval: The fifth parameter, interval, is the minimum rate at which kupdate will wake and flush. The value is expressed in @@ -88,7 +96,11 @@ synchronously. This can be viewed as the hard limit before bdflush forces buffers to disk. The default is 60%, the minimum is 0%, and the maximum is 100%. - + +int nfract_stop_bdflush: +The eighth parameter, nfract_stop_bdflush, governs the percentage +of buffer cache that is dirty which will stop bdflush. +The default is 20%, the miniumum is 0%, and the maxiumum is 100%. ============================================================== buffermem: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/video4linux/README.cpia linux.20pre2-ac1/Documentation/video4linux/README.cpia --- linux.20pre2/Documentation/video4linux/README.cpia 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/Documentation/video4linux/README.cpia 2002-08-06 15:42:28.000000000 +0100 @@ -1,8 +1,18 @@ -This is a driver for the CPiA PPC2 driven parallel connected -Camera. For example the Creative WebcamII is CPiA driven. +This is a driver for the CPiA PPC2 driven parallel connected or USB +Camera. For example the Creative WebcamII is CPiA driven. Also +various USB cameras, and the Intel Play QX3 microscope. ) [1]Peter Pregler, Linz 2000, published under the [2]GNU GPL + +NOTE ADDED (2002/05/23): +An improved version of the driver (cpia.c, cpia.h, cpia_usb.c, cpia_pp.c) +with extra features not yet integrated into the Official Linux Kernel versions +is available from http://sourceforge.net/projects/webcam as +cpia-2.2.1.tgz. This is a drop-in replacement for the driver in the kernel +sources, at least up to 2.4.18 kernels. The driver at sourceforge has been +stable for over a year, and is currently in low maintenance mode +(tracking kernel changes only). --------------------------------------------------------------------------- USAGE: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Documentation/vm/overcommit-accounting linux.20pre2-ac1/Documentation/vm/overcommit-accounting --- linux.20pre2/Documentation/vm/overcommit-accounting 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/Documentation/vm/overcommit-accounting 2002-08-06 15:42:27.000000000 +0100 @@ -0,0 +1,73 @@ +* This describes the overcommit management facility in the latest kernel + tree (FIXME: actually it also describes the stuff that isnt yet done) + +The Linux kernel supports four overcommit handling modes + +0 - Heuristic overcommit handling. Obvious overcommits of + address space are refused. Used for a typical system. It + ensures a seriously wild allocation fails while allowing + overcommit to reduce swap usage + +1 - No overcommit handling. Appropriate for some scientific + applications + +2 - (NEW) strict overcommit. The total address space commit + for the system is not permitted to exceed swap + half ram. + In almost all situations this means a process will not be + killed while accessing pages but only by malloc failures + that are reported back by the kernel mmap/brk code. + +3 - (NEW) paranoid overcommit The total address space commit + for the system is not permitted to exceed swap. The machine + will never kill a process accessing pages it has mapped + except due to a bug (ie report it!) + +Gotchas +------- + +The C language stack growth does an implicit mremap. If you want absolute +guarantees and run close to the edge you MUST mmap your stack for the +largest size you think you will need. For typical stack usage is does +not matter much but its a corner case if you really really care + +In modes 2 and 3 the MAP_NORESERVE flag is ignored. + + +How It Works +------------ + +The overcommit is based on the following rules + +For a file backed map + SHARED or READ only - 0 cost (the file is the map not swap) + + WRITABLE SHARED - size of mapping per instance + +For a direct map + SHARED or READ only - size of mapping + PRIVATE WRITEABLE - size of mapping per instance + +Additional accounting + Pages made writable copies by mmap + shmfs memory drawn from the same pool + +Status +------ + +o We account mmap memory mappings +o We account mprotect changes in commit +o We account mremap changes in size +o We account brk +o We account munmap +o We report the commit status in /proc +o Account and check on fork +o Review stack handling/building on exec +o SHMfs accounting +o Implement actual limit enforcement + +To Do +----- +o Account ptrace pages (this is hard) +o Disable MAP_NORESERVE in mode 2/3 +o Account for shared anonymous mappings properly + - right now we account them per instance diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/acpi/ospm/system/sm_osl.c linux.20pre2-ac1/drivers/acpi/ospm/system/sm_osl.c --- linux.20pre2/drivers/acpi/ospm/system/sm_osl.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/acpi/ospm/system/sm_osl.c 2002-08-06 15:42:18.000000000 +0100 @@ -685,6 +685,9 @@ */ if (state == ACPI_S2 || state == ACPI_S3) { #ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS + /* That && trick is *not going to work*. Read gcc + specs. That explicitely says: jumping from other + function is *not allowed*. */ wakeup_address = acpi_save_state_mem((unsigned long)&&acpi_sleep_done); if (!wakeup_address) goto acpi_sleep_done; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/atm/firestream.c linux.20pre2-ac1/drivers/atm/firestream.c --- linux.20pre2/drivers/atm/firestream.c 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/atm/firestream.c 2002-08-06 15:42:11.000000000 +0100 @@ -330,8 +330,8 @@ #define FS_DEBUG_QSIZE 0x00001000 -#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter " __FUNCTION__ "\n") -#define func_exit() fs_dprintk (FS_DEBUG_FLOW, "fs: exit " __FUNCTION__ "\n") +#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter %s\n", __FUNCTION__) +#define func_exit() fs_dprintk (FS_DEBUG_FLOW, "fs: exit %s\n", __FUNCTION__) struct fs_dev *fs_boards = NULL; @@ -760,6 +760,7 @@ default: /* Here we get the tx purge inhibit command ... */ /* Action, I believe, is "don't do anything". -- REW */ + break; } write_fs (dev, Q_RP(q->offset), Q_INCWRAP); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/cpqarray.c linux.20pre2-ac1/drivers/block/cpqarray.c --- linux.20pre2/drivers/block/cpqarray.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/cpqarray.c 2002-08-13 14:15:19.000000000 +0100 @@ -1141,8 +1141,12 @@ } complete_buffers(cmd->rq->bh, ok); + DBGPX(printk("Done with %p\n", cmd->rq);); + req_finished_io(cmd->rq); end_that_request_last(cmd->rq); + + } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/DAC960.c linux.20pre2-ac1/drivers/block/DAC960.c --- linux.20pre2/drivers/block/DAC960.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/DAC960.c 2002-08-06 15:56:13.000000000 +0100 @@ -5544,7 +5544,7 @@ static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File, unsigned int Request, unsigned long Argument) { - int ErrorCode; + int ErrorCode = 0 ; if (!capable(CAP_SYS_ADMIN)) return -EACCES; switch (Request) { @@ -5595,9 +5595,11 @@ int ControllerNumber, DataTransferLength; unsigned char *DataTransferBuffer = NULL; if (UserSpaceUserCommand == NULL) return -EINVAL; - ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand, - sizeof(DAC960_V1_UserCommand_T)); - if (ErrorCode != 0) goto Failure1; + if (copy_from_user(&UserCommand, UserSpaceUserCommand, + sizeof(DAC960_V1_UserCommand_T))) { + ErrorCode = -EFAULT; + goto Failure1; + } ControllerNumber = UserCommand.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) @@ -5610,9 +5612,11 @@ if (CommandOpcode & 0x80) return -EINVAL; if (CommandOpcode == DAC960_V1_DCDB) { - ErrorCode = - copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T)); - if (ErrorCode != 0) goto Failure1; + if (copy_from_user(&DCDB, UserCommand.DCDB, + sizeof(DAC960_V1_DCDB_T))) { + ErrorCode = -EFAULT; + goto Failure1; + } if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL; if (!((DataTransferLength == 0 && DCDB.Direction @@ -5638,10 +5642,12 @@ { DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL); if (DataTransferBuffer == NULL) return -ENOMEM; - ErrorCode = copy_from_user(DataTransferBuffer, - UserCommand.DataTransferBuffer, - -DataTransferLength); - if (ErrorCode != 0) goto Failure1; + if (copy_from_user(DataTransferBuffer, + UserCommand.DataTransferBuffer, + -DataTransferLength)) { + ErrorCode = -EFAULT; + goto Failure1; + } } if (CommandOpcode == DAC960_V1_DCDB) { @@ -5689,17 +5695,20 @@ DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); if (DataTransferLength > 0) { - ErrorCode = copy_to_user(UserCommand.DataTransferBuffer, - DataTransferBuffer, DataTransferLength); - if (ErrorCode != 0) goto Failure1; + if (copy_to_user(UserCommand.DataTransferBuffer, + DataTransferBuffer, DataTransferLength)) + ErrorCode = -EFAULT; + goto Failure1; } if (CommandOpcode == DAC960_V1_DCDB) { Controller->V1.DirectCommandActive[DCDB.Channel] [DCDB.TargetID] = false; - ErrorCode = - copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_V1_DCDB_T)); - if (ErrorCode != 0) goto Failure1; + if (copy_to_user(UserCommand.DCDB, &DCDB, + sizeof(DAC960_V1_DCDB_T))) { + ErrorCode = -EFAULT; + goto Failure1; + } } ErrorCode = CommandStatus; Failure1: @@ -5722,9 +5731,11 @@ unsigned char *DataTransferBuffer = NULL; unsigned char *RequestSenseBuffer = NULL; if (UserSpaceUserCommand == NULL) return -EINVAL; - ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand, - sizeof(DAC960_V2_UserCommand_T)); - if (ErrorCode != 0) goto Failure2; + if (copy_from_user(&UserCommand, UserSpaceUserCommand, + sizeof(DAC960_V2_UserCommand_T))) { + ErrorCode = -EFAULT; + goto Failure2; + } ControllerNumber = UserCommand.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) @@ -5743,10 +5754,12 @@ { DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL); if (DataTransferBuffer == NULL) return -ENOMEM; - ErrorCode = copy_from_user(DataTransferBuffer, - UserCommand.DataTransferBuffer, - -DataTransferLength); - if (ErrorCode != 0) goto Failure2; + if (copy_from_user(DataTransferBuffer, + UserCommand.DataTransferBuffer, + -DataTransferLength)) { + ErrorCode = -EFAULT; + goto Failure2; + } } RequestSenseLength = UserCommand.RequestSenseLength; if (RequestSenseLength > 0) @@ -5816,25 +5829,32 @@ DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); if (RequestSenseLength > UserCommand.RequestSenseLength) RequestSenseLength = UserCommand.RequestSenseLength; - ErrorCode = copy_to_user(&UserSpaceUserCommand->DataTransferLength, + if (copy_to_user(&UserSpaceUserCommand->DataTransferLength, &DataTransferResidue, - sizeof(DataTransferResidue)); - if (ErrorCode != 0) goto Failure2; - ErrorCode = copy_to_user(&UserSpaceUserCommand->RequestSenseLength, - &RequestSenseLength, - sizeof(RequestSenseLength)); - if (ErrorCode != 0) goto Failure2; + sizeof(DataTransferResidue))) { + ErrorCode = -EFAULT; + goto Failure2; + } + if (copy_to_user(&UserSpaceUserCommand->RequestSenseLength, + &RequestSenseLength, sizeof(RequestSenseLength))) { + ErrorCode = -EFAULT; + goto Failure2; + } if (DataTransferLength > 0) { - ErrorCode = copy_to_user(UserCommand.DataTransferBuffer, - DataTransferBuffer, DataTransferLength); - if (ErrorCode != 0) goto Failure2; + if (copy_to_user(UserCommand.DataTransferBuffer, + DataTransferBuffer, DataTransferLength)) { + ErrorCode = -EFAULT; + goto Failure2; + } } if (RequestSenseLength > 0) { - ErrorCode = copy_to_user(UserCommand.RequestSenseBuffer, - RequestSenseBuffer, RequestSenseLength); - if (ErrorCode != 0) goto Failure2; + if (copy_to_user(UserCommand.RequestSenseBuffer, + RequestSenseBuffer, RequestSenseLength)) { + ErrorCode = -EFAULT; + goto Failure2; + } } ErrorCode = CommandStatus; Failure2: @@ -5853,9 +5873,9 @@ DAC960_Controller_T *Controller; int ControllerNumber; if (UserSpaceGetHealthStatus == NULL) return -EINVAL; - ErrorCode = copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus, - sizeof(DAC960_V2_GetHealthStatus_T)); - if (ErrorCode != 0) return ErrorCode; + if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus, + sizeof(DAC960_V2_GetHealthStatus_T))) + return -EFAULT; ControllerNumber = GetHealthStatus.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) @@ -5863,10 +5883,10 @@ Controller = DAC960_Controllers[ControllerNumber]; if (Controller == NULL) return -ENXIO; if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL; - ErrorCode = copy_from_user(&HealthStatusBuffer, - GetHealthStatus.HealthStatusBuffer, - sizeof(DAC960_V2_HealthStatusBuffer_T)); - if (ErrorCode != 0) return ErrorCode; + if (copy_from_user(&HealthStatusBuffer, + GetHealthStatus.HealthStatusBuffer, + sizeof(DAC960_V2_HealthStatusBuffer_T))) + return -EFAULT; while (Controller->V2.HealthStatusBuffer->StatusChangeCounter == HealthStatusBuffer.StatusChangeCounter && Controller->V2.HealthStatusBuffer->NextEventSequenceNumber @@ -5876,10 +5896,11 @@ DAC960_MonitoringTimerInterval); if (signal_pending(current)) return -EINTR; } - ErrorCode = copy_to_user(GetHealthStatus.HealthStatusBuffer, - Controller->V2.HealthStatusBuffer, - sizeof(DAC960_V2_HealthStatusBuffer_T)); - return ErrorCode; + if (copy_to_user(GetHealthStatus.HealthStatusBuffer, + Controller->V2.HealthStatusBuffer, + sizeof(DAC960_V2_HealthStatusBuffer_T))) + return -EFAULT; + return 0; } } return -EINVAL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/genhd.c linux.20pre2-ac1/drivers/block/genhd.c --- linux.20pre2/drivers/block/genhd.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/genhd.c 2002-08-14 16:38:02.000000000 +0100 @@ -196,7 +196,7 @@ for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) { int mask = (1<minor_shift) - 1; - if (!(n & mask) || gp->part[n].nr_sects) { + if (gp->part[n].nr_sects) { struct hd_struct *hd = &gp->part[n]; #ifdef CONFIG_BLK_STATS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/ll_rw_blk.c linux.20pre2-ac1/drivers/block/ll_rw_blk.c --- linux.20pre2/drivers/block/ll_rw_blk.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/ll_rw_blk.c 2002-08-13 15:17:15.000000000 +0100 @@ -118,6 +118,13 @@ */ int * max_sectors[MAX_BLKDEV]; +/* + * blkdev_varyio indicates if variable size IO can be done on a device. + * + * Currently used for doing variable size IO on RAW devices. + */ +char * blkdev_varyio[MAX_BLKDEV]; + unsigned long blk_max_low_pfn, blk_max_pfn; int blk_nohighio = 0; @@ -1211,6 +1218,38 @@ } } +/* + * submit_bh_blknr() - same as submit_bh() except that b_rsector is + * set to b_blocknr. Used for RAW VARY. + */ +void submit_bh_blknr(int rw, struct buffer_head * bh) +{ + int count = bh->b_size >> 9; + + if (!test_bit(BH_Lock, &bh->b_state)) + BUG(); + + set_bit(BH_Req, &bh->b_state); + + /* + * First step, 'identity mapping' - RAID or LVM might + * further remap this. + */ + bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr; + + generic_make_request(rw, bh); + + switch (rw) { + case WRITE: + kstat.pgpgout += count; + break; + default: + kstat.pgpgin += count; + break; + } +} + /** * ll_rw_block: low-level access to block devices * @rw: whether to %READ or %WRITE or maybe %READA (readahead) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/loop.c linux.20pre2-ac1/drivers/block/loop.c --- linux.20pre2/drivers/block/loop.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/loop.c 2002-08-13 14:19:36.000000000 +0100 @@ -199,9 +199,9 @@ page = grab_cache_page(mapping, index); if (!page) goto fail; + kaddr = kmap(page); if (aops->prepare_write(file, page, offset, offset+size)) goto unlock; - kaddr = page_address(page); flush_dcache_page(page); transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV); if (transfer_result) { @@ -216,6 +216,7 @@ goto unlock; if (transfer_result) goto unlock; + kunmap(page); data += size; len -= size; offset = 0; @@ -228,6 +229,7 @@ return 0; unlock: + kunmap(page); UnlockPage(page); page_cache_release(page); fail: @@ -418,6 +420,7 @@ break; run_task_queue(&tq_disk); + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } while (1); memset(bh, 0, sizeof(*bh)); @@ -437,6 +440,7 @@ break; run_task_queue(&tq_disk); + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } while (1); @@ -563,6 +567,7 @@ daemonize(); exit_files(current); + reparent_to_init(); sprintf(current->comm, "loop%d", lo->lo_number); @@ -571,9 +576,6 @@ flush_signals(current); spin_unlock_irq(¤t->sigmask_lock); - current->policy = SCHED_OTHER; - current->nice = -20; - spin_lock_irq(&lo->lo_lock); lo->lo_state = Lo_bound; atomic_inc(&lo->lo_pending); @@ -645,7 +647,7 @@ lo_device = inode->i_rdev; if (lo_device == dev) { error = -EBUSY; - goto out; + goto out_putf; } } else if (S_ISREG(inode->i_mode)) { struct address_space_operations *aops = inode->i_mapping->a_ops; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/ps2esdi.c linux.20pre2-ac1/drivers/block/ps2esdi.c --- linux.20pre2/drivers/block/ps2esdi.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/ps2esdi.c 2002-08-12 21:57:28.000000000 +0100 @@ -466,7 +466,6 @@ u_int block, count; /* since, this routine is called with interrupts cleared - they must be before it finishes */ - sti(); #if 0 printk("%s:got request. device : %d minor : %d command : %d sector : %ld count : %ld, buffer: %p\n", @@ -563,6 +562,7 @@ u_short track, head, cylinder, sector; u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH]; + int err; /* do some relevant arithmatic */ track = block / ps2esdi_info[drive].sect; @@ -580,9 +580,13 @@ cylinder, head, sector, CURRENT->current_nr_sectors, drive); + spin_unlock_irq(&io_request_irq); /* send the command block to the controller */ - if (ps2esdi_out_cmd_blk(cmd_blk)) { - printk("%s: Controller failed\n", DEVICE_NAME); + err = ps2esdi_out_cmd_blk(cmd_blk); + spin_lock_irq(&io_request_irq); + + if (err) { + printk(KERN_ERR "%s: Controller failed\n", DEVICE_NAME); if ((++CURRENT->errors) >= MAX_RETRIES) end_request(FAIL); } @@ -1135,9 +1139,7 @@ int start = target << ps2esdi_gendisk.minor_shift; int partition; - cli(); ps2esdi_valid[target] = (access_count[target] != 1); - sti(); if (ps2esdi_valid[target]) return (-EBUSY); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/rd.c linux.20pre2-ac1/drivers/block/rd.c --- linux.20pre2/drivers/block/rd.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/rd.c 2002-08-06 15:42:07.000000000 +0100 @@ -217,7 +217,7 @@ bh_kunmap(sbh); if (rw == READ) { - flush_dcache_page(page); + flush_dcache_page(sbh->b_page); } else { SetPageDirty(page); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/xd.c linux.20pre2-ac1/drivers/block/xd.c --- linux.20pre2/drivers/block/xd.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/xd.c 2002-08-12 23:11:22.000000000 +0100 @@ -144,32 +144,40 @@ release: xd_release, ioctl: xd_ioctl, }; + static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open); -static u_char xd_valid[XD_MAXDRIVES] = { 0,0 }; -static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors; -static u_char xd_override __initdata = 0, xd_type __initdata = 0; -static u_short xd_iobase = 0x320; +static u8 xd_valid[XD_MAXDRIVES] = { 0,0 }; +static u8 xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors; +static u8 xd_override __initdata = 0, xd_type __initdata = 0; +static u16 xd_iobase = 0x320; static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0, }; static volatile int xdc_busy; -static DECLARE_WAIT_QUEUE_HEAD(xdc_wait); -static struct timer_list xd_timer, xd_watchdog_int; +static struct timer_list xd_watchdog_int; -static volatile u_char xd_error; +static volatile u8 xd_error; static int nodma = XD_DONT_USE_DMA; static devfs_handle_t devfs_handle = NULL; /* xd_init: register the block device number and set up pointer tables */ -int __init xd_init (void) +int __init xd_init(void) { - init_timer (&xd_timer); xd_timer.function = xd_wakeup; - init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog; + init_timer (&xd_watchdog_int); + xd_watchdog_int.function = xd_watchdog; + + if (!xd_dma_buffer) + xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200); + if (!xd_dma_buffer) + { + printk(KERN_ERR "xd: Out of memory.\n"); + return -ENOMEM; + } if (devfs_register_blkdev(MAJOR_NR,"xd",&xd_fops)) { - printk("xd: Unable to get major number %d\n",MAJOR_NR); + printk(KERN_ERR "xd: Unable to get major number %d\n",MAJOR_NR); return -1; } devfs_handle = devfs_mk_dir (NULL, xd_gendisk.major_name, NULL); @@ -182,9 +190,10 @@ } /* xd_detect: scan the possible BIOS ROM locations for the signature strings */ -static u_char __init xd_detect (u_char *controller, unsigned int *address) + +static u8 __init xd_detect (u8 *controller, unsigned int *address) { - u_char i,j,found = 0; + u8 i,j,found = 0; if (xd_override) { @@ -206,32 +215,32 @@ /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */ /* and set up the "raw" device entries in the table */ + static void __init xd_geninit (void) { - u_char i,controller; + u8 i,controller; unsigned int address; - for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024; + for(i=0;i<(XD_MAXDRIVES << 6);i++) + xd_blocksizes[i] = 1024; + blksize_size[MAJOR_NR] = xd_blocksizes; if (xd_detect(&controller,&address)) { - - printk("Detected a%s controller (type %d) at address %06x\n", + printk(KERN_INFO "Detected a%s controller (type %d) at address %06x\n", xd_sigs[controller].name,controller,address); - if (check_region(xd_iobase,4)) { - printk("xd: Ports at 0x%x are not available\n", - xd_iobase); + if (!request_region(xd_iobase,4, "xd")) { + printk(KERN_ERR "xd: Ports at 0x%x are not available\n", xd_iobase); return; } - request_region(xd_iobase,4,"xd"); if (controller) xd_sigs[controller].init_controller(address); xd_drives = xd_initdrives(xd_sigs[controller].init_drive); - printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n", + printk(KERN_INFO "Detected %d hard drive%s (using IRQ%d & DMA%d)\n", xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma); for (i = 0; i < xd_drives; i++) - printk(" xd%c: CHS=%d/%d/%d\n",'a'+i, + printk(KERN_INFO " xd%c: CHS=%d/%d/%d\n",'a'+i, xd_info[i].cylinders,xd_info[i].heads, xd_info[i].sectors); @@ -239,12 +248,12 @@ if (xd_drives) { if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) { if (request_dma(xd_dma,"xd")) { - printk("xd: unable to get DMA%d\n",xd_dma); + printk(KERN_ERR "xd: unable to get DMA%d\n",xd_dma); free_irq(xd_irq, NULL); } } else - printk("xd: unable to get IRQ%d\n",xd_irq); + printk(KERN_ERR "xd: unable to get IRQ%d\n",xd_irq); } /* xd_maxsectors depends on controller - so set after detection */ @@ -270,9 +279,7 @@ if (dev < xd_drives) { while (!xd_valid[dev]) sleep_on(&xd_wait_open); - xd_access[dev]++; - return (0); } @@ -282,18 +289,16 @@ /* do_xd_request: handle an incoming request */ static void do_xd_request (request_queue_t * q) { - u_int block,count,retry; + unsigned int block,count,retry; int code; - sti(); if (xdc_busy) return; + while (code = 0, !QUEUE_EMPTY) { INIT_REQUEST; /* do some checking on the request structure */ - if (CURRENT_DEV < xd_drives - && CURRENT->sector + CURRENT->nr_sectors - <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) { + if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) { block = CURRENT->sector + xd_struct[MINOR(CURRENT->rq_dev)].start_sect; count = CURRENT->nr_sectors; @@ -304,8 +309,7 @@ code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count); break; default: - printk("do_xd_request: unknown request\n"); - break; + BUG(); } } end_request(code); /* wrap up, 0 = fail, 1 = success */ @@ -313,7 +317,8 @@ } /* xd_ioctl: handle device ioctl's */ -static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) + +static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg) { int dev; @@ -327,7 +332,6 @@ { struct hd_geometry g; struct hd_geometry *geometry = (struct hd_geometry *) arg; - if (!geometry) return -EINVAL; g.heads = xd_info[dev].heads; g.sectors = xd_info[dev].sectors; g.cylinders = xd_info[dev].cylinders; @@ -335,12 +339,23 @@ return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } case HDIO_SET_DMA: - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (xdc_busy) return -EBUSY; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (xdc_busy) + return -EBUSY; + nodma = !arg; + if (nodma && xd_dma_buffer) { xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200); xd_dma_buffer = 0; + } else if (!nodma && !xd_dma_buffer) { + xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200); + if (!xd_dma_buffer) + { + nodma = XD_DONT_USE_DMA; + return -ENOMEM; + } } return 0; case HDIO_GET_DMA: @@ -351,7 +366,6 @@ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return xd_reread_partitions(inode->i_rdev); - case BLKGETSIZE: case BLKGETSIZE64: case BLKFLSBUF: @@ -361,7 +375,6 @@ case BLKRAGET: case BLKPG: return blk_ioctl(inode->i_rdev, cmd, arg); - default: return -EINVAL; } @@ -409,21 +422,20 @@ } /* xd_readwrite: handle a read/write request */ -static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count) +static int xd_readwrite (u8 operation,u8 drive,char *buffer,unsigned int block,unsigned int count) { - u_char cmdblk[6],sense[4]; - u_short track,cylinder; - u_char head,sector,control,mode = PIO_MODE,temp; + u8 cmdblk[6],sense[4]; + u16 track,cylinder; + u8 head,sector,control,mode = PIO_MODE,temp; char **real_buffer; - register int i; #ifdef DEBUG_READWRITE - printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count); + printk(KERN_DEBUG "xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count); #endif /* DEBUG_READWRITE */ + spin_unlock_irq(&io_request_lock); + control = xd_info[drive].control; - if (!xd_dma_buffer) - xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200); while (count) { temp = count < xd_maxsectors ? count : xd_maxsectors; @@ -433,28 +445,28 @@ sector = block % xd_info[drive].sectors; #ifdef DEBUG_READWRITE - printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp); + printk(KERN_DEBUG "xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp); #endif /* DEBUG_READWRITE */ if (xd_dma_buffer) { - mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200); + mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u8 *)(xd_dma_buffer),temp * 0x200); real_buffer = &xd_dma_buffer; - for (i=0; i < (temp * 0x200); i++) - xd_dma_buffer[i] = buffer[i]; + memcpy(xd_dma_buffer, buffer, temp * 0x200); } else real_buffer = &buffer; xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control); - switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) { + switch (xd_command(cmdblk,mode,(u8 *)(*real_buffer),(u8 *)(*real_buffer),sense,XD_TIMEOUT)) + { case 1: - printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write")); + printk(KERN_WARNING "xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write")); xd_recalibrate(drive); - return (0); + goto fail; case 2: if (sense[0] & 0x30) { - printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing")); + printk(KERN_ERR "xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing")); switch ((sense[0] & 0x30) >> 4) { case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F); break; @@ -471,25 +483,30 @@ /* reported drive number = (sense[1] & 0xE0) >> 5 */ else printk(" - no valid disk address\n"); - return (0); + goto fail; } if (xd_dma_buffer) - for (i=0; i < (temp * 0x200); i++) - buffer[i] = xd_dma_buffer[i]; + memcpy(buffer, xd_dma_buffer, (temp * 0x200)); count -= temp, buffer += temp * 0x200, block += temp; } - return (1); + spin_lock_irq(&io_request_lock); + return 1; + +fail: + spin_lock_irq(&io_request_lock); + return 0; + } /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */ -static void xd_recalibrate (u_char drive) +static void xd_recalibrate (u8 drive) { - u_char cmdblk[6]; + u8 cmdblk[6]; xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0); if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) - printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive); + printk(KERN_WARNING "xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive); } /* xd_interrupt_handler: interrupt service routine */ @@ -497,17 +514,17 @@ { if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */ #ifdef DEBUG_OTHER - printk("xd_interrupt_handler: interrupt detected\n"); + printk(KERN_DEBUG "xd_interrupt_handler: interrupt detected\n"); #endif /* DEBUG_OTHER */ outb(0,XD_CONTROL); /* acknowledge interrupt */ wake_up(&xd_wait_int); /* and wake up sleeping processes */ } else - printk("xd: unexpected interrupt\n"); + printk(KERN_DEBUG "xd: unexpected interrupt\n"); } /* xd_setup_dma: set up the DMA controller for a data transfer */ -static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count) +static u8 xd_setup_dma (u8 mode,u8 *buffer,unsigned int count) { unsigned long f; @@ -515,9 +532,9 @@ return (PIO_MODE); if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) { #ifdef DEBUG_OTHER - printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n"); + printk(KERN_DEBUG "xd_setup_dma: using PIO, transfer overlaps 64k boundary\n"); #endif /* DEBUG_OTHER */ - return (PIO_MODE); + return PIO_MODE; } f=claim_dma_lock(); @@ -529,11 +546,11 @@ release_dma_lock(f); - return (DMA_MODE); /* use DMA and INT */ + return DMA_MODE; /* use DMA and INT */ } /* xd_build: put stuff into an array in a format suitable for the controller */ -static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control) +static u8 *xd_build (u8 *cmdblk,u8 command,u8 drive,u8 head,u16 cylinder,u8 sector,u8 count,u8 control) { cmdblk[0] = command; cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F); @@ -542,13 +559,7 @@ cmdblk[4] = count; cmdblk[5] = control; - return (cmdblk); -} - -/* xd_wakeup is called from timer interrupt */ -static void xd_wakeup (unsigned long unused) -{ - wake_up(&xdc_wait); + return cmdblk; } /* xd_wakeup is called from timer interrupt */ @@ -559,25 +570,21 @@ } /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */ -static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout) +static inline u8 xd_waitport (u16 port,u8 flags,u8 mask,unsigned long timeout) { - u_long expiry = jiffies + timeout; + unsigned long expiry = jiffies + timeout; int success; xdc_busy = 1; while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry)) { - xd_timer.expires = jiffies; - cli(); - add_timer(&xd_timer); - sleep_on(&xdc_wait); - del_timer(&xd_timer); - sti(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); } xdc_busy = 0; return (success); } -static inline u_int xd_wait_for_IRQ (void) +static inline unsigned int xd_wait_for_IRQ (void) { unsigned long flags; xd_watchdog_int.expires = jiffies + 8 * HZ; @@ -588,7 +595,7 @@ release_dma_lock(flags); sleep_on(&xd_wait_int); - del_timer(&xd_watchdog_int); + del_timer_sync(&xd_watchdog_int); xdc_busy = 0; flags=claim_dma_lock(); @@ -596,7 +603,7 @@ release_dma_lock(flags); if (xd_error) { - printk("xd: missed IRQ - command aborted\n"); + printk(KERN_DEBUG "xd: missed IRQ - command aborted\n"); xd_error = 0; return (1); } @@ -604,12 +611,13 @@ } /* xd_command: handle all data transfers necessary for a single command */ -static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout) +static unsigned int xd_command (u8 *command,u8 mode,u8 *indata,u8 *outdata,u8 *sense,unsigned long timeout) { - u_char cmdblk[6],csb,complete = 0; + u8 cmdblk[6]; + u8 csb,complete = 0; #ifdef DEBUG_COMMAND - printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense); + printk(KERN_DEBUG "xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense); #endif /* DEBUG_COMMAND */ outb(0,XD_SELECT); @@ -656,55 +664,57 @@ if (csb & CSB_ERROR) { /* read sense data if error */ xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0); if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT)) - printk("xd: warning! sense command failed!\n"); + printk(KERN_DEBUG "xd: warning! sense command failed!\n"); } #ifdef DEBUG_COMMAND - printk("xd_command: completed with csb = 0x%X\n",csb); + printk(KERN_DEBUG "xd_command: completed with csb = 0x%X\n",csb); #endif /* DEBUG_COMMAND */ return (csb & CSB_ERROR); } -static u_char __init xd_initdrives (void (*init_drive)(u_char drive)) +static u8 __init xd_initdrives (void (*init_drive)(u8 drive)) { - u_char cmdblk[6],i,count = 0; + u8 cmdblk[6],i,count = 0; for (i = 0; i < XD_MAXDRIVES; i++) { xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0); if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) { - xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; - add_timer(&xd_timer); - sleep_on(&xdc_wait); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(XD_INIT_DISK_DELAY); init_drive(count); count++; - xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; - add_timer(&xd_timer); - sleep_on(&xdc_wait); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(XD_INIT_DISK_DELAY); } } return (count); } -static void __init xd_manual_geo_set (u_char drive) +static void __init xd_manual_geo_set (u8 drive) { - xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]); - xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]); - xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]); + xd_info[drive].heads = xd_geo[3 * drive + 1]; + xd_info[drive].cylinders= xd_geo[3 * drive]; + xd_info[drive].sectors = xd_geo[3 * drive + 2]; } static void __init xd_dtc_init_controller (unsigned int address) { switch (address) { case 0x00000: - case 0xC8000: break; /*initial: 0x320 */ - case 0xCA000: xd_iobase = 0x324; - case 0xD0000: /*5150CX*/ - case 0xD8000: break; /*5150CX & 5150XL*/ - default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address); - break; + case 0xC8000: + break; /*initial: 0x320 */ + case 0xCA000: + xd_iobase = 0x324; + case 0xD0000: /*5150CX*/ + case 0xD8000: + break; /*5150CX & 5150XL*/ + default: + printk(KERN_ERR "xd_dtc_init_controller: unsupported BIOS address %06x\n",address); + break; } xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */ @@ -712,10 +722,10 @@ } -static void __init xd_dtc5150cx_init_drive (u_char drive) +static void __init xd_dtc5150cx_init_drive (u8 drive) { /* values from controller's BIOS - BIOS chip may be removed */ - static u_short geometry_table[][4] = { + static u16 geometry_table[][4] = { {0x200,8,0x200,0x100}, {0x267,2,0x267,0x267}, {0x264,4,0x264,0x80}, @@ -732,7 +742,7 @@ {0x2B9,5,0x2B9,0x2B9}, {0x280,6,0x280,0x100}, {0x132,4,0x132,0x0}}; - u_char n; + u8 n; n = inb(XD_JUMPER); n = (drive ? n : (n >> 2)) & 0x33; @@ -741,7 +751,7 @@ xd_manual_geo_set(drive); else if (n != 7) { - xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */ + xd_info[drive].heads = (u8)(geometry_table[n][1]); /* heads */ xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */ #if 0 @@ -751,7 +761,7 @@ #endif /* 0 */ } else { - printk("xd%c: undetermined drive geometry\n",'a'+drive); + printk(KERN_WARNING "xd%c: undetermined drive geometry\n",'a'+drive); return; } xd_info[drive].control = 5; /* control byte */ @@ -759,31 +769,31 @@ xd_recalibrate(drive); } -static void __init xd_dtc_init_drive (u_char drive) +static void __init xd_dtc_init_drive (u8 drive) { - u_char cmdblk[6],buf[64]; + u8 cmdblk[6],buf[64]; xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0); if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { xd_info[drive].heads = buf[0x0A]; /* heads */ - xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */ + xd_info[drive].cylinders = ((u16 *) (buf))[0x04]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */ if (xd_geo[3*drive]) xd_manual_geo_set(drive); #if 0 - xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */ - xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */ + xd_info[drive].rwrite = ((u16 *) (buf + 1))[0x05]; /* reduced write */ + xd_info[drive].precomp = ((u16 *) (buf + 1))[0x06]; /* write precomp */ xd_info[drive].ecc = buf[0x0F]; /* ecc length */ #endif /* 0 */ xd_info[drive].control = 0; /* control byte */ - xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]); + xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u16 *) (buf + 1))[0x05],((u16 *) (buf + 1))[0x06],buf[0x0F]); xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7); if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) - printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive); + printk(KERN_WARNING "xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive); } else - printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive); + printk(KERN_WARNING "xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive); } static void __init xd_wd_init_controller (unsigned int address) @@ -796,22 +806,21 @@ case 0xCE000: xd_iobase = 0x32C; break; case 0xD0000: xd_iobase = 0x328; break; /* ? */ case 0xD8000: xd_iobase = 0x32C; break; /* ? */ - default: printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address); + default: printk(KERN_ERR "xd_wd_init_controller: unsupported BIOS address %06x\n",address); break; } xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */ outb(0,XD_RESET); /* reset the controller */ - xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; - add_timer(&xd_timer); - sleep_on(&xdc_wait); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(XD_INIT_DISK_DELAY); } -static void __init xd_wd_init_drive (u_char drive) +static void __init xd_wd_init_drive (u8 drive) { /* values from controller's BIOS - BIOS may be disabled */ - static u_short geometry_table[][4] = { + static u16 geometry_table[][4] = { {0x264,4,0x1C2,0x1C2}, /* common part */ {0x132,4,0x099,0x0}, {0x267,2,0x1C2,0x1C2}, @@ -827,9 +836,9 @@ {0x264,4,0x265,0x265}, {0x267,4,0x268,0x268}}; - u_char cmdblk[6],buf[0x200]; - u_char n = 0,rll,jumper_state,use_jumper_geo; - u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6'); + u8 cmdblk[6],buf[0x200]; + u8 n = 0,rll,jumper_state,use_jumper_geo; + u8 wd_1002 = (xd_sigs[xd_type].string[7] == '6'); jumper_state = ~(inb(0x322)); if (jumper_state & 0x40) @@ -838,13 +847,13 @@ xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0); if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { xd_info[drive].heads = buf[0x1AF]; /* heads */ - xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */ + xd_info[drive].cylinders = ((u16 *) (buf + 1))[0xD6]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */ if (xd_geo[3*drive]) xd_manual_geo_set(drive); #if 0 - xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */ - xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */ + xd_info[drive].rwrite = ((u16 *) (buf))[0xD8]; /* reduced write */ + xd_info[drive].wprecomp = ((u16 *) (buf))[0xDA]; /* write precomp */ xd_info[drive].ecc = buf[0x1B4]; /* ecc length */ #endif /* 0 */ xd_info[drive].control = buf[0x1B5]; /* control byte */ @@ -856,7 +865,7 @@ else if (use_jumper_geo) { n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll; xd_info[drive].cylinders = geometry_table[n][0]; - xd_info[drive].heads = (u_char)(geometry_table[n][1]); + xd_info[drive].heads = (u8)(geometry_table[n][1]); xd_info[drive].control = rll ? 7 : 5; #if 0 xd_info[drive].rwrite = geometry_table[n][2]; @@ -870,7 +879,7 @@ geometry_table[n][2],geometry_table[n][3],0x0B); else xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders, - ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]); + ((u16 *) (buf))[0xD8],((u16 *) (buf))[0xDA],buf[0x1B4]); } /* 1002 based RLL controller requests converted addressing, but reports physical (physical 26 sec., logical 17 sec.) @@ -888,7 +897,7 @@ } } else - printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive); + printk(KERN_WARNING "xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive); } @@ -900,7 +909,7 @@ case 0xD0000: xd_iobase = 0x324; break; case 0xD8000: xd_iobase = 0x328; break; case 0xE0000: xd_iobase = 0x32C; break; - default: printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address); + default: printk(KERN_ERR "xd_seagate_init_controller: unsupported BIOS address %06x\n",address); break; } xd_maxsectors = 0x40; @@ -908,9 +917,9 @@ outb(0,XD_RESET); /* reset the controller */ } -static void __init xd_seagate_init_drive (u_char drive) +static void __init xd_seagate_init_drive (u8 drive) { - u_char cmdblk[6],buf[0x200]; + u8 cmdblk[6],buf[0x200]; xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0); if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { @@ -920,7 +929,7 @@ xd_info[drive].control = 0; /* control byte */ } else - printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive); + printk(KERN_WARNING "xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive); } /* Omti support courtesy Dirk Melchers */ @@ -932,7 +941,7 @@ case 0xD0000: xd_iobase = 0x324; break; case 0xD8000: xd_iobase = 0x328; break; case 0xE0000: xd_iobase = 0x32C; break; - default: printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address); + default: printk(KERN_ERR "xd_omti_init_controller: unsupported BIOS address %06x\n",address); break; } @@ -941,7 +950,7 @@ outb(0,XD_RESET); /* reset the controller */ } -static void __init xd_omti_init_drive (u_char drive) +static void __init xd_omti_init_drive (u8 drive) { /* gets infos from drive */ xd_override_init_drive(drive); @@ -972,22 +981,21 @@ case 0xDC000: case 0xDE000: case 0xE0000: break; - default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address); + default: printk(KERN_ERR "xd_xebec_init_controller: unsupported BIOS address %06x\n",address); break; } xd_maxsectors = 0x01; outb(0,XD_RESET); /* reset the controller */ - xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; - add_timer(&xd_timer); - sleep_on(&xdc_wait); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(XD_INIT_DISK_DELAY); } -static void __init xd_xebec_init_drive (u_char drive) +static void __init xd_xebec_init_drive (u8 drive) { /* values from controller's BIOS - BIOS chip may be removed */ - static u_short geometry_table[][5] = { + static u16 geometry_table[][5] = { {0x132,4,0x080,0x080,0x7}, {0x132,4,0x080,0x080,0x17}, {0x264,2,0x100,0x100,0x7}, @@ -1004,14 +1012,14 @@ {0x400,6,0x400,0x400,0x7}, {0x264,8,0x264,0x200,0x17}, {0x33E,7,0x33E,0x200,0x7}}; - u_char n; + u8 n; n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry is assumed for BOTH drives */ if (xd_geo[3*drive]) xd_manual_geo_set(drive); else { - xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */ + xd_info[drive].heads = (u8)(geometry_table[n][1]); /* heads */ xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */ #if 0 @@ -1027,10 +1035,10 @@ /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */ -static void __init xd_override_init_drive (u_char drive) +static void __init xd_override_init_drive (u8 drive) { - u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 }; - u_char cmdblk[6],i; + u16 min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 }; + u8 cmdblk[6],i; if (xd_geo[3*drive]) xd_manual_geo_set(drive); @@ -1038,7 +1046,7 @@ for (i = 0; i < 3; i++) { while (min[i] != max[i] - 1) { test[i] = (min[i] + max[i]) / 2; - xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0); + xd_build(cmdblk,CMD_SEEK,drive,(u8) test[0],(u16) test[1],(u8) test[2],0,0); if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) min[i] = test[i]; else @@ -1046,9 +1054,9 @@ } test[i] = min[i]; } - xd_info[drive].heads = (u_char) min[0] + 1; - xd_info[drive].cylinders = (u_short) min[1] + 1; - xd_info[drive].sectors = (u_char) min[2] + 1; + xd_info[drive].heads = (u8) min[0] + 1; + xd_info[drive].cylinders = (u16) min[1] + 1; + xd_info[drive].sectors = (u8) min[2] + 1; } xd_info[drive].control = 0; } @@ -1069,30 +1077,30 @@ if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0])))) xd_type = integers[1]; case 0: break; - default:printk("xd: too many parameters for xd\n"); + default:printk(KERN_ERR "xd: too many parameters for xd\n"); } xd_maxsectors = 0x01; } /* xd_setparam: set the drive characteristics */ -static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc) +static void __init xd_setparam (u8 command,u8 drive,u8 heads,u16 cylinders,u16 rwrite,u16 wprecomp,u8 ecc) { - u_char cmdblk[14]; + u8 cmdblk[14]; xd_build(cmdblk,command,drive,0,0,0,0,0); - cmdblk[6] = (u_char) (cylinders >> 8) & 0x03; - cmdblk[7] = (u_char) (cylinders & 0xFF); + cmdblk[6] = (u8) (cylinders >> 8) & 0x03; + cmdblk[7] = (u8) (cylinders & 0xFF); cmdblk[8] = heads & 0x1F; - cmdblk[9] = (u_char) (rwrite >> 8) & 0x03; - cmdblk[10] = (u_char) (rwrite & 0xFF); - cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03; - cmdblk[12] = (u_char) (wprecomp & 0xFF); + cmdblk[9] = (u8) (rwrite >> 8) & 0x03; + cmdblk[10] = (u8) (rwrite & 0xFF); + cmdblk[11] = (u8) (wprecomp >> 8) & 0x03; + cmdblk[12] = (u8) (wprecomp & 0xFF); cmdblk[13] = ecc; /* Some controllers require geometry info as data, not command */ if (xd_command(cmdblk,PIO_MODE,0,&cmdblk[6],0,XD_TIMEOUT * 2)) - printk("xd: error setting characteristics for xd%c\n", 'a'+drive); + printk(KERN_WARNING "xd: error setting characteristics for xd%c\n", 'a'+drive); } @@ -1145,7 +1153,7 @@ { devfs_unregister_blkdev(MAJOR_NR, "xd"); xd_done(); - devfs_unregister (devfs_handle); + devfs_unregister(devfs_handle); if (xd_drives) { free_irq(xd_irq, NULL); free_dma(xd_dma); @@ -1171,7 +1179,7 @@ get_options (str, ARRAY_SIZE (integers), integers); if (integers[0]%3 != 0) { - printk("xd: incorrect number of parameters for xd_geo\n"); + printk(KERN_ERR "xd: incorrect number of parameters for xd_geo\n"); return 1; } for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/block/xd.h linux.20pre2-ac1/drivers/block/xd.h --- linux.20pre2/drivers/block/xd.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/block/xd.h 2002-08-12 23:02:27.000000000 +0100 @@ -80,10 +80,10 @@ /* this structure defines the XT drives and their types */ typedef struct { - u_char heads; - u_short cylinders; - u_char sectors; - u_char control; + u8 heads; + u16 cylinders; + u8 sectors; + u8 control; } XD_INFO; /* this structure is returned to the HDIO_GETGEO ioctl */ @@ -99,15 +99,15 @@ unsigned int offset; const char *string; void (*init_controller)(unsigned int address); - void (*init_drive)(u_char drive); + void (*init_drive)(u8 drive); const char *name; } XD_SIGNATURE; #ifndef MODULE static int xd_manual_geo_init (char *command); #endif /* MODULE */ -static u_char xd_detect (u_char *controller, unsigned int *address); -static u_char xd_initdrives (void (*init_drive)(u_char drive)); +static u8 xd_detect (u8 *controller, unsigned int *address); +static u8 xd_initdrives (void (*init_drive)(u8 drive)); static void xd_geninit (void); static int xd_open (struct inode *inode,struct file *file); @@ -115,30 +115,29 @@ static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg); static int xd_release (struct inode *inode,struct file *file); static int xd_reread_partitions (kdev_t dev); -static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count); -static void xd_recalibrate (u_char drive); +static int xd_readwrite (u8 operation,u8 drive,char *buffer,u_int block,u_int count); +static void xd_recalibrate (u8 drive); static void xd_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs); -static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count); -static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control); -static void xd_wakeup (unsigned long unused); +static u8 xd_setup_dma (u8 opcode,u8 *buffer,u_int count); +static u8 *xd_build (u8 *cmdblk,u8 command,u8 drive,u8 head,u16 cylinder,u8 sector,u8 count,u8 control); static void xd_watchdog (unsigned long unused); -static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout); -static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout); +static inline u8 xd_waitport (u16 port,u8 flags,u8 mask,unsigned long timeout); +static u_int xd_command (u8 *command,u8 mode,u8 *indata,u8 *outdata,u8 *sense,unsigned long timeout); /* card specific setup and geometry gathering code */ static void xd_dtc_init_controller (unsigned int address); -static void xd_dtc5150cx_init_drive (u_char drive); -static void xd_dtc_init_drive (u_char drive); +static void xd_dtc5150cx_init_drive (u8 drive); +static void xd_dtc_init_drive (u8 drive); static void xd_wd_init_controller (unsigned int address); -static void xd_wd_init_drive (u_char drive); +static void xd_wd_init_drive (u8 drive); static void xd_seagate_init_controller (unsigned int address); -static void xd_seagate_init_drive (u_char drive); +static void xd_seagate_init_drive (u8 drive); static void xd_omti_init_controller (unsigned int address); -static void xd_omti_init_drive (u_char drive); +static void xd_omti_init_drive (u8 drive); static void xd_xebec_init_controller (unsigned int address); -static void xd_xebec_init_drive (u_char drive); -static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc); -static void xd_override_init_drive (u_char drive); +static void xd_xebec_init_drive (u8 drive); +static void xd_setparam (u8 command,u8 drive,u8 heads,u16 cylinders,u16 rwrite,u16 wprecomp,u8 ecc); +static void xd_override_init_drive (u8 drive); #endif /* _LINUX_XD_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/alim1535d_wdt.c linux.20pre2-ac1/drivers/char/alim1535d_wdt.c --- linux.20pre2/drivers/char/alim1535d_wdt.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/alim1535d_wdt.c 2002-08-12 14:58:07.000000000 +0100 @@ -0,0 +1,356 @@ +/* + * Watchdog for the 7101 PMU version found in the ALi1535 chipsets + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static spinlock_t ali_lock; /* Guards the hardware */ + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static unsigned long timer_alive; +static char ali_expect_close; +static u32 ali_timeout = 60; /* 60 seconds */ +static u32 ali_timeout_bits = 1 | (1<<7); /* 1 count in minutes */ + +static struct pci_dev *ali_pci; + +/** + * ali_timer_start - start watchdog countdown + * @dev: PCI device of the PMU + * + * Starts the timer running providing the timer has a counter + * configuration set. + */ + +static void ali_timer_start(struct pci_dev *pdev) +{ + u32 val; + + spin_lock(&ali_lock); + + pci_read_config_dword(pdev, 0xCC, &val); + val &= ~0x3F; /* Mask count */ + val |= (1<<25) | ali_timeout_bits; + pci_write_config_dword(pdev, 0xCC, val); + spin_unlock(&ali_lock); +} + +/** + * ali_timer_stop - stop the timer countdown + * @pdev: PCI device of the PMU + * + * Stop the ALi watchdog countdown + */ + +static void ali_timer_stop (struct pci_dev *pdev) +{ + u32 val; + + spin_lock(&ali_lock); + pci_read_config_dword(pdev, 0xCC, &val); + val &= ~0x3F; /* Mask count to zero (disabled) */ + val &= ~(1<<25);/* and for safety mask the reset enable */ + pci_write_config_dword(pdev, 0xCC, val); + spin_unlock(&ali_lock); +} + +/** + * ali_timer_settimer - compute the timer reload value + * @pdev: PCI device of the PMU + * @t: time in seconds + * + * Computes the timeout values needed and then restarts the timer + * running with the new timeout values + */ + +static int ali_timer_settimer(struct pci_dev *pdev, unsigned long t) +{ + if(t < 60) + ali_timeout_bits = t|(1<<6); + else if(t < 3600) + ali_timeout_bits = (t/60)|(1<<7); + else if(t < 18000) + ali_timeout_bits = (t/300)|(1<<6)|(1<<7); + else return -EINVAL; + + ali_timeout = t; + ali_timer_start(pdev); + return 0; +} + +/** + * ali_open - handle open of ali watchdog + * @inode: inode from VFS + * @file: file from VFS + * + * Open the ALi watchdog device. Ensure only one person opens it + * at a time. Also start the watchdog running. + */ + +static int ali_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &timer_alive)) + return -EBUSY; + ali_timer_start (ali_pci); + return 0; +} + +/** + * ali_release - close an ALi watchdog + * @inode: inode from VFS + * @file: file from VFS + * + * Close the ALi watchdog device. Actual shutdown of the timer + * only occurs if the magic sequence has been set or nowayout is + * disabled + */ + +static int ali_release (struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + */ + if (ali_expect_close == 42 && !nowayout) { + ali_timer_stop(ali_pci); + } else { + ali_timer_start(ali_pci); + printk(KERN_CRIT "ali1535_wdt: Unexpected close, not stopping watchdog!\n"); + } + clear_bit(0, &timer_alive); + ali_expect_close = 0; + return 0; +} + +/** + * ali_write - writes to ALi watchdog + * @file: file from VFS + * @data: user address of data + * @len: length of data + * @ppos: pointer to the file offset + * + * Handle a write to the ALi watchdog. Writing to the file pings + * the watchdog and resets it. Writing the magic 'V' sequence allows + * the next close to turn off the watchdog. + */ + +static ssize_t ali_write (struct file *file, const char *data, + size_t len, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + size_t i; + + ali_expect_close = 0; + + /* scan to see wether or not we got the magic character */ + for (i = 0; i != len; i++) { + u8 c; + if(get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + ali_expect_close = 42; + } + + /* someone wrote to us, we should reload the timer */ + ali_timer_start(ali_pci); + return 1; + } + return 0; +} + +/** + * ali_ioctl - handle watchdog ioctls + * @inode: VFS inode + * @file: VFS file pointer + * @cmd: ioctl number + * @arg: arguments to the ioctl + * + * Handle the watchdog ioctls supported by the ALi driver. Really + * we want an extension to enable irq ack monitoring and the like + */ + +static int ali_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int options, retval = -EINVAL; + u32 t; + static struct watchdog_info ident = { + options: WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + firmware_version: 0, + identity: "ALi 1535D+ TCO timer", + }; + switch (cmd) { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *) arg, &ident, sizeof (ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *) arg); + case WDIOC_SETOPTIONS: + if (get_user (options, (int *) arg)) + return -EFAULT; + if (options & WDIOS_DISABLECARD) { + ali_timer_stop(ali_pci); + retval = 0; + } + if (options & WDIOS_ENABLECARD) { + ali_timer_start(ali_pci); + retval = 0; + } + return retval; + case WDIOC_KEEPALIVE: + ali_timer_start(ali_pci); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(t, (int *) arg)) + return -EFAULT; + if (ali_timer_settimer(ali_pci, t)) + return -EINVAL; + ali_timer_start(ali_pci); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(ali_timeout, (int *)arg); + } +} + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ + +static struct pci_device_id ali_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_AL, 1535, PCI_ANY_ID, PCI_ANY_ID,}, + { 0, }, +}; +MODULE_DEVICE_TABLE (pci, ali_pci_tbl); + + +/** + * ali_find_watchdog - find a 1535 and 7101 + * + * Scans the PCI hardware for a 1535 series bridge and matching 7101 + * watchdog device. This may be overtight but it is better to be safe + */ + +static int __init ali_find_watchdog(void) +{ + struct pci_dev *pdev; + u32 wdog; + + /* Check for a 1535 series bridge */ + pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL); + if(pdev == NULL) + return -ENODEV; + + /* Check for the a 7101 PMU */ + pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL); + if(pdev == NULL) + return -ENODEV; + + if(pci_enable_device(pdev)) + return -EIO; + + ali_pci = pdev; + + /* + * Initialize the timer bits + */ + + pci_read_config_dword(pdev, 0xCC, &wdog); + + wdog &= ~0x3F; /* Timer bits */ + wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24)); /* Issued events */ + wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)); /* No monitor bits */ + + pci_write_config_dword(pdev, 0xCC, wdog); + return 0; +} + +static struct file_operations ali_fops = { + owner: THIS_MODULE, + write: ali_write, + ioctl: ali_ioctl, + open: ali_open, + release: ali_release, +}; + +static struct miscdevice ali_miscdev = { + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &ali_fops, +}; + +/** + * watchdog_init - module initialiser + * + * Scan for a suitable watchdog and if so initialize it. Return an error + * if we cannot, the error causes the module to unload + */ + +static int __init watchdog_init (void) +{ + spin_lock_init(&ali_lock); + if (!ali_find_watchdog()) + return -ENODEV; + if (misc_register (&ali_miscdev) != 0) { + printk (KERN_ERR "alim1535d: cannot register watchdog device node.\n"); + return -EIO; + } + return 0; +} + +/** + * watchdog_cleanup - unload watchdog + * + * Called on the unload of a successfully installed watchdog module. + */ + +static void __exit watchdog_cleanup (void) +{ + ali_timer_stop(ali_pci); + misc_deregister (&ali_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_cleanup); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("Watchdog driver for the ALi 1535+ PMU"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/amd76x_pm.c linux.20pre2-ac1/drivers/char/amd76x_pm.c --- linux.20pre2/drivers/char/amd76x_pm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/amd76x_pm.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,688 @@ +/* + * ACPI sytle PM for SMP AMD-760MP(X) based systems. + * For use until the ACPI project catches up. :-) + * + * Copyright (C) 2002 Johnathan Hicks + * + * History: + * + * 20020702 - amd-smp-idle: Tony Lindgren + * Influenced by Vcool, and LVCool. Rewrote everything from scratch to + * use the PCI features in Linux, and to support SMP systems. Provides + * C2 idling on SMP AMD-760MP systems. + * + * 20020722: JH + * I adapted Tony's code for the AMD-765/766 southbridge and adapted it + * according to the AMD-768 data sheet to provide the same capability for + * SMP AMD-760MPX systems. Posted to acpi-devel list. + * + * 20020722: Alan Cox + * Replaces non-functional amd76x_pm code in -ac tree. + * + * 20020730: JH + * Added ability to do normal throttling (the non-thermal kind), C3 idling + * and Power On Suspend (S1 sleep). It would be very easy to tie swsusp + * into activate_amd76x_SLP(). C3 idling doesn't happen yet; see my note + * in amd76x_smp_idle(). I've noticed that when NTH and idling are both + * enabled, my hardware locks and requires a hard reset, so I have + * #ifndefed around the idle loop setting to prevent this. POS locks it up + * too, both ought to be fixable. I've also noticed that idling and NTH + * make some interference that is picked up by the onboard sound chip on + * my ASUS A7M266-D motherboard. + * + * + * TODO: Thermal throttling (TTH). + * /proc interface for normal throttling level. + * /proc interface for POS. + * + * + * + * + * Processor idle mode module for AMD SMP 760MP(X) based systems + * + * Copyright (C) 2002 Tony Lindgren + * Johnathan Hicks (768 support) + * + * Using this module saves about 70 - 90W of energy in the idle mode compared + * to the default idle mode. Waking up from the idle mode is fast to keep the + * system response time good. Currently no CPU load calculation is done, the + * system exits the idle mode if the idle function runs twice on the same + * processor in a row. This only works on SMP systems, but maybe the idle mode + * enabling can be integrated to ACPI to provide C2 mode at some point. + * + * NOTE: Currently there's a bug somewhere where the reading the + * P_LVL2 for the first time causes the system to sleep instead of + * idling. This means that you need to hit the power button once to + * wake the system after loading the module for the first time after + * reboot. After that the system idles as supposed. + * + * + * Influenced by Vcool, and LVCool. Rewrote everything from scratch to + * use the PCI features in Linux, and to support SMP systems. + * + * Currently only tested on a TYAN S2460 (760MP) system (Tony) and an + * ASUS A7M266-D (760MPX) system (Johnathan). Adding support for other Athlon + * SMP or single processor systems should be easy if desired. + * + * This software is licensed under GNU General Public License Version 2 + * as specified in file COPYING in the Linux kernel source tree main + * directory. + * + * + */ + + +#include +#include +#include +#include +#include +#include + +#include "amd76x_pm.h" + +#define VERSION "20020730" + +// #define AMD76X_C3 1 +// #define AMD76X_NTH 1 +// #define AMD76X_POS 1 + + +extern void default_idle(void); +static void amd76x_smp_idle(void); +static int amd76x_pm_main(void); +static int __devinit amd_nb_init(struct pci_dev *pdev, + const struct pci_device_id *ent); +static void amd_nb_remove(struct pci_dev *pdev); +static int __devinit amd_sb_init(struct pci_dev *pdev, + const struct pci_device_id *ent); +static void amd_sb_remove(struct pci_dev *pdev); + + +static struct pci_dev *pdev_nb; +static struct pci_dev *pdev_sb; + +struct PM_cfg { + unsigned int status_reg; + unsigned int C2_reg; + unsigned int C3_reg; + unsigned int NTH_reg; + unsigned int slp_reg; + unsigned int resume_reg; + void (*orig_idle) (void); + void (*curr_idle) (void); + unsigned long C2_cnt, C3_cnt; + int last_pr; +}; +static struct PM_cfg amd76x_pm_cfg; + +struct cpu_idle_state { + int idle; + int count; +}; +static struct cpu_idle_state prs[2]; + +static struct pci_device_id amd_nb_tbl[] __devinitdata = { + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, PCI_ANY_ID, PCI_ANY_ID,}, + {0,} +}; + +static struct pci_device_id amd_sb_tbl[] __devinitdata = { + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443, PCI_ANY_ID, PCI_ANY_ID,}, + {0,} +}; + +static struct pci_driver amd_nb_driver = { + name:"amd76x_pm-nb", + id_table:amd_nb_tbl, + probe:amd_nb_init, + remove:__devexit_p(amd_nb_remove), +}; + +static struct pci_driver amd_sb_driver = { + name:"amd76x_pm-sb", + id_table:amd_sb_tbl, + probe:amd_sb_init, + remove:__devexit_p(amd_sb_remove), +}; + + +static int __devinit +amd_nb_init(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + pdev_nb = pdev; + printk(KERN_INFO "amd76x_pm: Initializing northbridge %s\n", + pdev_nb->name); + + return 0; +} + + +static void __devexit +amd_nb_remove(struct pci_dev *pdev) +{ +} + + +static int __devinit +amd_sb_init(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + pdev_sb = pdev; + printk(KERN_INFO "amd76x_pm: Initializing southbridge %s\n", + pdev_sb->name); + + return 0; +} + + +static void __devexit +amd_sb_remove(struct pci_dev *pdev) +{ +} + + +/* + * Configures the AMD-762 northbridge to support PM calls + */ +static int +config_amd762(int enable) +{ + unsigned int regdword; + + /* Enable STPGNT in BIU Status/Control for cpu0 */ + pci_read_config_dword(pdev_nb, 0x60, ®dword); + regdword |= (1 << 17); + pci_write_config_dword(pdev_nb, 0x60, regdword); + + /* Enable STPGNT in BIU Status/Control for cpu1 */ + pci_read_config_dword(pdev_nb, 0x68, ®dword); + regdword |= (1 << 17); + pci_write_config_dword(pdev_nb, 0x68, regdword); + + /* DRAM refresh enable */ + pci_read_config_dword(pdev_nb, 0x58, ®dword); + regdword &= ~(1 << 19); + pci_write_config_dword(pdev_nb, 0x58, regdword); + + /* Self refresh enable */ + pci_read_config_dword(pdev_nb, 0x70, ®dword); + regdword |= (1 << 18); + pci_write_config_dword(pdev_nb, 0x70, regdword); + + return 0; +} + + +/* + * Get the base PMIO address and set the pm registers in amd76x_pm_cfg. + */ +static void +amd76x_get_PM(void) +{ + unsigned int regdword; + + /* Get the address for pm status, P_LVL2, etc */ + pci_read_config_dword(pdev_sb, 0x58, ®dword); + regdword &= 0xff80; + amd76x_pm_cfg.status_reg = (regdword + 0x00); + amd76x_pm_cfg.slp_reg = (regdword + 0x04); + amd76x_pm_cfg.NTH_reg = (regdword + 0x10); + amd76x_pm_cfg.C2_reg = (regdword + 0x14); + amd76x_pm_cfg.C3_reg = (regdword + 0x15); + amd76x_pm_cfg.resume_reg = (regdword + 0x16); /* N/A for 768 */ +} + + +/* + * En/Disable PMIO and configure W4SG & STPGNT. + */ +static int +config_PMIO_amd76x(int is_766, int enable) +{ + unsigned char regbyte; + + /* Clear W4SG, and set PMIOEN, if using a 765/766 set STPGNT as well. + * AMD-766: C3A41; page 59 in AMD-766 doc + * AMD-768: DevB:3x41C; page 94 in AMD-768 doc */ + pci_read_config_byte(pdev_sb, 0x41, ®byte); + if(enable) { + regbyte |= ((0 << 0) | (is_766?1:0 << 1) | (1 << 7)); + } + else { + regbyte |= (0 << 7); + } + pci_write_config_byte(pdev_sb, 0x41, regbyte); + + return 0; +} + +/* + * C2 idle support for AMD-766. + */ +static void +config_amd766_C2(int enable) +{ + unsigned int regdword; + + /* Set C2 options in C3A50, page 63 in AMD-766 doc */ + pci_read_config_dword(pdev_sb, 0x50, ®dword); + if(enable) { + regdword &= ~((DCSTOP_EN | CPUSTP_EN | PCISTP_EN | SUSPND_EN | + CPURST_EN) << C2_REGS); + regdword |= (STPCLK_EN /* ~ 20 Watt savings max */ + | CPUSLP_EN) /* Additional ~ 70 Watts max! */ + << C2_REGS; + } + else + regdword &= ~((STPCLK_EN | CPUSLP_EN) << C2_REGS); + pci_write_config_dword(pdev_sb, 0x50, regdword); +} + + +#ifdef AMD76X_C3 +/* + * Untested C3 idle support for AMD-766. + */ +static void +config_amd766_C3(int enable) +{ + unsigned int regdword; + + /* Set C3 options in C3A50, page 63 in AMD-766 doc */ + pci_read_config_dword(pdev_sb, 0x50, ®dword); + if(enable) { + regdword &= ~((DCSTOP_EN | PCISTP_EN | SUSPND_EN | CPURST_EN) + << C3_REGS); + regdword |= (STPCLK_EN /* ~ 20 Watt savings max */ + | CPUSLP_EN /* Additional ~ 70 Watts max! */ + | CPUSTP_EN) /* yet more savings! */ + << C3_REGS; + } + else + regdword &= ~((STPCLK_EN | CPUSLP_EN | CPUSTP_EN) << C3_REGS); + pci_write_config_dword(pdev_sb, 0x50, regdword); +} +#endif + + +#ifdef AMD76X_POS +static void +config_amd766_POS(int enable) +{ + unsigned int regdword; + + /* Set C3 options in C3A50, page 63 in AMD-766 doc */ + pci_read_config_dword(pdev_sb, 0x50, ®dword); + if(enable) { + regdword &= ~((ZZ_CACHE_EN | CPURST_EN) << POS_REGS); + regdword |= ((DCSTOP_EN | STPCLK_EN | CPUSTP_EN | PCISTP_EN | + CPUSLP_EN | SUSPND_EN) << POS_REGS); + } + else + regdword ^= (0xff << POS_REGS); + pci_write_config_dword(pdev_sb, 0x50, regdword); +} +#endif + + +/* + * Configures the 765 & 766 southbridges. + */ +static int +config_amd766(int enable) +{ + amd76x_get_PM(); + config_PMIO_amd76x(1, 1); + + config_amd766_C2(enable); +#ifdef AMD76X_C3 + config_amd766_C3(enable); +#endif +#ifdef AMD76X_POS + config_amd766_POS(enable); +#endif + + return 0; +} + + +/* + * C2 idling support for AMD-768. + */ +static void +config_amd768_C2(int enable) +{ + unsigned char regbyte; + + /* Set C2 options in DevB:3x4F, page 100 in AMD-768 doc */ + pci_read_config_byte(pdev_sb, 0x4F, ®byte); + if(enable) + regbyte |= C2EN; + else + regbyte ^= C2EN; + pci_write_config_byte(pdev_sb, 0x4F, regbyte); +} + + +#ifdef AMD76X_C3 +/* + * C3 idle support for AMD-768. The idle loop would need some extra + * handling for C3, but it would make more sense for ACPI to handle CX level + * transitions like it is supposed to. Unfortunately ACPI doesn't do CX + * levels on SMP systems yet. + */ +static void +config_amd768_C3(int enable) +{ + unsigned char regbyte; + + /* Set C3 options in DevB:3x4F, page 100 in AMD-768 doc */ + pci_read_config_byte(pdev_sb, 0x4F, ®byte); + if(enable) + regbyte |= (C3EN /* | ZZ_C3EN | CSLP_C3EN | CSTP_C3EN */); + else + regbyte ^= C3EN; + pci_write_config_byte(pdev_sb, 0x4F, regbyte); +} +#endif + + +#ifdef AMD76X_POS +/* + * Untested Power On Suspend support for AMD-768. This should also be handled + * by ACPI. + */ +static void +config_amd768_POS(int enable) +{ + unsigned int regdword; + + /* Set POS options in DevB:3x50, page 101 in AMD-768 doc */ + pci_read_config_dword(pdev_sb, 0x50, ®dword); + if(enable) + regdword |= (POSEN | CSTP | PSTP | ASTP | DCSTP | CSLP | SUSP); + else + regdword ^= POSEN; + pci_write_config_dword(pdev_sb, 0x50, regdword); +} +#endif + + +#ifdef AMD76X_NTH +/* + * Normal Throttling support for AMD-768. There are several settings + * that can be set depending on how long you want some of the delays to be. + * I'm not sure if this is even neccessary at all as the 766 doesn't need this. + */ +static void +config_amd768_NTH(int enable, int ntper, int thminen) +{ + unsigned char regbyte; + + /* DevB:3x40, pg 93 of 768 doc */ + pci_read_config_byte(pdev_sb, 0x40, ®byte); + /* Is it neccessary to use THMINEN at ANY time? */ + regbyte |= (NTPER(ntper) | THMINEN(thminen)); + pci_write_config_byte(pdev_sb, 0x40, regbyte); +} +#endif + + +/* + * Configures the 768 southbridge to support idle calls, and gets + * the processor idle call register location. + */ +static int +config_amd768(int enable) +{ + amd76x_get_PM(); + config_PMIO_amd76x(0, 1); + + config_amd768_C2(enable); +#ifdef AMD76X_C3 + config_amd768_C3(enable); +#endif +#ifdef AMD76X_POS + config_amd768_POS(enable); +#endif +#ifdef AMD76X_NTH + config_amd768_NTH(enable, 1, 2); +#endif + + return 0; +} + + +#ifdef AMD76X_NTH +/* + * Activate normal throttling via its ACPI register (P_CNT). + */ +static void +activate_amd76x_NTH(int enable, int ratio) +{ + unsigned int regdword; + + /* PM10, pg 110 of 768 doc, pg 70 of 766 doc */ + regdword=inl(amd76x_pm_cfg.NTH_reg); + if(enable) + regdword |= (NTH_EN | NTH_RATIO(ratio)); + else + regdword ^= NTH_EN; + outl(regdword, amd76x_pm_cfg.NTH_reg); +} +#endif + + +/* + * Activate sleep state via its ACPI register (PM1_CNT). + */ +static void +activate_amd76x_SLP(int type) +{ + unsigned short regshort; + + /* PM04, pg 109 of 768 doc, pg 69 of 766 doc */ + regshort=inw(amd76x_pm_cfg.slp_reg); + regshort |= (SLP_EN | SLP_TYP(type)) ; + outw(regshort, amd76x_pm_cfg.slp_reg); +} + + +#ifdef AMD76X_POS +/* + * Wrapper function to activate POS sleep state. + */ +static void +activate_amd76x_POS(void) +{ + activate_amd76x_SLP(1); +} +#endif + + +#if 0 +/* + * Idle loop for single processor systems + */ +void +amd76x_up_idle(void) +{ + // FIXME: Optionally add non-smp idle loop here +} +#endif + + +/* + * Idle loop for SMP systems, supports currently only 2 processors. + * + * Note; for 2.5 folks - not pre-empt safe + */ +static void +amd76x_smp_idle(void) +{ + + /* + * Exit idle mode immediately if the CPU does not change. + * Usually that means that we have some load on another CPU. + */ + if (prs[0].idle && prs[1].idle && amd76x_pm_cfg.last_pr == smp_processor_id()) { + prs[0].idle = 0; + prs[1].idle = 0; + /* This looks redundent as it was just checked in the if() */ + /* amd76x_pm_cfg.last_pr = smp_processor_id(); */ + return; + } + + prs[smp_processor_id()].count++; + + /* Don't start the idle mode immediately */ + if (prs[smp_processor_id()].count >= LAZY_IDLE_DELAY) { + + /* Put the current processor into idle mode */ + prs[smp_processor_id()].idle = + (prs[smp_processor_id()].idle ? 2 : 1); + + /* Only idle if both processors are idle */ + if ((prs[0].idle==1) && (prs[1].idle==1)) { + amd76x_pm_cfg.C2_cnt++; + inb(amd76x_pm_cfg.C2_reg); + } + #ifdef AMD76X_C3 + /* + * JH: I've not been able to get into here. Could this have + * something to do with the way the kernel handles the idle + * loop, or and error that I've made? + */ + else if ((prs[0].idle==2) && (prs[1].idle==2)) { + amd76x_pm_cfg.C3_cnt++; + inb(amd76x_pm_cfg.C3_reg); + } + #endif + + prs[smp_processor_id()].count = 0; + + } + amd76x_pm_cfg.last_pr = smp_processor_id(); +} + + +/* + * Finds and initializes the bridges, and then sets the idle function + */ +static int +amd76x_pm_main(void) +{ + int found; + + /* Find northbridge */ + found = pci_module_init(&amd_nb_driver); + if (found < 0) { + printk(KERN_ERR "amd76x_pm: Could not find northbridge\n"); + return 1; + } + + /* Find southbridge */ + found = pci_module_init(&amd_sb_driver); + if (found < 0) { + printk(KERN_ERR "amd76x_pm: Could not find southbridge\n"); + pci_unregister_driver(&amd_nb_driver); + return 1; + } + + /* Init southbridge */ + switch (pdev_sb->device) { + case PCI_DEVICE_ID_AMD_VIPER_7413: /* AMD-765 or 766 */ + config_amd766(1); + break; + case PCI_DEVICE_ID_AMD_VIPER_7443: /* AMD-768 */ + config_amd768(1); + break; + default: + printk(KERN_ERR "amd76x_pm: No southbridge to initialize\n"); + break; + } + + /* Init northbridge and queue the new idle function */ + switch (pdev_nb->device) { + case PCI_DEVICE_ID_AMD_FE_GATE_700C: /* AMD-762 */ + config_amd762(1); +#ifndef AMD76X_NTH + amd76x_pm_cfg.curr_idle = amd76x_smp_idle; +#endif + break; + default: + printk(KERN_ERR "amd76x_pm: No northbridge to initialize\n"); + break; + } + +#ifndef AMD76X_NTH + if (!amd76x_pm_cfg.curr_idle) { + printk(KERN_ERR "amd76x_pm: Idle function not changed\n"); + return 1; + } + + amd76x_pm_cfg.orig_idle = pm_idle; + pm_idle = amd76x_pm_cfg.curr_idle; +#endif + +#ifdef AMD76X_NTH + /* Turn NTH on with maxium throttling for testing. */ + activate_amd76x_NTH(1, 1); +#endif + +#ifdef AMD76X_POS + /* Testing here only. */ + activate_amd76x_POS(); +#endif + + return 0; +} + + +static int __init +amd76x_pm_init(void) +{ + printk(KERN_INFO "amd76x_pm: Version %s\n", VERSION); + return amd76x_pm_main(); +} + + +static void __exit +amd76x_pm_cleanup(void) +{ +#ifndef AMD76X_NTH + pm_idle = amd76x_pm_cfg.orig_idle; + + /* This isn't really needed. */ + printk(KERN_INFO "amd76x_pm: %lu C2 calls\n", amd76x_pm_cfg.C2_cnt); +#ifdef AMD76X_C3 + printk(KERN_INFO "amd76x_pm: %lu C3 calls\n", amd76x_pm_cfg.C3_cnt); +#endif + + /* + * FIXME: We want to wait until all CPUs have set the new + * idle function, otherwise we will oops. This may not be + * the right way to do it, but seems to work. + * + * - Best answer is going to be to ban unload, but when its debugged + * --- Alan + */ + schedule(); + mdelay(1000); +#endif + +#ifdef AMD76X_NTH + /* Turn NTH off*/ + activate_amd76x_NTH(0, 0); +#endif + + pci_unregister_driver(&amd_nb_driver); + pci_unregister_driver(&amd_sb_driver); + +} + + +MODULE_LICENSE("GPL"); +module_init(amd76x_pm_init); +module_exit(amd76x_pm_cleanup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/amd76x_pm.h linux.20pre2-ac1/drivers/char/amd76x_pm.h --- linux.20pre2/drivers/char/amd76x_pm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/amd76x_pm.h 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,59 @@ +/* + * Begin 765/766 + */ +/* C2/C3/POS options in C3A50, page 63 in AMD-766 doc */ +#define ZZ_CACHE_EN 1 +#define DCSTOP_EN (1 << 1) +#define STPCLK_EN (1 << 2) +#define CPUSTP_EN (1 << 3) +#define PCISTP_EN (1 << 4) +#define CPUSLP_EN (1 << 5) +#define SUSPND_EN (1 << 6) +#define CPURST_EN (1 << 7) + +#define C2_REGS 0 +#define C3_REGS 8 +#define POS_REGS 16 +/* + * End 765/766 + */ + + +/* + * Begin 768 + */ +/* C2/C3 options in DevB:3x4F, page 100 in AMD-768 doc */ +#define C2EN 1 +#define C3EN (1 << 1) +#define ZZ_C3EN (1 << 2) +#define CSLP_C3EN (1 << 3) +#define CSTP_C3EN (1 << 4) + +/* POS options in DevB:3x50, page 101 in AMD-768 doc */ +#define POSEN 1 +#define CSTP (1 << 2) +#define PSTP (1 << 3) +#define ASTP (1 << 4) +#define DCSTP (1 << 5) +#define CSLP (1 << 6) +#define SUSP (1 << 8) +#define MSRSM (1 << 14) +#define PITRSM (1 << 15) + +/* NTH options DevB:3x40, pg 93 of 768 doc */ +#define NTPER(x) (x << 3) +#define THMINEN(x) (x << 4) + +/* + * End 768 + */ + +/* NTH activate. PM10, pg 110 of 768 doc, pg 70 of 766 doc */ +#define NTH_RATIO(x) (x << 1) +#define NTH_EN (1 << 4) + +/* Sleep state. PM04, pg 109 of 768 doc, pg 69 of 766 doc */ +#define SLP_EN (1 << 13) +#define SLP_TYP(x) (x << 10) + +#define LAZY_IDLE_DELAY 800 /* 0: Best savings, 3000: More responsive */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/amd7xx_tco.c linux.20pre2-ac1/drivers/char/amd7xx_tco.c --- linux.20pre2/drivers/char/amd7xx_tco.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/amd7xx_tco.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,377 @@ +/* + * AMD 766/768 TCO Timer Driver + * (c) Copyright 2002 Zwane Mwaikambo + * All Rights Reserved. + * + * Parts from; + * Hardware driver for the AMD 768 Random Number Generator (RNG) + * (c) Copyright 2001 Red Hat Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AMDTCO_MODULE_VER "build 20020601" +#define AMDTCO_MODULE_NAME "amd7xx_tco" +#define PFX AMDTCO_MODULE_NAME ": " + +#define MAX_TIMEOUT 38 /* max of 38 seconds */ + +/* pmbase registers */ +#define GLOBAL_SMI_REG 0x2a +#define TCO_EN (1 << 1) /* bit 1 in global SMI register */ +#define TCO_RELOAD_REG 0x40 /* bits 0-5 are current count, 6-7 are reserved */ +#define TCO_INITVAL_REG 0x41 /* bits 0-5 are value to load, 6-7 are reserved */ +#define TCO_TIMEOUT_MASK 0x3f +#define TCO_STATUS2_REG 0x46 +#define NDTO_STS2 (1 << 1) /* we're interested in the second timeout */ +#define BOOT_STS (1 << 2) /* will be set if NDTO_STS2 was set before reboot */ +#define TCO_CTRL1_REG 0x48 +#define TCO_HALT (1 << 11) + +static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER; +static int timeout = 38; +static u32 pmbase; /* PMxx I/O base */ +static struct pci_dev *dev; +static struct semaphore open_sem; +spinlock_t amdtco_lock; /* only for device access */ +static int expect_close = 0; + +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38"); + +static inline int amdtco_status(void) +{ + u16 reg; + int status = 0; + + reg = inb(pmbase+TCO_CTRL1_REG); + if ((reg & TCO_HALT) == 0) + status |= WDIOF_KEEPALIVEPING; + + reg = inb(pmbase+TCO_STATUS2_REG); + if (reg & BOOT_STS) + status |= WDIOF_CARDRESET; + + return status; +} + +static inline void amdtco_ping(void) +{ + u8 reg; + + spin_lock(&amdtco_lock); + reg = inb(pmbase+TCO_RELOAD_REG); + outb(1 | reg, pmbase+TCO_RELOAD_REG); + spin_unlock(&amdtco_lock); +} + +static inline int amdtco_gettimeout(void) +{ + return inb(TCO_RELOAD_REG) & TCO_TIMEOUT_MASK; +} + +static inline void amdtco_settimeout(unsigned int timeout) +{ + u8 reg; + + spin_lock(&amdtco_lock); + reg = inb(pmbase+TCO_INITVAL_REG); + reg |= timeout & TCO_TIMEOUT_MASK; + outb(reg, pmbase+TCO_INITVAL_REG); + spin_unlock(&amdtco_lock); +} + +static inline void amdtco_global_enable(void) +{ + u16 reg; + + spin_lock(&amdtco_lock); + reg = inw(pmbase+GLOBAL_SMI_REG); + reg |= TCO_EN; + outw(reg, pmbase+GLOBAL_SMI_REG); + spin_unlock(&amdtco_lock); +} + +static inline void amdtco_enable(void) +{ + u16 reg; + + spin_lock(&amdtco_lock); + reg = inw(pmbase+TCO_CTRL1_REG); + reg &= ~TCO_HALT; + outw(reg, pmbase+TCO_CTRL1_REG); + spin_unlock(&amdtco_lock); +} + +static inline void amdtco_disable(void) +{ + u16 reg; + + spin_lock(&amdtco_lock); + reg = inw(pmbase+TCO_CTRL1_REG); + reg |= TCO_HALT; + outw(reg, pmbase+TCO_CTRL1_REG); + spin_unlock(&amdtco_lock); +} + +static int amdtco_fop_open(struct inode *inode, struct file *file) +{ + if (down_trylock(&open_sem)) + return -EBUSY; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + + if (timeout > MAX_TIMEOUT) + timeout = MAX_TIMEOUT; + + amdtco_settimeout(timeout); + amdtco_global_enable(); + amdtco_ping(); + printk(KERN_INFO PFX "Watchdog enabled, timeout = %d/%d seconds", + amdtco_gettimeout(), timeout); + + return 0; +} + + +static int amdtco_fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int new_timeout; + int tmp; + + static struct watchdog_info ident = { + options: WDIOF_SETTIMEOUT | WDIOF_CARDRESET, + identity: "AMD 766/768" + }; + + switch (cmd) { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident)) + return -EFAULT; + return 0; + + case WDIOC_GETSTATUS: + return put_user(amdtco_status(), (int *)arg); + + case WDIOC_KEEPALIVE: + amdtco_ping(); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, (int *)arg)) + return -EFAULT; + + if (new_timeout < 0) + return -EINVAL; + + if (new_timeout > MAX_TIMEOUT) + new_timeout = MAX_TIMEOUT; + + timeout = new_timeout; + amdtco_settimeout(timeout); + /* fall through and return the new timeout */ + + case WDIOC_GETTIMEOUT: + return put_user(amdtco_gettimeout(), (int *)arg); + + case WDIOC_SETOPTIONS: + if (copy_from_user(&tmp, (int *)arg, sizeof tmp)) + return -EFAULT; + + if (tmp & WDIOS_DISABLECARD) + amdtco_disable(); + + if (tmp & WDIOS_ENABLECARD) + amdtco_enable(); + + return 0; + } +} + + +static int amdtco_fop_release(struct inode *inode, struct file *file) +{ + if (expect_close) { + amdtco_disable(); + printk(KERN_INFO PFX "Watchdog disabled\n"); + } else { + amdtco_ping(); + printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds)\n", timeout); + } + + up(&open_sem); + return 0; +} + + +static ssize_t amdtco_fop_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (len) { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + size_t i; + char c; + expect_close = 0; + + for (i = 0; i != len; i++) { + if (get_user(c, data + i)) + return -EFAULT; + + if (c == 'V') + expect_close = 1; + } +#endif + amdtco_ping(); + return len; + } + + return 0; +} + + +static int amdtco_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + amdtco_disable(); + + return NOTIFY_DONE; +} + + +static struct notifier_block amdtco_notifier = +{ + notifier_call: amdtco_notify_sys +}; + +static struct file_operations amdtco_fops = +{ + owner: THIS_MODULE, + write: amdtco_fop_write, + ioctl: amdtco_fop_ioctl, + open: amdtco_fop_open, + release: amdtco_fop_release +}; + +static struct miscdevice amdtco_miscdev = +{ + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &amdtco_fops +}; + +static struct pci_device_id amdtco_pci_tbl[] __initdata = { + /* AMD 766 PCI_IDs here */ + { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; + +MODULE_DEVICE_TABLE (pci, amdtco_pci_tbl); + +static int __init amdtco_init(void) +{ + int ret; + + sema_init(&open_sem, 1); + spin_lock_init(&amdtco_lock); + + pci_for_each_dev(dev) { + if (pci_match_device (amdtco_pci_tbl, dev) != NULL) + goto found_one; + } + + return -ENODEV; + +found_one: + + if ((ret = register_reboot_notifier(&amdtco_notifier))) { + printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); + goto out_clean; + } + + if ((ret = misc_register(&amdtco_miscdev))) { + printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); + goto out_unreg_reboot; + } + + pci_read_config_dword(dev, 0x58, &pmbase); + pmbase &= 0x0000FF00; + + if (pmbase == 0) { + printk (KERN_ERR PFX "power management base not set\n"); + ret = -EIO; + goto out_unreg_misc; + } + + /* ret = 0; */ + printk(banner); + goto out_clean; + +out_unreg_misc: + misc_deregister(&amdtco_miscdev); +out_unreg_reboot: + unregister_reboot_notifier(&amdtco_notifier); +out_clean: + return ret; +} + +static void __exit amdtco_exit(void) +{ + misc_deregister(&amdtco_miscdev); + unregister_reboot_notifier(&amdtco_notifier); +} + + +#ifndef MODULE +static int __init amdtco_setup(char *str) +{ + int ints[4]; + + str = get_options (str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) + timeout = ints[1]; + + return 1; +} + +__setup("amd7xx_tco=", amdtco_setup); +#endif + +module_init(amdtco_init); +module_exit(amdtco_exit); + +MODULE_AUTHOR("Zwane Mwaikambo "); +MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/Config.in linux.20pre2-ac1/drivers/char/Config.in --- linux.20pre2/drivers/char/Config.in 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/Config.in 2002-08-13 14:21:03.000000000 +0100 @@ -54,6 +54,7 @@ dep_tristate ' Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m fi tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK + tristate ' SyncLink Multiport support' CONFIG_SYNCLINKMP tristate ' HDLC line discipline support' CONFIG_N_HDLC tristate ' SDL RISCom/8 card support' CONFIG_RISCOM8 if [ "$CONFIG_X86_64" != "y" ]; then @@ -192,6 +193,7 @@ bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT + tristate ' ALi M7101 PMU on ALi 1535D+ Watchdog Timer' CONFIG_ALIM1535_WDT tristate ' ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT tristate ' AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG @@ -222,6 +224,7 @@ fi fi tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT + dep_tristate ' AMD 766/768 TCO Timer/Watchdog' CONFIG_AMD7XX_TCO $CONFIG_EXPERIMENTAL fi endmenu @@ -240,6 +243,7 @@ if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI fi +dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_IA64" = "y" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/console.c linux.20pre2-ac1/drivers/char/console.c --- linux.20pre2/drivers/char/console.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/console.c 2002-08-06 15:42:07.000000000 +0100 @@ -101,6 +101,7 @@ #include #include #include +#include #include #include @@ -155,6 +156,7 @@ static void unblank_screen_t(unsigned long dummy); static void console_callback(void *ignored); + static int printable; /* Is console ready for printing? */ int do_poke_blanked_console; @@ -686,6 +688,8 @@ screenbuf = (unsigned short *) q; kmalloced = 1; vc_init(currcons, video_num_lines, video_num_columns, 1); + speakup_allocate(currcons); /* speakup needs more too. */ + if (!pm_con) { pm_con = pm_register(PM_SYS_DEV, @@ -912,6 +916,7 @@ pos += video_size_row; } need_wrap = 0; + speakup_con_write(currcons, "\n",1); } static void ri(int currcons) @@ -938,8 +943,9 @@ { if (x) { pos -= 2; - x--; need_wrap = 0; + x--; + speakup_bs(currcons); } } @@ -1421,7 +1427,10 @@ kbd_table[currcons].slockstate = 0; kbd_table[currcons].ledmode = LED_SHOW_FLAGS; kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; - set_leds(); + + /* Only schedule the keyboard_tasklet if it is enabled. */ + if(!atomic_read(&keyboard_tasklet.count)) + set_leds(); cursor_type = CUR_DEFAULT; complement_mask = s_complement_mask; @@ -1680,7 +1689,12 @@ if (par[0]) par[0]--; gotoxay(currcons,x,par[0]); return; - case 'H': case 'f': + case 'f': + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxay(currcons,par[1],par[0]); + return; + case 'H': if (par[0]) par[0]--; if (par[1]) par[1]--; gotoxay(currcons,par[1],par[0]); @@ -1957,6 +1971,7 @@ if (vc_state == ESnormal && ok) { /* Now try to find out how to display it */ tc = conv_uni_to_pc(vc_cons[currcons].d, tc); + if ( tc == -4 ) { /* If we got -4 (not found) then see if we have defined a replacement character (U+FFFD) */ @@ -1982,6 +1997,7 @@ } if (decim) insert_char(currcons, 1); + speakup_con_write(currcons, (char *) &tc,1); scr_writew(himask ? ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : (attr << 8) + tc, @@ -2022,6 +2038,7 @@ up(&con_buf_sem); } + speakup_con_update(currcons); return n; #undef FLUSH @@ -2047,6 +2064,7 @@ /* we only changed when the console had already been allocated - a new console is not created in an interrupt routine */ + speakup_con_update(want_console); } want_console = -1; } @@ -2118,6 +2136,7 @@ /* Contrived structure to try to emulate original need_wrap behaviour * Problems caused when we have need_wrap set on '\n' character */ + speakup_con_write(currcons, b, count); while (count--) { c = *b++; if (c == 10 || c == 13 || c == 8 || need_wrap) { @@ -2162,6 +2181,7 @@ } } set_cursor(currcons); + speakup_con_update(currcons); if (!oops_in_progress) poke_blanked_console(); @@ -2509,6 +2529,8 @@ master_display_fg = vc_cons[currcons].d; set_origin(currcons); save_screen(currcons); + speakup_init(currcons); + gotoxy(currcons,x,y); csi_J(currcons, 0); update_screen(fg_console); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/Config.in linux.20pre2-ac1/drivers/char/drm/Config.in --- linux.20pre2/drivers/char/drm/Config.in 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/Config.in 2002-08-06 15:42:07.000000000 +0100 @@ -10,5 +10,6 @@ tristate ' ATI Rage 128' CONFIG_DRM_R128 dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP +dep_tristate ' Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP dep_tristate ' SiS' CONFIG_DRM_SIS $CONFIG_AGP diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm_agpsupport.h linux.20pre2-ac1/drivers/char/drm/drm_agpsupport.h --- linux.20pre2/drivers/char/drm/drm_agpsupport.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm_agpsupport.h 2002-08-14 14:41:30.000000000 +0100 @@ -35,12 +35,8 @@ #if __REALLY_HAVE_AGP -#if LINUX_VERSION_CODE < 0x020400 -#include "agpsupport-pre24.h" -#else #define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp") #define DRM_AGP_PUT inter_module_put("drm_agp") -#endif static const drm_agp_t *drm_agp = NULL; @@ -271,24 +267,24 @@ case INTEL_GX: head->chipset = "Intel 440GX"; break; case INTEL_I810: head->chipset = "Intel i810"; break; -#if LINUX_VERSION_CODE >= 0x020400 case INTEL_I815: head->chipset = "Intel i815"; break; +#if LINUX_VERSION_CODE >= 0x020415 case INTEL_I820: head->chipset = "Intel i820"; break; +#endif case INTEL_I840: head->chipset = "Intel i840"; break; +#if LINUX_VERSION_CODE >= 0x020415 case INTEL_I845: head->chipset = "Intel i845"; break; - case INTEL_I850: head->chipset = "Intel i850"; break; #endif + case INTEL_I850: head->chipset = "Intel i850"; break; case VIA_GENERIC: head->chipset = "VIA"; break; case VIA_VP3: head->chipset = "VIA VP3"; break; case VIA_MVP3: head->chipset = "VIA MVP3"; break; -#if LINUX_VERSION_CODE >= 0x020400 case VIA_MVP4: head->chipset = "VIA MVP4"; break; case VIA_APOLLO_KX133: head->chipset = "VIA Apollo KX133"; break; case VIA_APOLLO_KT133: head->chipset = "VIA Apollo KT133"; break; -#endif case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro"; break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm_bufs.h linux.20pre2-ac1/drivers/char/drm/drm_bufs.h --- linux.20pre2/drivers/char/drm/drm_bufs.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm_bufs.h 2002-08-14 14:41:30.000000000 +0100 @@ -229,11 +229,7 @@ DRM(free)(list, sizeof(*list), DRM_MEM_MAPS); for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { -#if LINUX_VERSION_CODE >= 0x020300 if (pt->vma->vm_private_data == map) found_maps++; -#else - if (pt->vma->vm_pte == map) found_maps++; -#endif } if(!found_maps) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm_drv.h linux.20pre2-ac1/drivers/char/drm/drm_drv.h --- linux.20pre2/drivers/char/drm/drm_drv.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm_drv.h 2002-08-06 15:42:07.000000000 +0100 @@ -113,7 +113,6 @@ #define DRIVER_IOCTLS #endif #ifndef DRIVER_FOPS -#if LINUX_VERSION_CODE >= 0x020400 #define DRIVER_FOPS \ static struct file_operations DRM(fops) = { \ owner: THIS_MODULE, \ @@ -126,19 +125,6 @@ fasync: DRM(fasync), \ poll: DRM(poll), \ } -#else -#define DRIVER_FOPS \ -static struct file_operations DRM(fops) = { \ - open: DRM(open), \ - flush: DRM(flush), \ - release: DRM(release), \ - ioctl: DRM(ioctl), \ - mmap: DRM(mmap), \ - read: DRM(read), \ - fasync: DRM(fasync), \ - poll: DRM(poll), \ -} -#endif #endif @@ -234,7 +220,9 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_PARM( drm_opts, "s" ); +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL and additional rights"); +#endif static int DRM(setup)( drm_device_t *dev ) { @@ -732,9 +720,6 @@ retcode = DRM(open_helper)( inode, filp, dev ); if ( !retcode ) { -#if LINUX_VERSION_CODE < 0x020333 - MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif atomic_inc( &dev->counts[_DRM_STAT_OPENS] ); spin_lock( &dev->count_lock ); if ( !dev->open_count++ ) { @@ -853,9 +838,6 @@ * End inline drm_release */ -#if LINUX_VERSION_CODE < 0x020333 - MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif atomic_inc( &dev->counts[_DRM_STAT_CLOSES] ); spin_lock( &dev->count_lock ); if ( !--dev->open_count ) { @@ -1047,25 +1029,6 @@ atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] ); -#if __HAVE_KERNEL_CTX_SWITCH - /* We no longer really hold it, but if we are the next - * agent to request it then we should just be able to - * take it immediately and not eat the ioctl. - */ - dev->lock.pid = 0; - { - __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; - unsigned int old, new, prev, ctx; - - ctx = lock.context; - do { - old = *plock; - new = ctx; - prev = cmpxchg(plock, old, new); - } while (prev != old); - } - wake_up_interruptible(&dev->lock.lock_queue); -#else DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT ); #if __HAVE_DMA_SCHEDULE @@ -1080,7 +1043,6 @@ DRM_ERROR( "\n" ); } } -#endif /* !__HAVE_KERNEL_CTX_SWITCH */ unblock_all_signals(); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm_fops.h linux.20pre2-ac1/drivers/char/drm/drm_fops.h --- linux.20pre2/drivers/char/drm/drm_fops.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm_fops.h 2002-08-14 14:41:30.000000000 +0100 @@ -125,21 +125,31 @@ int avail; int send; int cur; + DECLARE_WAITQUEUE(wait, current); DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp); + add_wait_queue(&dev->buf_readers, &wait); + set_current_state(TASK_INTERRUPTIBLE); while (dev->buf_rp == dev->buf_wp) { DRM_DEBUG(" sleeping\n"); if (filp->f_flags & O_NONBLOCK) { + remove_wait_queue(&dev->buf_readers, &wait); + set_current_state(TASK_RUNNING); return -EAGAIN; } - interruptible_sleep_on(&dev->buf_readers); + schedule(); /* wait for dev->buf_readers */ if (signal_pending(current)) { DRM_DEBUG(" interrupted\n"); + remove_wait_queue(&dev->buf_readers, &wait); + set_current_state(TASK_RUNNING); return -ERESTARTSYS; } DRM_DEBUG(" awake\n"); + set_current_state(TASK_INTERRUPTIBLE); } + remove_wait_queue(&dev->buf_readers, &wait); + set_current_state(TASK_RUNNING); left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; avail = DRM_BSZ - left; @@ -191,24 +201,8 @@ send -= count; } -#if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS) - /* The extra parameter to kill_fasync was added in 2.3.21, and is - _not_ present in _stock_ 2.2.14 and 2.2.15. However, some - distributions patch 2.2.x kernels to add this parameter. The - Makefile.linux attempts to detect this addition and defines - KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */ - if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); -#else - - /* Parameter added in 2.3.21. */ -#if LINUX_VERSION_CODE < 0x020400 - if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN); -#else - /* Type of first parameter changed in - Linux 2.4.0-test2... */ if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN); -#endif -#endif + DRM_DEBUG("waking\n"); wake_up_interruptible(&dev->buf_readers); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm.h linux.20pre2-ac1/drivers/char/drm/drm.h --- linux.20pre2/drivers/char/drm/drm.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm.h 2002-08-06 18:24:33.000000000 +0100 @@ -104,9 +104,8 @@ #include "i810_drm.h" #include "r128_drm.h" #include "radeon_drm.h" -#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) #include "sis_drm.h" -#endif +#include "i830_drm.h" typedef struct drm_version { int version_major; /* Major version */ @@ -449,6 +448,12 @@ #define DRM_IOCTL_I810_SWAP DRM_IO( 0x46) #define DRM_IOCTL_I810_COPY DRM_IOW( 0x47, drm_i810_copy_t) #define DRM_IOCTL_I810_DOCOPY DRM_IO( 0x48) +#define DRM_IOCTL_I810_OV0INFO DRM_IOR( 0x49, drm_i810_overlay_t) +#define DRM_IOCTL_I810_FSTATUS DRM_IO ( 0x4a) +#define DRM_IOCTL_I810_OV0FLIP DRM_IO ( 0x4b) +#define DRM_IOCTL_I810_MC DRM_IOW( 0x4c, drm_i810_mc_t) +#define DRM_IOCTL_I810_RSTATUS DRM_IO ( 0x4d ) + /* Rage 128 specific ioctls */ #define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) @@ -483,7 +488,6 @@ #define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(0x4d, drm_radeon_indirect_t) #define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(0x4e, drm_radeon_texture_t) -#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) /* SiS specific ioctls */ #define SIS_IOCTL_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) #define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) @@ -493,6 +497,16 @@ #define SIS_IOCTL_FLIP DRM_IOW( 0x48, drm_sis_flip_t) #define SIS_IOCTL_FLIP_INIT DRM_IO( 0x49) #define SIS_IOCTL_FLIP_FINAL DRM_IO( 0x50) -#endif + +/* I830 specific ioctls */ +#define DRM_IOCTL_I830_INIT DRM_IOW( 0x40, drm_i830_init_t) +#define DRM_IOCTL_I830_VERTEX DRM_IOW( 0x41, drm_i830_vertex_t) +#define DRM_IOCTL_I830_CLEAR DRM_IOW( 0x42, drm_i830_clear_t) +#define DRM_IOCTL_I830_FLUSH DRM_IO ( 0x43) +#define DRM_IOCTL_I830_GETAGE DRM_IO ( 0x44) +#define DRM_IOCTL_I830_GETBUF DRM_IOWR(0x45, drm_i830_dma_t) +#define DRM_IOCTL_I830_SWAP DRM_IO ( 0x46) +#define DRM_IOCTL_I830_COPY DRM_IOW( 0x47, drm_i830_copy_t) +#define DRM_IOCTL_I830_DOCOPY DRM_IO ( 0x48) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm_memory.h linux.20pre2-ac1/drivers/char/drm/drm_memory.h --- linux.20pre2/drivers/char/drm/drm_memory.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm_memory.h 2002-08-14 14:41:30.000000000 +0100 @@ -85,12 +85,7 @@ } si_meminfo(&si); -#if LINUX_VERSION_CODE < 0x020317 - /* Changed to page count in 2.3.23 */ - DRM(ram_available) = si.totalram >> PAGE_SHIFT; -#else DRM(ram_available) = si.totalram; -#endif DRM(ram_used) = 0; } @@ -257,12 +252,7 @@ for (addr = address, sz = bytes; sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { -#if LINUX_VERSION_CODE >= 0x020400 - /* Argument type changed in 2.4.0-test6/pre8 */ mem_map_reserve(virt_to_page(addr)); -#else - mem_map_reserve(MAP_NR(addr)); -#endif } return address; @@ -283,12 +273,7 @@ for (addr = address, sz = bytes; sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { -#if LINUX_VERSION_CODE >= 0x020400 - /* Argument type changed in 2.4.0-test6/pre8 */ mem_map_unreserve(virt_to_page(addr)); -#else - mem_map_unreserve(MAP_NR(addr)); -#endif } free_pages(address, order); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drmP.h linux.20pre2-ac1/drivers/char/drm/drmP.h --- linux.20pre2/drivers/char/drm/drmP.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drmP.h 2002-08-14 14:41:30.000000000 +0100 @@ -66,13 +66,8 @@ #include #include #endif -#if LINUX_VERSION_CODE >= 0x020100 /* KERNEL_VERSION(2,1,0) */ #include #include -#endif -#if LINUX_VERSION_CODE < 0x020400 -#include "compat-pre24.h" -#endif #include #include "drm.h" @@ -81,12 +76,6 @@ #define page_to_bus(page) ((unsigned int)(virt_to_bus(page_address(page)))) #endif -/* We just use virt_to_bus for pci_map_single on older kernels */ -#if LINUX_VERSION_CODE < 0x020400 -#define pci_map_single(hwdev, ptr, size, direction) virt_to_bus(ptr) -#define pci_unmap_single(hwdev, dma_addr, size, direction) -#endif - /* DRM template customization defaults */ #ifndef __HAVE_AGP @@ -119,87 +108,6 @@ #define __REALLY_HAVE_MTRR (__HAVE_MTRR && defined(CONFIG_MTRR)) -/* Begin the DRM... - */ - -#define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then - also include looping detection. */ - -#define DRM_HASH_SIZE 16 /* Size of key hash table */ -#define DRM_KERNEL_CONTEXT 0 /* Change drm_resctx if changed */ -#define DRM_RESERVED_CONTEXTS 1 /* Change drm_resctx if changed */ -#define DRM_LOOPING_LIMIT 5000000 -#define DRM_BSZ 1024 /* Buffer size for /dev/drm? output */ -#define DRM_TIME_SLICE (HZ/20) /* Time slice for GLXContexts */ -#define DRM_LOCK_SLICE 1 /* Time slice for lock, in jiffies */ - -#define DRM_FLAG_DEBUG 0x01 -#define DRM_FLAG_NOCTX 0x02 - -#define DRM_MEM_DMA 0 -#define DRM_MEM_SAREA 1 -#define DRM_MEM_DRIVER 2 -#define DRM_MEM_MAGIC 3 -#define DRM_MEM_IOCTLS 4 -#define DRM_MEM_MAPS 5 -#define DRM_MEM_VMAS 6 -#define DRM_MEM_BUFS 7 -#define DRM_MEM_SEGS 8 -#define DRM_MEM_PAGES 9 -#define DRM_MEM_FILES 10 -#define DRM_MEM_QUEUES 11 -#define DRM_MEM_CMDS 12 -#define DRM_MEM_MAPPINGS 13 -#define DRM_MEM_BUFLISTS 14 -#define DRM_MEM_AGPLISTS 15 -#define DRM_MEM_TOTALAGP 16 -#define DRM_MEM_BOUNDAGP 17 -#define DRM_MEM_CTXBITMAP 18 -#define DRM_MEM_STUB 19 -#define DRM_MEM_SGLISTS 20 - -#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) - - /* Backward compatibility section */ - /* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */ -#ifndef _PAGE_PWT -#define _PAGE_PWT _PAGE_WT -#endif - /* Wait queue declarations changed in 2.3.1 */ -#ifndef DECLARE_WAITQUEUE -#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL } -typedef struct wait_queue *wait_queue_head_t; -#define init_waitqueue_head(q) *q = NULL; -#endif - - /* _PAGE_4M changed to _PAGE_PSE in 2.3.23 */ -#ifndef _PAGE_PSE -#define _PAGE_PSE _PAGE_4M -#endif - - /* vm_offset changed to vm_pgoff in 2.3.25 */ -#if LINUX_VERSION_CODE < 0x020319 -#define VM_OFFSET(vma) ((vma)->vm_offset) -#else -#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT) -#endif - - /* *_nopage return values defined in 2.3.26 */ -#ifndef NOPAGE_SIGBUS -#define NOPAGE_SIGBUS 0 -#endif -#ifndef NOPAGE_OOM -#define NOPAGE_OOM 0 -#endif - - /* module_init/module_exit added in 2.3.13 */ -#ifndef module_init -#define module_init(x) int init_module(void) { return x(); } -#endif -#ifndef module_exit -#define module_exit(x) void cleanup_module(void) { x(); } -#endif - /* Generic cmpxchg added in 2.3.x */ #ifndef __HAVE_ARCH_CMPXCHG /* Include this here so that driver can be @@ -211,7 +119,7 @@ unsigned long prev, cmp; __asm__ __volatile__( - "1: ldl_l %0,%5\n" + "1: ldl_l %0,%2\n" " cmpeq %0,%3,%1\n" " beq %1,2f\n" " mov %4,%1\n" @@ -222,8 +130,7 @@ "3: br 1b\n" ".previous" : "=&r"(prev), "=&r"(cmp), "=m"(*m) - : "r"((long) old), "r"(new), "m"(*m) - : "memory" ); + : "r"((long) old), "r"(new), "m"(*m)); return prev; } @@ -234,7 +141,7 @@ unsigned long prev, cmp; __asm__ __volatile__( - "1: ldq_l %0,%5\n" + "1: ldq_l %0,%2\n" " cmpeq %0,%3,%1\n" " beq %1,2f\n" " mov %4,%1\n" @@ -245,8 +152,7 @@ "3: br 1b\n" ".previous" : "=&r"(prev), "=&r"(cmp), "=m"(*m) - : "r"((long) old), "r"(new), "m"(*m) - : "memory" ); + : "r"((long) old), "r"(new), "m"(*m)); return prev; } @@ -298,42 +204,82 @@ return old; } -#elif defined(__powerpc__) -extern void __cmpxchg_called_with_bad_pointer(void); -static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, - unsigned long new, int size) -{ - unsigned long prev; - - switch (size) { - case 4: - __asm__ __volatile__( - "sync;" - "0: lwarx %0,0,%1 ;" - " cmpl 0,%0,%3;" - " bne 1f;" - " stwcx. %2,0,%1;" - " bne- 0b;" - "1: " - "sync;" - : "=&r"(prev) - : "r"(ptr), "r"(new), "r"(old) - : "cr0", "memory"); - return prev; - } - __cmpxchg_called_with_bad_pointer(); - return old; -} - -#endif /* i386, powerpc & alpha */ - -#ifndef __alpha__ #define cmpxchg(ptr,o,n) \ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \ (unsigned long)(n),sizeof(*(ptr)))) +#endif /* i386 & alpha */ #endif -#endif /* !__HAVE_ARCH_CMPXCHG */ +/* Begin the DRM... + */ + +#define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then + also include looping detection. */ + +#define DRM_HASH_SIZE 16 /* Size of key hash table */ +#define DRM_KERNEL_CONTEXT 0 /* Change drm_resctx if changed */ +#define DRM_RESERVED_CONTEXTS 1 /* Change drm_resctx if changed */ +#define DRM_LOOPING_LIMIT 5000000 +#define DRM_BSZ 1024 /* Buffer size for /dev/drm? output */ +#define DRM_TIME_SLICE (HZ/20) /* Time slice for GLXContexts */ +#define DRM_LOCK_SLICE 1 /* Time slice for lock, in jiffies */ + +#define DRM_FLAG_DEBUG 0x01 +#define DRM_FLAG_NOCTX 0x02 + +#define DRM_MEM_DMA 0 +#define DRM_MEM_SAREA 1 +#define DRM_MEM_DRIVER 2 +#define DRM_MEM_MAGIC 3 +#define DRM_MEM_IOCTLS 4 +#define DRM_MEM_MAPS 5 +#define DRM_MEM_VMAS 6 +#define DRM_MEM_BUFS 7 +#define DRM_MEM_SEGS 8 +#define DRM_MEM_PAGES 9 +#define DRM_MEM_FILES 10 +#define DRM_MEM_QUEUES 11 +#define DRM_MEM_CMDS 12 +#define DRM_MEM_MAPPINGS 13 +#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_AGPLISTS 15 +#define DRM_MEM_TOTALAGP 16 +#define DRM_MEM_BOUNDAGP 17 +#define DRM_MEM_CTXBITMAP 18 +#define DRM_MEM_STUB 19 +#define DRM_MEM_SGLISTS 20 + +#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) + +#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT) + +/* Macros to make printk easier */ + +#if ( __GNUC__ > 2 ) + +#define DRM_ERROR(fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__, ##arg) +#define DRM_MEM_ERROR(area, fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \ + DRM(mem_stats)[area].name , ##arg) +#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) + +#if DRM_DEBUG_CODE +#define DRM_DEBUG(fmt, arg...) \ + do { \ + if ( DRM(flags) & DRM_FLAG_DEBUG ) \ + printk(KERN_DEBUG \ + "[" DRM_NAME ":%s] " fmt , \ + __FUNCTION__, \ + ##arg); \ + } while (0) +#else +#define DRM_DEBUG(fmt, arg...) do { } while (0) +#endif + +#else /* Gcc 2.x */ + +/* Work around a C preprocessor bug */ /* Macros to make printk easier */ #define DRM_ERROR(fmt, arg...) \ @@ -355,6 +301,9 @@ #define DRM_DEBUG(fmt, arg...) do { } while (0) #endif +#endif /* Gcc 2.x */ + + #define DRM_PROC_LIMIT (PAGE_SIZE-80) #define DRM_PROC_PRINT(fmt, arg...) \ @@ -778,34 +727,18 @@ struct poll_table_struct *wait); /* Mapping support (drm_vm.h) */ -#if LINUX_VERSION_CODE < 0x020317 -extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma, - unsigned long address, - int unused); -extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma, - unsigned long address, - int unused); -extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, - unsigned long address, - int unused); -extern unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma, - unsigned long address, - int unused); -#else - /* Return type changed in 2.3.23 */ extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma, unsigned long address, - int unused); + int write_access); extern struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, unsigned long address, - int unused); + int write_access); extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, - int unused); + int write_access); extern struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma, unsigned long address, - int unused); -#endif + int write_access); extern void DRM(vm_open)(struct vm_area_struct *vma); extern void DRM(vm_close)(struct vm_area_struct *vma); extern void DRM(vm_shm_close)(struct vm_area_struct *vma); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm_scatter.h linux.20pre2-ac1/drivers/char/drm/drm_scatter.h --- linux.20pre2/drivers/char/drm/drm_scatter.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm_scatter.h 2002-08-14 14:41:30.000000000 +0100 @@ -66,9 +66,6 @@ drm_scatter_gather_t request; drm_sg_mem_t *entry; unsigned long pages, i, j; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; DRM_DEBUG( "%s\n", __FUNCTION__ ); @@ -135,21 +132,10 @@ DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual ); for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) { - pgd = pgd_offset_k( i ); - if ( !pgd_present( *pgd ) ) + entry->pagelist[j] = vmalloc_to_page((void *)i); + if (!entry->pagelist[j]) goto failed; - - pmd = pmd_offset( pgd, i ); - if ( !pmd_present( *pmd ) ) - goto failed; - - pte = pte_offset( pmd, i ); - if ( !pte_present( *pte ) ) - goto failed; - - entry->pagelist[j] = pte_page( *pte ); - - SetPageReserved( entry->pagelist[j] ); + SetPageReserved(entry->pagelist[j]); } request.handle = entry->handle; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm_stub.h linux.20pre2-ac1/drivers/char/drm/drm_stub.h --- linux.20pre2/drivers/char/drm/drm_stub.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm_stub.h 2002-08-14 14:41:30.000000000 +0100 @@ -31,10 +31,6 @@ #define __NO_VERSION__ #include "drmP.h" -#if LINUX_VERSION_CODE < 0x020400 -#include "stubsupport-pre24.h" -#endif - #define DRM_STUB_MAXCARDS 16 /* Enough for one machine */ static struct drm_stub_list { @@ -70,9 +66,7 @@ } static struct file_operations DRM(stub_fops) = { -#if LINUX_VERSION_CODE >= 0x020400 owner: THIS_MODULE, -#endif open: DRM(stub_open) }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/drm_vm.h linux.20pre2-ac1/drivers/char/drm/drm_vm.h --- linux.20pre2/drivers/char/drm/drm_vm.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/drm_vm.h 2002-08-14 14:41:30.000000000 +0100 @@ -56,16 +56,9 @@ close: DRM(vm_close), }; -#if LINUX_VERSION_CODE < 0x020317 -unsigned long DRM(vm_nopage)(struct vm_area_struct *vma, - unsigned long address, - int unused) -#else - /* Return type changed in 2.3.23 */ struct page *DRM(vm_nopage)(struct vm_area_struct *vma, unsigned long address, - int unused) -#endif + int write_access) { #if __REALLY_HAVE_AGP drm_file_t *priv = vma->vm_file->private_data; @@ -122,11 +115,7 @@ DRM_DEBUG("baddr = 0x%lx page = 0x%p, offset = 0x%lx\n", baddr, __va(agpmem->memory->memory[offset]), offset); -#if LINUX_VERSION_CODE < 0x020317 - return page_address(page); -#else return page; -#endif } vm_nopage_error: #endif /* __REALLY_HAVE_AGP */ @@ -134,27 +123,13 @@ return NOPAGE_SIGBUS; /* Disallow mremap */ } -#if LINUX_VERSION_CODE < 0x020317 -unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma, - unsigned long address, - int unused) -#else - /* Return type changed in 2.3.23 */ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, unsigned long address, - int unused) -#endif + int write_access) { -#if LINUX_VERSION_CODE >= 0x020300 drm_map_t *map = (drm_map_t *)vma->vm_private_data; -#else - drm_map_t *map = (drm_map_t *)vma->vm_pte; -#endif unsigned long offset; unsigned long i; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; struct page *page; if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ @@ -162,25 +137,13 @@ offset = address - vma->vm_start; i = (unsigned long)map->handle + offset; - /* We have to walk page tables here because we need large SAREA's, and - * they need to be virtually contiguous in kernel space. - */ - pgd = pgd_offset_k( i ); - if( !pgd_present( *pgd ) ) return NOPAGE_OOM; - pmd = pmd_offset( pgd, i ); - if( !pmd_present( *pmd ) ) return NOPAGE_OOM; - pte = pte_offset( pmd, i ); - if( !pte_present( *pte ) ) return NOPAGE_OOM; - - page = pte_page(*pte); + page = vmalloc_to_page((void *)i); + if (!page) + return NOPAGE_OOM; get_page(page); - DRM_DEBUG("shm_nopage 0x%lx\n", address); -#if LINUX_VERSION_CODE < 0x020317 - return page_address(page); -#else + DRM_DEBUG("0x%08lx => 0x%08x\n", address, page_to_bus(page)); return page; -#endif } /* Special close routine which deletes map information if we are the last @@ -199,25 +162,14 @@ DRM_DEBUG("0x%08lx,0x%08lx\n", vma->vm_start, vma->vm_end - vma->vm_start); -#if LINUX_VERSION_CODE < 0x020333 - MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif atomic_dec(&dev->vma_count); -#if LINUX_VERSION_CODE >= 0x020300 map = vma->vm_private_data; -#else - map = vma->vm_pte; -#endif down(&dev->struct_sem); for (pt = dev->vmalist, prev = NULL; pt; pt = next) { next = pt->next; -#if LINUX_VERSION_CODE >= 0x020300 if (pt->vma->vm_private_data == map) found_maps++; -#else - if (pt->vma->vm_pte == map) found_maps++; -#endif if (pt->vma == vma) { if (prev) { prev->next = pt->next; @@ -270,16 +222,9 @@ up(&dev->struct_sem); } -#if LINUX_VERSION_CODE < 0x020317 -unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, - unsigned long address, - int unused) -#else - /* Return type changed in 2.3.23 */ struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, - int unused) -#endif + int write_access) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; @@ -299,30 +244,16 @@ get_page(page); - DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr); -#if LINUX_VERSION_CODE < 0x020317 - return page_address(page); -#else + DRM_DEBUG("0x%08lx (page %lu) => 0x%08x\n", address, page_nr, + page_to_bus(page)); return page; -#endif } -#if LINUX_VERSION_CODE < 0x020317 -unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma, - unsigned long address, - int unused) -#else - /* Return type changed in 2.3.23 */ struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma, unsigned long address, - int unused) -#endif + int write_access) { -#if LINUX_VERSION_CODE >= 0x020300 drm_map_t *map = (drm_map_t *)vma->vm_private_data; -#else - drm_map_t *map = (drm_map_t *)vma->vm_pte; -#endif drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; drm_sg_mem_t *entry = dev->sg; @@ -342,11 +273,7 @@ page = entry->pagelist[page_offset]; get_page(page); -#if LINUX_VERSION_CODE < 0x020317 - return page_address(page); -#else return page; -#endif } void DRM(vm_open)(struct vm_area_struct *vma) @@ -358,10 +285,6 @@ DRM_DEBUG("0x%08lx,0x%08lx\n", vma->vm_start, vma->vm_end - vma->vm_start); atomic_inc(&dev->vma_count); -#if LINUX_VERSION_CODE < 0x020333 - /* The map can exist after the fd is closed. */ - MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif vma_entry = DRM(alloc)(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { @@ -382,9 +305,6 @@ DRM_DEBUG("0x%08lx,0x%08lx\n", vma->vm_start, vma->vm_end - vma->vm_start); -#if LINUX_VERSION_CODE < 0x020333 - MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif atomic_dec(&dev->vma_count); down(&dev->struct_sem); @@ -423,13 +343,13 @@ unlock_kernel(); vma->vm_ops = &DRM(vm_dma_ops); - vma->vm_flags |= VM_RESERVED; /* Don't swap */ -#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ - /* In Linux 2.2.3 and above, this is - handled in do_mmap() in mm/mmap.c. */ - ++filp->f_count; +#if LINUX_VERSION_CODE <= 0x020414 + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ +#else + vma->vm_flags |= VM_RESERVED; /* Don't swap */ #endif + vma->vm_file = filp; /* Needed for drm_vm_open() */ DRM(vm_open)(vma); return 0; @@ -531,17 +451,10 @@ vma->vm_flags |= VM_IO; /* not in core dump */ } offset = DRIVER_GET_REG_OFS(); -#ifdef __sparc__ - if (io_remap_page_range(vma->vm_start, - VM_OFFSET(vma) + offset, - vma->vm_end - vma->vm_start, - vma->vm_page_prot, 0)) -#else if (remap_page_range(vma->vm_start, VM_OFFSET(vma) + offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) -#endif return -EAGAIN; DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," " offset = 0x%lx\n", @@ -551,34 +464,33 @@ break; case _DRM_SHM: vma->vm_ops = &DRM(vm_shm_ops); -#if LINUX_VERSION_CODE >= 0x020300 vma->vm_private_data = (void *)map; -#else - vma->vm_pte = (unsigned long)map; -#endif /* Don't let this area swap. Change when DRM_KERNEL advisory is supported. */ +#if LINUX_VERSION_CODE <= 0x020414 + vma->vm_flags |= VM_LOCKED; +#else vma->vm_flags |= VM_RESERVED; +#endif break; case _DRM_SCATTER_GATHER: vma->vm_ops = &DRM(vm_sg_ops); -#if LINUX_VERSION_CODE >= 0x020300 vma->vm_private_data = (void *)map; +#if LINUX_VERSION_CODE <= 0x020414 + vma->vm_flags |= VM_LOCKED; #else - vma->vm_pte = (unsigned long)map; + vma->vm_flags |= VM_RESERVED; #endif - vma->vm_flags |= VM_RESERVED; break; default: return -EINVAL; /* This should never happen. */ } +#if LINUX_VERSION_CODE <= 0x020414 + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ +#else vma->vm_flags |= VM_RESERVED; /* Don't swap */ - -#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ - /* In Linux 2.2.3 and above, this is - handled in do_mmap() in mm/mmap.c. */ - ++filp->f_count; #endif + vma->vm_file = filp; /* Needed for drm_vm_open() */ DRM(vm_open)(vma); return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/i810_dma.c linux.20pre2-ac1/drivers/char/drm/i810_dma.c --- linux.20pre2/drivers/char/drm/i810_dma.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/i810_dma.c 2002-08-06 15:42:07.000000000 +0100 @@ -35,6 +35,7 @@ #include "drmP.h" #include "i810_drv.h" #include /* For task queue support */ +#include /* in case we don't have a 2.3.99-pre6 kernel or later: */ #ifndef VM_DONTCOPY @@ -73,7 +74,7 @@ *(volatile unsigned int *)(virt + outring) = n; \ outring += 4; \ outring &= ringmask; \ -} while (0); +} while (0) static inline void i810_print_status_page(drm_device_t *dev) { @@ -86,6 +87,7 @@ DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]); DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]); DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]); + DRM_DEBUG( "hw_status: Last Render: %x\n", temp[4]); DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]); for(i = 6; i < dma->buf_count + 6; i++) { DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]); @@ -227,14 +229,9 @@ #else down_write( ¤t->mm->mmap_sem ); #endif -#if LINUX_VERSION_CODE < 0x020399 - retcode = do_munmap((unsigned long)buf_priv->virtual, - (size_t) buf->total); -#else retcode = do_munmap(current->mm, (unsigned long)buf_priv->virtual, - (size_t) buf->total); -#endif + (size_t) buf->total, 1); #if LINUX_VERSION_CODE <= 0x020402 up( ¤t->mm->mmap_sem ); #else @@ -278,30 +275,6 @@ return retcode; } -static unsigned long i810_alloc_page(drm_device_t *dev) -{ - unsigned long address; - - address = __get_free_page(GFP_KERNEL); - if(address == 0UL) - return 0; - - get_page(virt_to_page(address)); - LockPage(virt_to_page(address)); - - return address; -} - -static void i810_free_page(drm_device_t *dev, unsigned long page) -{ - if (page) { - struct page *p = virt_to_page(page); - put_page(p); - UnlockPage(p); - free_page(page); - } -} - static int i810_dma_cleanup(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; @@ -316,7 +289,8 @@ dev_priv->ring.Size); } if(dev_priv->hw_status_page != 0UL) { - i810_free_page(dev, dev_priv->hw_status_page); + pci_free_consistent(dev->pdev, PAGE_SIZE, (void *)dev_priv->hw_status_page, + dev_priv->dma_status_page); /* Need to rewrite hardware status page */ I810_WRITE(0x02080, 0x1ffff000); } @@ -474,12 +448,16 @@ dev_priv->back_offset = init->back_offset; dev_priv->depth_offset = init->depth_offset; + dev_priv->overlay_offset = init->overlay_offset; + dev_priv->overlay_physical = init->overlay_physical; + dev_priv->front_di1 = init->front_offset | init->pitch_bits; dev_priv->back_di1 = init->back_offset | init->pitch_bits; dev_priv->zi1 = init->depth_offset | init->pitch_bits; /* Program Hardware Status Page */ - dev_priv->hw_status_page = i810_alloc_page(dev); + dev_priv->hw_status_page = (unsigned long)pci_alloc_consistent(dev->pdev, PAGE_SIZE, + &dev_priv->dma_status_page); if(dev_priv->hw_status_page == 0UL) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); @@ -489,7 +467,7 @@ memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); - I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page)); + I810_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); /* Now we need to init our freelist */ @@ -505,6 +483,12 @@ return 0; } + +int xfreeversion = -1; + +MODULE_PARM(xfreeversion, "i"); +MODULE_PARM_DESC(xfreeversion, "The version of XFree86 that needs to be supported"); + int i810_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -516,6 +500,22 @@ if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init))) return -EFAULT; + + if ((xfreeversion==41) || ((xfreeversion==-1)&&(init.pitch==0))) { + /* Ok we have a problem here. Someone decided it was funny to add + * two fields in the middle of the drm_i810_init_it structure in the + * transition between XFree86 4.1.0 and 4.2.0. The code below tries + * to fix this ABI breakage up as good as possible, unfortionatly + * it's impossible to autodetect which interface the user wants, + * hence the module parameter -- Arjan + */ + init.pitch_bits = init.h; + init.pitch = init.w; + init.h = init.overlay_physical; + init.w = init.overlay_offset; + init.overlay_physical = 0; + init.overlay_offset = 0; + } switch(init.func) { case I810_INIT_DMA: @@ -1262,3 +1262,156 @@ if(VM_DONTCOPY == 0) return 1; return 0; } + +static void i810_dma_dispatch_mc(drm_device_t *dev, drm_buf_t *buf, int used, + unsigned int last_render) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + drm_i810_buf_priv_t *buf_priv = buf->dev_private; + drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned long address = (unsigned long)buf->bus_address; + unsigned long start = address - dev->agp->base; + int u; + RING_LOCALS; + + i810_kernel_lost_context(dev); + + u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, + I810_BUF_HARDWARE); + if(u != I810_BUF_CLIENT) { + DRM_DEBUG("MC found buffer that isn't mine!\n"); + } + + if (used > 4*1024) + used = 0; + + sarea_priv->dirty = 0x7f; + + DRM_DEBUG("dispatch mc addr 0x%lx, used 0x%x\n", + address, used); + + dev_priv->counter++; + DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter); + DRM_DEBUG("i810_dma_dispatch_mc\n"); + DRM_DEBUG("start : %lx\n", start); + DRM_DEBUG("used : %d\n", used); + DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4); + + if (buf_priv->currently_mapped == I810_BUF_MAPPED) { + if (used & 4) { + *(u32 *)((u32)buf_priv->virtual + used) = 0; + used += 4; + } + + i810_unmap_buffer(buf); + } + BEGIN_LP_RING(4); + OUT_RING( CMD_OP_BATCH_BUFFER ); + OUT_RING( start | BB1_PROTECTED ); + OUT_RING( start + used - 4 ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + + BEGIN_LP_RING(8); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( buf_priv->my_use_idx ); + OUT_RING( I810_BUF_FREE ); + OUT_RING( 0 ); + + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( 16 ); + OUT_RING( last_render ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); +} + +int i810_dma_mc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) + dev_priv->sarea_priv; + drm_i810_mc_t mc; + + if (copy_from_user(&mc, (drm_i810_mc_t *)arg, sizeof(mc))) + return -EFAULT; + + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_dma_mc called without lock held\n"); + return -EINVAL; + } + + i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used, + mc.last_render ); + + atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]); + atomic_inc(&dev->counts[_DRM_STAT_DMA]); + sarea_priv->last_enqueue = dev_priv->counter-1; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return 0; +} + +int i810_rstatus(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + + return (int)(((u32 *)(dev_priv->hw_status_page))[4]); +} + +int i810_ov0_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + drm_i810_overlay_t data; + + data.offset = dev_priv->overlay_offset; + data.physical = dev_priv->overlay_physical; + copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data)); + return 0; +} + +int i810_fstatus(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_fstatus called without lock held\n"); + return -EINVAL; + } + return I810_READ(0x30008); +} + +int i810_ov0_flip(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_ov0_flip called without lock held\n"); + return -EINVAL; + } + + //Tell the overlay to update + I810_WRITE(0x30000,dev_priv->overlay_physical | 0x80000000); + + return 0; +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/i810_drm.h linux.20pre2-ac1/drivers/char/drm/i810_drm.h --- linux.20pre2/drivers/char/drm/i810_drm.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/i810_drm.h 2002-08-06 15:42:07.000000000 +0100 @@ -112,6 +112,8 @@ unsigned int front_offset; unsigned int back_offset; unsigned int depth_offset; + unsigned int overlay_offset; + unsigned int overlay_physical; unsigned int w; unsigned int h; unsigned int pitch; @@ -196,4 +198,18 @@ int granted; } drm_i810_dma_t; +typedef struct _drm_i810_overlay_t { + unsigned int offset; /* Address of the Overlay Regs */ + unsigned int physical; +} drm_i810_overlay_t; + +typedef struct _drm_i810_mc { + int idx; /* buffer index */ + int used; /* nr bytes in use */ + int num_blocks; /* number of GFXBlocks */ + int *length; /* List of lengths for GFXBlocks (FUTURE)*/ + unsigned int last_render; /* Last Render Request */ +} drm_i810_mc_t; + + #endif /* _I810_DRM_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/i810_drv.c linux.20pre2-ac1/drivers/char/drm/i810_drv.c --- linux.20pre2/drivers/char/drm/i810_drv.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/i810_drv.c 2002-08-06 15:42:07.000000000 +0100 @@ -39,10 +39,10 @@ #define DRIVER_NAME "i810" #define DRIVER_DESC "Intel i810" -#define DRIVER_DATE "20010616" +#define DRIVER_DATE "20010920" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 1 +#define DRIVER_MINOR 2 #define DRIVER_PATCHLEVEL 0 #define DRIVER_IOCTLS \ @@ -54,7 +54,12 @@ [DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)] = { i810_swap_bufs, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)] = { i810_copybuf, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I810_OV0INFO)] = { i810_ov0_info, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I810_FSTATUS)] = { i810_fstatus, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I810_OV0FLIP)] = { i810_ov0_flip, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I810_MC)] = { i810_dma_mc, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus, 1, 0 } #define __HAVE_COUNTERS 4 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/i810_drv.h linux.20pre2-ac1/drivers/char/drm/i810_drv.h --- linux.20pre2/drivers/char/drm/i810_drv.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/i810_drv.h 2002-08-06 15:42:07.000000000 +0100 @@ -63,6 +63,7 @@ unsigned long hw_status_page; unsigned long counter; + dma_addr_t dma_status_page; atomic_t flush_done; wait_queue_head_t flush_queue; /* Processes waiting until flush */ @@ -73,6 +74,8 @@ int back_offset; int depth_offset; + int overlay_offset; + int overlay_physical; int w, h; int pitch; } drm_i810_private_t; @@ -94,6 +97,18 @@ extern int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int i810_rstatus(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_ov0_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_fstatus(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_ov0_flip(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i810_dma_mc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + extern void i810_dma_quiescent(drm_device_t *dev); #define I810_VERBOSE 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/i830_dma.c linux.20pre2-ac1/drivers/char/drm/i830_dma.c --- linux.20pre2/drivers/char/drm/i830_dma.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/i830_dma.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,1381 @@ +/* i830_dma.c -- DMA support for the I830 -*- linux-c -*- + * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * Keith Whitwell + * Abraham vd Merwe + * + */ + +#define __NO_VERSION__ +#include "i830.h" +#include "drmP.h" +#include "i830_drv.h" +#include /* For task queue support */ +#include +/* in case we don't have a 2.3.99-pre6 kernel or later: */ +#ifndef VM_DONTCOPY +#define VM_DONTCOPY 0 +#endif + +#define I830_BUF_FREE 2 +#define I830_BUF_CLIENT 1 +#define I830_BUF_HARDWARE 0 + +#define I830_BUF_UNMAPPED 0 +#define I830_BUF_MAPPED 1 + +#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; + + +#define DO_IDLE_WORKAROUND() \ +do { \ + int _head; \ + int _tail; \ + int _i; \ + do { \ + _head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR; \ + _tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR; \ + udelay(1); \ + } while(_head != _tail); \ +} while(0) + +#define I830_SYNC_WORKAROUND 0 + +#define BEGIN_LP_RING(n) do { \ + if (I830_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ + n, __FUNCTION__); \ + if (I830_SYNC_WORKAROUND) \ + DO_IDLE_WORKAROUND(); \ + if (dev_priv->ring.space < n*4) \ + i830_wait_ring(dev, n*4); \ + dev_priv->ring.space -= n*4; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I830_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ + dev_priv->ring.tail = outring; \ + I830_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +#define OUT_RING(n) do { \ + if (I830_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} while (0); + +static inline void i830_print_status_page(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + drm_i830_private_t *dev_priv = dev->dev_private; + u32 *temp = dev_priv->hw_status_page; + int i; + + DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); + DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]); + DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]); + DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]); + DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]); + for(i = 9; i < dma->buf_count + 9; i++) { + DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 9, temp[i]); + } +} + +static drm_buf_t *i830_freelist_get(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i; + int used; + + /* Linear search might not be the best solution */ + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I830_BUF_FREE, + I830_BUF_CLIENT); + if(used == I830_BUF_FREE) { + return buf; + } + } + return NULL; +} + +/* This should only be called if the buffer is not sent to the hardware + * yet, the hardware updates in use for us once its on the ring buffer. + */ + +static int i830_freelist_put(drm_device_t *dev, drm_buf_t *buf) +{ + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + int used; + + /* In use is already a pointer */ + used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE); + if(used != I830_BUF_CLIENT) { + DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); + return -EINVAL; + } + + return 0; +} + +static struct file_operations i830_buffer_fops = { + open: DRM(open), + flush: DRM(flush), + release: DRM(release), + ioctl: DRM(ioctl), + mmap: i830_mmap_buffers, + read: DRM(read), + fasync: DRM(fasync), + poll: DRM(poll), +}; + +int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev; + drm_i830_private_t *dev_priv; + drm_buf_t *buf; + drm_i830_buf_priv_t *buf_priv; + + lock_kernel(); + dev = priv->dev; + dev_priv = dev->dev_private; + buf = dev_priv->mmap_buffer; + buf_priv = buf->dev_private; + + vma->vm_flags |= (VM_IO | VM_DONTCOPY); + vma->vm_file = filp; + + buf_priv->currently_mapped = I830_BUF_MAPPED; + unlock_kernel(); + + if (remap_page_range(vma->vm_start, + VM_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) return -EAGAIN; + return 0; +} + +static int i830_map_buffer(drm_buf_t *buf, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + drm_i830_private_t *dev_priv = dev->dev_private; + struct file_operations *old_fops; + int retcode = 0; + + if(buf_priv->currently_mapped == I830_BUF_MAPPED) return -EINVAL; + + if(VM_DONTCOPY != 0) { +#if LINUX_VERSION_CODE <= 0x020402 + down( ¤t->mm->mmap_sem ); +#else + down_write( ¤t->mm->mmap_sem ); +#endif + old_fops = filp->f_op; + filp->f_op = &i830_buffer_fops; + dev_priv->mmap_buffer = buf; + buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, + PROT_READ|PROT_WRITE, + MAP_SHARED, + buf->bus_address); + dev_priv->mmap_buffer = NULL; + filp->f_op = old_fops; + if ((unsigned long)buf_priv->virtual > -1024UL) { + /* Real error */ + DRM_DEBUG("mmap error\n"); + retcode = (signed int)buf_priv->virtual; + buf_priv->virtual = 0; + } +#if LINUX_VERSION_CODE <= 0x020402 + up( ¤t->mm->mmap_sem ); +#else + up_write( ¤t->mm->mmap_sem ); +#endif + } else { + buf_priv->virtual = buf_priv->kernel_virtual; + buf_priv->currently_mapped = I830_BUF_MAPPED; + } + return retcode; +} + +static int i830_unmap_buffer(drm_buf_t *buf) +{ + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + int retcode = 0; + + if(VM_DONTCOPY != 0) { + if(buf_priv->currently_mapped != I830_BUF_MAPPED) + return -EINVAL; + down_write( ¤t->mm->mmap_sem ); + retcode = do_munmap(current->mm, + (unsigned long)buf_priv->virtual, + (size_t) buf->total, 1); + up_write( ¤t->mm->mmap_sem ); + } + buf_priv->currently_mapped = I830_BUF_UNMAPPED; + buf_priv->virtual = 0; + + return retcode; +} + +static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d, + struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_buf_t *buf; + drm_i830_buf_priv_t *buf_priv; + int retcode = 0; + + buf = i830_freelist_get(dev); + if (!buf) { + retcode = -ENOMEM; + DRM_DEBUG("retcode=%d\n", retcode); + return retcode; + } + + retcode = i830_map_buffer(buf, filp); + if(retcode) { + i830_freelist_put(dev, buf); + DRM_DEBUG("mapbuf failed, retcode %d\n", retcode); + return retcode; + } + buf->pid = priv->pid; + buf_priv = buf->dev_private; + d->granted = 1; + d->request_idx = buf->idx; + d->request_size = buf->total; + d->virtual = buf_priv->virtual; + + return retcode; +} + +static int i830_dma_cleanup(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + + if(dev->dev_private) { + int i; + drm_i830_private_t *dev_priv = + (drm_i830_private_t *) dev->dev_private; + + if(dev_priv->ring.virtual_start) { + DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, + dev_priv->ring.Size); + } + if(dev_priv->hw_status_page != NULL) { + pci_free_consistent(dev->pdev, PAGE_SIZE, + dev_priv->hw_status_page, dev_priv->dma_status_page); + /* Need to rewrite hardware status page */ + I830_WRITE(0x02080, 0x1ffff000); + } + DRM(free)(dev->dev_private, sizeof(drm_i830_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total); + } + } + return 0; +} + +static int i830_wait_ring(drm_device_t *dev, int n) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_ring_buffer_t *ring = &(dev_priv->ring); + int iters = 0; + unsigned long end; + unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + + end = jiffies + (HZ*3); + while (ring->space < n) { + int i; + + ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; + + if (ring->head != last_head) { + end = jiffies + (HZ*3); + last_head = ring->head; + } + + iters++; + if(time_before(end,jiffies)) { + DRM_ERROR("space: %d wanted %d\n", ring->space, n); + DRM_ERROR("lockup\n"); + goto out_wait_ring; + } + + udelay(1); + } + +out_wait_ring: + return iters; +} + +static void i830_kernel_lost_context(drm_device_t *dev) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_ring_buffer_t *ring = &(dev_priv->ring); + + ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->tail = I830_READ(LP_RING + RING_TAIL); + ring->space = ring->head - (ring->tail+8); + if (ring->space < 0) ring->space += ring->Size; +} + +static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv) +{ + drm_device_dma_t *dma = dev->dma; + int my_idx = 36; + u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx); + int i; + + if(dma->buf_count > 1019) { + /* Not enough space in the status page for the freelist */ + return -EINVAL; + } + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + + buf_priv->in_use = hw_status++; + buf_priv->my_use_idx = my_idx; + my_idx += 4; + + *buf_priv->in_use = I830_BUF_FREE; + + buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, + buf->total); + } + return 0; +} + +static int i830_dma_initialize(drm_device_t *dev, + drm_i830_private_t *dev_priv, + drm_i830_init_t *init) +{ + struct list_head *list; + + memset(dev_priv, 0, sizeof(drm_i830_private_t)); + + list_for_each(list, &dev->maplist->head) { + drm_map_list_t *r_list = (drm_map_list_t *)list; + if( r_list->map && + r_list->map->type == _DRM_SHM && + r_list->map->flags & _DRM_CONTAINS_LOCK ) { + dev_priv->sarea_map = r_list->map; + break; + } + } + + if(!dev_priv->sarea_map) { + dev->dev_private = (void *)dev_priv; + i830_dma_cleanup(dev); + DRM_ERROR("can not find sarea!\n"); + return -EINVAL; + } + DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset ); + if(!dev_priv->mmio_map) { + dev->dev_private = (void *)dev_priv; + i830_dma_cleanup(dev); + DRM_ERROR("can not find mmio map!\n"); + return -EINVAL; + } + DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset ); + if(!dev_priv->buffer_map) { + dev->dev_private = (void *)dev_priv; + i830_dma_cleanup(dev); + DRM_ERROR("can not find dma buffer map!\n"); + return -EINVAL; + } + + dev_priv->sarea_priv = (drm_i830_sarea_t *) + ((u8 *)dev_priv->sarea_map->handle + + init->sarea_priv_offset); + + atomic_set(&dev_priv->flush_done, 0); + init_waitqueue_head(&dev_priv->flush_queue); + + dev_priv->ring.Start = init->ring_start; + dev_priv->ring.End = init->ring_end; + dev_priv->ring.Size = init->ring_size; + + dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + + init->ring_start, + init->ring_size); + + if (dev_priv->ring.virtual_start == NULL) { + dev->dev_private = (void *) dev_priv; + i830_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; + } + + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + dev_priv->w = init->w; + dev_priv->h = init->h; + dev_priv->pitch = init->pitch; + dev_priv->back_offset = init->back_offset; + dev_priv->depth_offset = init->depth_offset; + + dev_priv->front_di1 = init->front_offset | init->pitch_bits; + dev_priv->back_di1 = init->back_offset | init->pitch_bits; + dev_priv->zi1 = init->depth_offset | init->pitch_bits; + + dev_priv->cpp = init->cpp; + /* We are using seperate values as placeholders for mechanisms for + * private backbuffer/depthbuffer usage. + */ + + dev_priv->back_pitch = init->back_pitch; + dev_priv->depth_pitch = init->depth_pitch; + + /* Program Hardware Status Page */ + dev_priv->hw_status_page = pci_alloc_consistent(dev->pdev, PAGE_SIZE, + &dev_priv->dma_status_page); + if(dev_priv->hw_status_page == NULL) { + dev->dev_private = (void *)dev_priv; + i830_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return -ENOMEM; + } + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + + I830_WRITE(0x02080, dev_priv->dma_status_page); + DRM_DEBUG("Enabled hardware status page\n"); + + /* Now we need to init our freelist */ + if(i830_freelist_init(dev, dev_priv) != 0) { + dev->dev_private = (void *)dev_priv; + i830_dma_cleanup(dev); + DRM_ERROR("Not enough space in the status page for" + " the freelist\n"); + return -ENOMEM; + } + dev->dev_private = (void *)dev_priv; + + return 0; +} + +int i830_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_private_t *dev_priv; + drm_i830_init_t init; + int retcode = 0; + + if (copy_from_user(&init, (drm_i830_init_t *)arg, sizeof(init))) + return -EFAULT; + + switch(init.func) { + case I830_INIT_DMA: + dev_priv = DRM(alloc)(sizeof(drm_i830_private_t), + DRM_MEM_DRIVER); + if(dev_priv == NULL) return -ENOMEM; + retcode = i830_dma_initialize(dev, dev_priv, &init); + break; + case I830_CLEANUP_DMA: + retcode = i830_dma_cleanup(dev); + break; + default: + retcode = -EINVAL; + break; + } + + return retcode; +} + +/* Most efficient way to verify state for the i830 is as it is + * emitted. Non-conformant state is silently dropped. + * + * Use 'volatile' & local var tmp to force the emitted values to be + * identical to the verified ones. + */ +static void i830EmitContextVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + int i, j = 0; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I830_CTX_SETUP_SIZE ); + for ( i = 0 ; i < I830_CTX_SETUP_SIZE ; i++ ) { + tmp = code[i]; + +#if 0 + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) { + OUT_RING( tmp ); + j++; + } else { + printk("Skipping %d\n", i); + } +#else + OUT_RING( tmp ); + j++; +#endif + } + + if (j & 1) + OUT_RING( 0 ); + + ADVANCE_LP_RING(); +} + +static void i830EmitTexVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + int i, j = 0; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I830_TEX_SETUP_SIZE ); + + OUT_RING( GFX_OP_MAP_INFO ); + OUT_RING( code[I830_TEXREG_MI1] ); + OUT_RING( code[I830_TEXREG_MI2] ); + OUT_RING( code[I830_TEXREG_MI3] ); + OUT_RING( code[I830_TEXREG_MI4] ); + OUT_RING( code[I830_TEXREG_MI5] ); + + for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) { + tmp = code[i]; + OUT_RING( tmp ); + j++; + } + + if (j & 1) + OUT_RING( 0 ); + + ADVANCE_LP_RING(); +} + +static void i830EmitTexBlendVerified( drm_device_t *dev, + volatile unsigned int *code, + volatile unsigned int num) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + int i, j = 0; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( num ); + + for ( i = 0 ; i < num ; i++ ) { + tmp = code[i]; + OUT_RING( tmp ); + j++; + } + + if (j & 1) + OUT_RING( 0 ); + + ADVANCE_LP_RING(); +} + +static void i830EmitTexPalette( drm_device_t *dev, + unsigned int *palette, + int number, + int is_shared ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + int i; + RING_LOCALS; + + BEGIN_LP_RING( 258 ); + + if(is_shared == 1) { + OUT_RING(CMD_OP_MAP_PALETTE_LOAD | + MAP_PALETTE_NUM(0) | + MAP_PALETTE_BOTH); + } else { + OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number)); + } + for(i = 0; i < 256; i++) { + OUT_RING(palette[i]); + } + OUT_RING(0); +} + +/* Need to do some additional checking when setting the dest buffer. + */ +static void i830EmitDestVerified( drm_device_t *dev, + volatile unsigned int *code ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + unsigned int tmp; + RING_LOCALS; + + BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 6 ); + + tmp = code[I830_DESTREG_CBUFADDR]; + if (tmp == dev_priv->front_di1) { + /* Don't use fence when front buffer rendering */ + OUT_RING( CMD_OP_DESTBUFFER_INFO ); + OUT_RING( BUF_3D_ID_COLOR_BACK | + BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) ); + OUT_RING( tmp ); + + OUT_RING( CMD_OP_DESTBUFFER_INFO ); + OUT_RING( BUF_3D_ID_DEPTH | + BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp)); + OUT_RING( dev_priv->zi1 ); + } else if(tmp == dev_priv->back_di1) { + OUT_RING( CMD_OP_DESTBUFFER_INFO ); + OUT_RING( BUF_3D_ID_COLOR_BACK | + BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) | + BUF_3D_USE_FENCE); + OUT_RING( tmp ); + + OUT_RING( CMD_OP_DESTBUFFER_INFO ); + OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE | + BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp)); + OUT_RING( dev_priv->zi1 ); + } else { + DRM_DEBUG("bad di1 %x (allow %x or %x)\n", + tmp, dev_priv->front_di1, dev_priv->back_di1); + } + + /* invarient: + */ + + + OUT_RING( GFX_OP_DESTBUFFER_VARS ); + OUT_RING( code[I830_DESTREG_DV1] ); + + OUT_RING( GFX_OP_DRAWRECT_INFO ); + OUT_RING( code[I830_DESTREG_DR1] ); + OUT_RING( code[I830_DESTREG_DR2] ); + OUT_RING( code[I830_DESTREG_DR3] ); + OUT_RING( code[I830_DESTREG_DR4] ); + + /* Need to verify this */ + tmp = code[I830_DESTREG_SENABLE]; + if((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) { + OUT_RING( tmp ); + } else { + DRM_DEBUG("bad scissor enable\n"); + OUT_RING( 0 ); + } + + OUT_RING( code[I830_DESTREG_SENABLE] ); + + OUT_RING( GFX_OP_SCISSOR_RECT ); + OUT_RING( code[I830_DESTREG_SR1] ); + OUT_RING( code[I830_DESTREG_SR2] ); + + ADVANCE_LP_RING(); +} + +static void i830EmitState( drm_device_t *dev ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + + if (dirty & I830_UPLOAD_BUFFERS) { + i830EmitDestVerified( dev, sarea_priv->BufferState ); + sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS; + } + + if (dirty & I830_UPLOAD_CTX) { + i830EmitContextVerified( dev, sarea_priv->ContextState ); + sarea_priv->dirty &= ~I830_UPLOAD_CTX; + } + + if (dirty & I830_UPLOAD_TEX0) { + i830EmitTexVerified( dev, sarea_priv->TexState[0] ); + sarea_priv->dirty &= ~I830_UPLOAD_TEX0; + } + + if (dirty & I830_UPLOAD_TEX1) { + i830EmitTexVerified( dev, sarea_priv->TexState[1] ); + sarea_priv->dirty &= ~I830_UPLOAD_TEX1; + } + + if (dirty & I830_UPLOAD_TEXBLEND0) { + i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[0], + sarea_priv->TexBlendStateWordsUsed[0]); + sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND0; + } + + if (dirty & I830_UPLOAD_TEXBLEND1) { + i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[1], + sarea_priv->TexBlendStateWordsUsed[1]); + sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND1; + } + + if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) { + i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1); + } else { + if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) { + i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0); + sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0); + } + if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) { + i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0); + sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1); + } + } +} + +static void i830_dma_dispatch_clear( drm_device_t *dev, int flags, + unsigned int clear_color, + unsigned int clear_zval, + unsigned int clear_depthmask) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int pitch = dev_priv->pitch; + int cpp = dev_priv->cpp; + int i; + unsigned int BR13, CMD, D_CMD; + RING_LOCALS; + + i830_kernel_lost_context(dev); + + switch(cpp) { + case 2: + BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24); + D_CMD = CMD = XY_COLOR_BLT_CMD; + break; + case 4: + BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25); + CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA | + XY_COLOR_BLT_WRITE_RGB); + D_CMD = XY_COLOR_BLT_CMD; + if(clear_depthmask & 0x00ffffff) + D_CMD |= XY_COLOR_BLT_WRITE_RGB; + if(clear_depthmask & 0xff000000) + D_CMD |= XY_COLOR_BLT_WRITE_ALPHA; + break; + default: + BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24); + D_CMD = CMD = XY_COLOR_BLT_CMD; + break; + } + + if (nbox > I830_NR_SAREA_CLIPRECTS) + nbox = I830_NR_SAREA_CLIPRECTS; + + for (i = 0 ; i < nbox ; i++, pbox++) { + if (pbox->x1 > pbox->x2 || + pbox->y1 > pbox->y2 || + pbox->x2 > dev_priv->w || + pbox->y2 > dev_priv->h) + continue; + + if ( flags & I830_FRONT ) { + DRM_DEBUG("clear front\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( CMD ); + OUT_RING( BR13 ); + OUT_RING( (pbox->y1 << 16) | pbox->x1 ); + OUT_RING( (pbox->y2 << 16) | pbox->x2 ); + OUT_RING( 0 ); + OUT_RING( clear_color ); + ADVANCE_LP_RING(); + } + + if ( flags & I830_BACK ) { + DRM_DEBUG("clear back\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( CMD ); + OUT_RING( BR13 ); + OUT_RING( (pbox->y1 << 16) | pbox->x1 ); + OUT_RING( (pbox->y2 << 16) | pbox->x2 ); + OUT_RING( dev_priv->back_offset ); + OUT_RING( clear_color ); + ADVANCE_LP_RING(); + } + + if ( flags & I830_DEPTH ) { + DRM_DEBUG("clear depth\n"); + BEGIN_LP_RING( 6 ); + OUT_RING( D_CMD ); + OUT_RING( BR13 ); + OUT_RING( (pbox->y1 << 16) | pbox->x1 ); + OUT_RING( (pbox->y2 << 16) | pbox->x2 ); + OUT_RING( dev_priv->depth_offset ); + OUT_RING( clear_zval ); + ADVANCE_LP_RING(); + } + } +} + +static void i830_dma_dispatch_swap( drm_device_t *dev ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; + int nbox = sarea_priv->nbox; + drm_clip_rect_t *pbox = sarea_priv->boxes; + int pitch = dev_priv->pitch; + int cpp = dev_priv->cpp; + int ofs = dev_priv->back_offset; + int i; + unsigned int CMD, BR13; + RING_LOCALS; + + DRM_DEBUG("swapbuffers\n"); + + switch(cpp) { + case 2: + BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24); + CMD = XY_SRC_COPY_BLT_CMD; + break; + case 4: + BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25); + CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + break; + default: + BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24); + CMD = XY_SRC_COPY_BLT_CMD; + break; + } + + i830_kernel_lost_context(dev); + + if (nbox > I830_NR_SAREA_CLIPRECTS) + nbox = I830_NR_SAREA_CLIPRECTS; + + for (i = 0 ; i < nbox; i++, pbox++) + { + if (pbox->x1 > pbox->x2 || + pbox->y1 > pbox->y2 || + pbox->x2 > dev_priv->w || + pbox->y2 > dev_priv->h) + continue; + + DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", + pbox->x1, pbox->y1, + pbox->x2, pbox->y2); + + BEGIN_LP_RING( 8 ); + OUT_RING( CMD ); + OUT_RING( BR13 ); + + OUT_RING( (pbox->y1 << 16) | + pbox->x1 ); + OUT_RING( (pbox->y2 << 16) | + pbox->x2 ); + + OUT_RING( 0 /* front ofs always zero */ ); + OUT_RING( (pbox->y1 << 16) | + pbox->x1 ); + + OUT_RING( BR13 & 0xffff ); + OUT_RING( ofs ); + + ADVANCE_LP_RING(); + } +} + + +static void i830_dma_dispatch_vertex(drm_device_t *dev, + drm_buf_t *buf, + int discard, + int used) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_clip_rect_t *box = sarea_priv->boxes; + int nbox = sarea_priv->nbox; + unsigned long address = (unsigned long)buf->bus_address; + unsigned long start = address - dev->agp->base; + int i = 0, u; + RING_LOCALS; + + i830_kernel_lost_context(dev); + + if (nbox > I830_NR_SAREA_CLIPRECTS) + nbox = I830_NR_SAREA_CLIPRECTS; + + if (discard) { + u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, + I830_BUF_HARDWARE); + if(u != I830_BUF_CLIENT) { + DRM_DEBUG("xxxx 2\n"); + } + } + + if (used > 4*1024) + used = 0; + + if (sarea_priv->dirty) + i830EmitState( dev ); + + DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", + address, used, nbox); + + dev_priv->counter++; + DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter); + DRM_DEBUG( "i830_dma_dispatch\n"); + DRM_DEBUG( "start : %lx\n", start); + DRM_DEBUG( "used : %d\n", used); + DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4); + + if (buf_priv->currently_mapped == I830_BUF_MAPPED) { + *(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE | + sarea_priv->vertex_prim | + ((used/4)-2)); + + if (used & 4) { + *(u32 *)((u32)buf_priv->virtual + used) = 0; + used += 4; + } + + i830_unmap_buffer(buf); + } + + if (used) { + do { + if (i < nbox) { + BEGIN_LP_RING(6); + OUT_RING( GFX_OP_DRAWRECT_INFO ); + OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR1] ); + OUT_RING( box[i].x1 | (box[i].y1<<16) ); + OUT_RING( box[i].x2 | (box[i].y2<<16) ); + OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR4] ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + } + + BEGIN_LP_RING(4); + + OUT_RING( MI_BATCH_BUFFER ); + OUT_RING( start | MI_BATCH_NON_SECURE ); + OUT_RING( start + used - 4 ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + } while (++i < nbox); + } + + BEGIN_LP_RING(10); + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( 20 ); + OUT_RING( dev_priv->counter ); + OUT_RING( 0 ); + + if (discard) { + OUT_RING( CMD_STORE_DWORD_IDX ); + OUT_RING( buf_priv->my_use_idx ); + OUT_RING( I830_BUF_FREE ); + OUT_RING( 0 ); + } + + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); +} + +/* Interrupts are only for flushing */ +void i830_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + u16 temp; + + temp = I830_READ16(I830REG_INT_IDENTITY_R); + temp = temp & ~(0x6000); + if(temp != 0) I830_WRITE16(I830REG_INT_IDENTITY_R, + temp); /* Clear all interrupts */ + else + return; + + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +void DRM(dma_immediate_bh)(void *device) +{ + drm_device_t *dev = (drm_device_t *) device; + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + + atomic_set(&dev_priv->flush_done, 1); + wake_up_interruptible(&dev_priv->flush_queue); +} + +static inline void i830_dma_emit_flush(drm_device_t *dev) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i830_kernel_lost_context(dev); + + BEGIN_LP_RING(2); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); + + i830_wait_ring( dev, dev_priv->ring.Size - 8 ); + atomic_set(&dev_priv->flush_done, 1); + wake_up_interruptible(&dev_priv->flush_queue); +} + +static inline void i830_dma_quiescent_emit(drm_device_t *dev) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i830_kernel_lost_context(dev); + + BEGIN_LP_RING(4); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); + + i830_wait_ring( dev, dev_priv->ring.Size - 8 ); + atomic_set(&dev_priv->flush_done, 1); + wake_up_interruptible(&dev_priv->flush_queue); +} + +void i830_dma_quiescent(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + unsigned long end; + + if(dev_priv == NULL) { + return; + } + atomic_set(&dev_priv->flush_done, 0); + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + + for (;;) { + current->state = TASK_INTERRUPTIBLE; + i830_dma_quiescent_emit(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if(time_before(end, jiffies)) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + return; +} + +static int i830_flush_queue(drm_device_t *dev) +{ + DECLARE_WAITQUEUE(entry, current); + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; + unsigned long end; + int i, ret = 0; + + if(dev_priv == NULL) { + return 0; + } + atomic_set(&dev_priv->flush_done, 0); + add_wait_queue(&dev_priv->flush_queue, &entry); + end = jiffies + (HZ*3); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + i830_dma_emit_flush(dev); + if (atomic_read(&dev_priv->flush_done) == 1) break; + if(time_before(end, jiffies)) { + DRM_ERROR("lockup\n"); + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->flush_queue, &entry); + + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + + int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE, + I830_BUF_FREE); + + if (used == I830_BUF_HARDWARE) + DRM_DEBUG("reclaimed from HARDWARE\n"); + if (used == I830_BUF_CLIENT) + DRM_DEBUG("still on client HARDWARE\n"); + } + + return ret; +} + +/* Must be called with the lock held */ +void i830_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + if (!dev->dev_private) return; + if (!dma->buflist) return; + + i830_flush_queue(dev); + + for (i = 0; i < dma->buf_count; i++) { + drm_buf_t *buf = dma->buflist[ i ]; + drm_i830_buf_priv_t *buf_priv = buf->dev_private; + + if (buf->pid == pid && buf_priv) { + int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, + I830_BUF_FREE); + + if (used == I830_BUF_CLIENT) + DRM_DEBUG("reclaimed from client\n"); + if(buf_priv->currently_mapped == I830_BUF_MAPPED) + buf_priv->currently_mapped = I830_BUF_UNMAPPED; + } + } +} + +int i830_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + DRM_DEBUG("i830_flush_ioctl\n"); + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i830_flush_ioctl called without lock held\n"); + return -EINVAL; + } + + i830_flush_queue(dev); + return 0; +} + +int i830_dma_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) + dev_priv->sarea_priv; + drm_i830_vertex_t vertex; + + if (copy_from_user(&vertex, (drm_i830_vertex_t *)arg, sizeof(vertex))) + return -EFAULT; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i830_dma_vertex called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n", + vertex.idx, vertex.used, vertex.discard); + + if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL; + + i830_dma_dispatch_vertex( dev, + dma->buflist[ vertex.idx ], + vertex.discard, vertex.used ); + + sarea_priv->last_enqueue = dev_priv->counter-1; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return 0; +} + +int i830_clear_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_clear_t clear; + + if (copy_from_user(&clear, (drm_i830_clear_t *)arg, sizeof(clear))) + return -EFAULT; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i830_clear_bufs called without lock held\n"); + return -EINVAL; + } + + /* GH: Someone's doing nasty things... */ + if (!dev->dev_private) { + return -EINVAL; + } + + i830_dma_dispatch_clear( dev, clear.flags, + clear.clear_color, + clear.clear_depth, + clear.clear_depthmask); + return 0; +} + +int i830_swap_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + DRM_DEBUG("i830_swap_bufs\n"); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i830_swap_buf called without lock held\n"); + return -EINVAL; + } + + i830_dma_dispatch_swap( dev ); + return 0; +} + +int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) + dev_priv->sarea_priv; + + sarea_priv->last_dispatch = (int) hw_status[5]; + return 0; +} + +int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + drm_i830_dma_t d; + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) + dev_priv->sarea_priv; + + DRM_DEBUG("getbuf\n"); + if (copy_from_user(&d, (drm_i830_dma_t *)arg, sizeof(d))) + return -EFAULT; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i830_dma called without lock held\n"); + return -EINVAL; + } + + d.granted = 0; + + retcode = i830_dma_get_buffer(dev, &d, filp); + + DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n", + current->pid, retcode, d.granted); + + if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d))) + return -EFAULT; + sarea_priv->last_dispatch = (int) hw_status[5]; + + return retcode; +} + +int i830_copybuf(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_copy_t d; + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + u32 *hw_status = (u32 *)dev_priv->hw_status_page; + drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) + dev_priv->sarea_priv; + drm_buf_t *buf; + drm_i830_buf_priv_t *buf_priv; + drm_device_dma_t *dma = dev->dma; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i830_dma called without lock held\n"); + return -EINVAL; + } + + if (copy_from_user(&d, (drm_i830_copy_t *)arg, sizeof(d))) + return -EFAULT; + + if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL; + buf = dma->buflist[ d.idx ]; + buf_priv = buf->dev_private; + if (buf_priv->currently_mapped != I830_BUF_MAPPED) return -EPERM; + + if(d.used < 0 || d.used > buf->total) return -EINVAL; + + if (copy_from_user(buf_priv->virtual, d.address, d.used)) + return -EFAULT; + + sarea_priv->last_dispatch = (int) hw_status[5]; + + return 0; +} + +int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + if(VM_DONTCOPY == 0) return 1; + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/i830_drm.h linux.20pre2-ac1/drivers/char/drm/i830_drm.h --- linux.20pre2/drivers/char/drm/i830_drm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/i830_drm.h 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,238 @@ +#ifndef _I830_DRM_H_ +#define _I830_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +#ifndef _I830_DEFINES_ +#define _I830_DEFINES_ + +#define I830_DMA_BUF_ORDER 12 +#define I830_DMA_BUF_SZ (1< + * Jeff Hartmann + * Gareth Hughes + * Abraham vd Merwe + */ + +#include +#include "i830.h" +#include "drmP.h" +#include "i830_drv.h" + +#define DRIVER_AUTHOR "VA Linux Systems Inc." + +#define DRIVER_NAME "i830" +#define DRIVER_DESC "Intel 830M" +#define DRIVER_DATE "20011004" + +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 2 +#define DRIVER_PATCHLEVEL 0 + +#define DRIVER_IOCTLS \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_INIT)] = { i830_dma_init, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_VERTEX)] = { i830_dma_vertex, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_CLEAR)] = { i830_clear_bufs, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_FLUSH)] = { i830_flush_ioctl, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_GETAGE)] = { i830_getage, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_GETBUF)] = { i830_getbuf, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_SWAP)] = { i830_swap_bufs, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_COPY)] = { i830_copybuf, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_DOCOPY)] = { i830_docopy, 1, 0 }, + +#define __HAVE_COUNTERS 4 +#define __HAVE_COUNTER6 _DRM_STAT_IRQ +#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY +#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY +#define __HAVE_COUNTER9 _DRM_STAT_DMA + + +#include "drm_agpsupport.h" +#include "drm_auth.h" +#include "drm_bufs.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_drv.h" + +#ifndef MODULE +/* DRM(options) is called by the kernel to parse command-line options + * passed via the boot-loader (e.g., LILO). It calls the insmod option + * routine, drm_parse_drm. + */ + +/* JH- We have to hand expand the string ourselves because of the cpp. If + * anyone can think of a way that we can fit into the __setup macro without + * changing it, then please send the solution my way. + */ +static int __init i830_options( char *str ) +{ + DRM(parse_options)( str ); + return 1; +} + +__setup( DRIVER_NAME "=", i830_options ); +#endif + +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lock.h" +#include "drm_lists.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/i830_drv.h linux.20pre2-ac1/drivers/char/drm/i830_drv.h --- linux.20pre2/drivers/char/drm/i830_drv.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/i830_drv.h 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,215 @@ +/* i830_drv.h -- Private header for the I830 driver -*- linux-c -*- + * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith + * Jeff Hartmann + * + */ + +#ifndef _I830_DRV_H_ +#define _I830_DRV_H_ + +typedef struct drm_i830_buf_priv { + u32 *in_use; + int my_use_idx; + int currently_mapped; + void *virtual; + void *kernel_virtual; + int map_count; + struct vm_area_struct *vma; +} drm_i830_buf_priv_t; + +typedef struct _drm_i830_ring_buffer{ + int tail_mask; + unsigned long Start; + unsigned long End; + unsigned long Size; + u8 *virtual_start; + int head; + int tail; + int space; +} drm_i830_ring_buffer_t; + +typedef struct drm_i830_private { + drm_map_t *sarea_map; + drm_map_t *buffer_map; + drm_map_t *mmio_map; + + drm_i830_sarea_t *sarea_priv; + drm_i830_ring_buffer_t ring; + + u8 *hw_status_page; + unsigned long counter; + + dma_addr_t dma_status_page; + + atomic_t flush_done; + wait_queue_head_t flush_queue; /* Processes waiting until flush */ + drm_buf_t *mmap_buffer; + + u32 front_di1, back_di1, zi1; + + int back_offset; + int depth_offset; + int w, h; + int pitch; + int back_pitch; + int depth_pitch; + unsigned int cpp; +} drm_i830_private_t; + + /* i830_dma.c */ +extern int i830_dma_schedule(drm_device_t *dev, int locked); +extern int i830_getbuf(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i830_dma_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i830_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void i830_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma); +extern int i830_copybuf(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int i830_docopy(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern void i830_dma_quiescent(drm_device_t *dev); + +extern int i830_dma_vertex(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int i830_swap_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int i830_clear_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +#define I830_VERBOSE 0 + +#define I830_BASE(reg) ((unsigned long) \ + dev_priv->mmio_map->handle) +#define I830_ADDR(reg) (I830_BASE(reg) + reg) +#define I830_DEREF(reg) *(__volatile__ int *)I830_ADDR(reg) +#define I830_READ(reg) I830_DEREF(reg) +#define I830_WRITE(reg,val) do { I830_DEREF(reg) = val; } while (0) +#define I830_DEREF16(reg) *(__volatile__ u16 *)I830_ADDR(reg) +#define I830_READ16(reg) I830_DEREF16(reg) +#define I830_WRITE16(reg,val) do { I830_DEREF16(reg) = val; } while (0) + +#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) +#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) +#define CMD_REPORT_HEAD (7<<23) +#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) +#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) + +#define INST_PARSER_CLIENT 0x00000000 +#define INST_OP_FLUSH 0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + + +#define BB1_START_ADDR_MASK (~0x7) +#define BB1_PROTECTED (1<<0) +#define BB1_UNPROTECTED (0<<0) +#define BB2_END_ADDR_MASK (~0x7) + +#define I830REG_HWSTAM 0x02098 +#define I830REG_INT_IDENTITY_R 0x020a4 +#define I830REG_INT_MASK_R 0x020a8 +#define I830REG_INT_ENABLE_R 0x020a0 + +#define LP_RING 0x2030 +#define HP_RING 0x2040 +#define RING_TAIL 0x00 +#define TAIL_ADDR 0x000FFFF8 +#define RING_HEAD 0x04 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_START 0x08 +#define START_ADDR 0x00FFFFF8 +#define RING_LEN 0x0C +#define RING_NR_PAGES 0x000FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 + +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) + +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) + +#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) +#define GFX_OP_PRIMITIVE ((0x3<<29)|(0x1f<<24)) + +#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) + + +#define BR00_BITBLT_CLIENT 0x40000000 +#define BR00_OP_COLOR_BLT 0x10000000 +#define BR00_OP_SRC_COPY_BLT 0x10C00000 +#define BR13_SOLID_PATTERN 0x80000000 + +#define BUF_3D_ID_COLOR_BACK (0x3<<24) +#define BUF_3D_ID_DEPTH (0x7<<24) +#define BUF_3D_USE_FENCE (1<<23) +#define BUF_3D_PITCH(x) (((x)/4)<<2) + +#define CMD_OP_MAP_PALETTE_LOAD ((3<<29)|(0x1d<<24)|(0x82<<16)|255) +#define MAP_PALETTE_NUM(x) ((x<<8) & (1<<8)) +#define MAP_PALETTE_BOTH (1<<11) + +#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|0x4) +#define XY_COLOR_BLT_WRITE_ALPHA (1<<21) +#define XY_COLOR_BLT_WRITE_RGB (1<<20) + +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) + +#define MI_BATCH_BUFFER ((0x30<<23)|1) +#define MI_BATCH_NON_SECURE (1) + + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/i830.h linux.20pre2-ac1/drivers/char/drm/i830.h --- linux.20pre2/drivers/char/drm/i830.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/i830.h 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,116 @@ +/* i830.h -- Intel I830 DRM template customization -*- linux-c -*- + * Created: Thu Feb 15 00:01:12 2001 by gareth@valinux.com + * + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + * Gareth Hughes + */ + +#ifndef __I830_H__ +#define __I830_H__ + +/* This remains constant for all DRM template files. + */ +#define DRM(x) i830_##x + +/* General customization: + */ +#define __HAVE_AGP 1 +#define __MUST_HAVE_AGP 1 +#define __HAVE_MTRR 1 +#define __HAVE_CTX_BITMAP 1 + +/* Driver customization: + */ +#define __HAVE_RELEASE 1 +#define DRIVER_RELEASE() do { \ + i830_reclaim_buffers( dev, priv->pid ); \ +} while (0) + +/* DMA customization: + */ +#define __HAVE_DMA 1 +#define __HAVE_DMA_QUEUE 1 +#define __HAVE_DMA_WAITLIST 1 +#define __HAVE_DMA_RECLAIM 1 + +#define __HAVE_DMA_QUIESCENT 1 +#define DRIVER_DMA_QUIESCENT() do { \ + i830_dma_quiescent( dev ); \ +} while (0) + +#define __HAVE_DMA_IRQ 1 +#define __HAVE_DMA_IRQ_BH 1 +#define __HAVE_SHARED_IRQ 1 +#define DRIVER_PREINSTALL() do { \ + drm_i830_private_t *dev_priv = \ + (drm_i830_private_t *)dev->dev_private; \ + u16 tmp; \ + tmp = I830_READ16( I830REG_HWSTAM ); \ + tmp = tmp & 0x6000; \ + I830_WRITE16( I830REG_HWSTAM, tmp ); \ + \ + tmp = I830_READ16( I830REG_INT_MASK_R ); \ + tmp = tmp & 0x6000; /* Unmask interrupts */ \ + I830_WRITE16( I830REG_INT_MASK_R, tmp ); \ + tmp = I830_READ16( I830REG_INT_ENABLE_R ); \ + tmp = tmp & 0x6000; /* Disable all interrupts */ \ + I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \ +} while (0) + +#define DRIVER_POSTINSTALL() do { \ + drm_i830_private_t *dev_priv = \ + (drm_i830_private_t *)dev->dev_private; \ + u16 tmp; \ + tmp = I830_READ16( I830REG_INT_ENABLE_R ); \ + tmp = tmp & 0x6000; \ + tmp = tmp | 0x0003; /* Enable bp & user interrupts */ \ + I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \ +} while (0) + +#define DRIVER_UNINSTALL() do { \ + drm_i830_private_t *dev_priv = \ + (drm_i830_private_t *)dev->dev_private; \ + u16 tmp; \ + if ( dev_priv ) { \ + tmp = I830_READ16( I830REG_INT_IDENTITY_R ); \ + tmp = tmp & ~(0x6000); /* Clear all interrupts */ \ + if ( tmp != 0 ) \ + I830_WRITE16( I830REG_INT_IDENTITY_R, tmp ); \ + \ + tmp = I830_READ16( I830REG_INT_ENABLE_R ); \ + tmp = tmp & 0x6000; /* Disable all interrupts */ \ + I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \ + } \ +} while (0) + +/* Buffer customization: + */ + +#define DRIVER_BUF_PRIV_T drm_i830_buf_priv_t + +#define DRIVER_AGP_BUFFERS_MAP( dev ) \ + ((drm_i830_private_t *)((dev)->dev_private))->buffer_map + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/Makefile linux.20pre2-ac1/drivers/char/drm/Makefile --- linux.20pre2/drivers/char/drm/Makefile 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/Makefile 2002-08-06 15:42:07.000000000 +0100 @@ -3,13 +3,15 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. O_TARGET := drm.o -list-multi := gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o sis.o +list-multi := gamma.o tdfx.o r128.o mga.o i810.o i830.o radeon.o ffb.o sis.o gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o i810-objs := i810_drv.o i810_dma.o +i830-objs := i830_drv.o i830_dma.o + radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o ffb-objs := ffb_drv.o ffb_context.o sis-objs := sis_drv.o sis_ds.o sis_mm.o @@ -20,6 +22,7 @@ obj-$(CONFIG_DRM_RADEON)+= radeon.o obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o +obj-$(CONFIG_DRM_I830) += i830.o obj-$(CONFIG_DRM_FFB) += ffb.o obj-$(CONFIG_DRM_SIS) += sis.o @@ -37,6 +40,9 @@ i810.o: $(i810-objs) $(lib) $(LD) -r -o $@ $(i810-objs) $(lib) +i830.o: $(i830-objs) $(lib) + $(LD) -r -o $@ $(i830-objs) $(lib) + r128.o: $(r128-objs) $(lib) $(LD) -r -o $@ $(r128-objs) $(lib) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/mga_drv.h linux.20pre2-ac1/drivers/char/drm/mga_drv.h --- linux.20pre2/drivers/char/drm/mga_drv.h 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/mga_drv.h 2002-08-13 14:21:16.000000000 +0100 @@ -213,7 +213,7 @@ } else if ( dev_priv->prim.space < \ dev_priv->prim.high_mark ) { \ if ( MGA_DMA_DEBUG ) \ - DRM_INFO( __FUNCTION__": wrap...\n" ); \ + DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \ return -EBUSY; \ } \ } \ @@ -224,7 +224,7 @@ if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \ if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \ if ( MGA_DMA_DEBUG ) \ - DRM_INFO( __FUNCTION__": wrap...\n" ); \ + DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \ return -EBUSY; \ } \ mga_do_dma_wrap_end( dev_priv ); \ @@ -276,7 +276,7 @@ #define FLUSH_DMA() \ do { \ if ( 0 ) { \ - DRM_INFO( __FUNCTION__ ":\n" ); \ + DRM_INFO( "%s:\n" , __FUNCTION__); \ DRM_INFO( " tail=0x%06x head=0x%06lx\n", \ dev_priv->prim.tail, \ MGA_READ( MGA_PRIMADDRESS ) - \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/mga_state.c linux.20pre2-ac1/drivers/char/drm/mga_state.c --- linux.20pre2/drivers/char/drm/mga_state.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/mga_state.c 2002-08-06 15:42:07.000000000 +0100 @@ -513,7 +513,7 @@ int nbox = sarea_priv->nbox; int i; DMA_LOCALS; - DRM_DEBUG( __FUNCTION__ ":\n" ); + DRM_DEBUG("%s:\n" , __FUNCTION__); BEGIN_DMA( 1 ); @@ -607,7 +607,7 @@ int nbox = sarea_priv->nbox; int i; DMA_LOCALS; - DRM_DEBUG( __FUNCTION__ ":\n" ); + DRM_DEBUG( "%s:\n", __FUNCTION__ ); sarea_priv->last_frame.head = dev_priv->prim.tail; sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap; @@ -816,7 +816,7 @@ int nbox = sarea_priv->nbox; u32 scandir = 0, i; DMA_LOCALS; - DRM_DEBUG( __FUNCTION__ ":\n" ); + DRM_DEBUG( "%s:\n", __FUNCTION__ ); BEGIN_DMA( 4 + nbox ); @@ -1019,7 +1019,7 @@ drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; drm_mga_iload_t iload; - DRM_DEBUG( __FUNCTION__ ":\n" ); + DRM_DEBUG( "%s:\n", __FUNCTION__ ); LOCK_TEST_WITH_RETURN( dev ); @@ -1029,7 +1029,7 @@ #if 0 if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { if ( MGA_DMA_DEBUG ) - DRM_INFO( __FUNCTION__": -EBUSY\n" ); + DRM_INFO( "%s: -EBUSY\n" , __FUNCTION__); return -EBUSY; } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/picker.c linux.20pre2-ac1/drivers/char/drm/picker.c --- linux.20pre2/drivers/char/drm/picker.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/picker.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,30 @@ + +#include +#include + +#ifndef CONFIG_SMP +#define CONFIG_SMP 0 +#endif + +#ifndef CONFIG_MODULES +#define CONFIG_MODULES 0 +#endif + +#ifndef CONFIG_MODVERSIONS +#define CONFIG_MODVERSIONS 0 +#endif + +#ifndef CONFIG_AGP_MODULE +#define CONFIG_AGP_MODULE 0 +#endif + +#ifndef CONFIG_AGP +#define CONFIG_AGP 0 +#endif + +SMP = CONFIG_SMP +MODULES = CONFIG_MODULES +MODVERSIONS = CONFIG_MODVERSIONS +AGP = CONFIG_AGP +AGP_MODULE = CONFIG_AGP_MODULE +RELEASE = UTS_RELEASE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/r128_drv.c linux.20pre2-ac1/drivers/char/drm/r128_drv.c --- linux.20pre2/drivers/char/drm/r128_drv.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/r128_drv.c 2002-08-06 15:42:07.000000000 +0100 @@ -39,11 +39,11 @@ #define DRIVER_NAME "r128" #define DRIVER_DESC "ATI Rage 128" -#define DRIVER_DATE "20010405" +#define DRIVER_DATE "20010917" #define DRIVER_MAJOR 2 -#define DRIVER_MINOR 1 -#define DRIVER_PATCHLEVEL 6 +#define DRIVER_MINOR 2 +#define DRIVER_PATCHLEVEL 0 #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { r128_cce_buffers, 1, 0 }, \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/r128_drv.h linux.20pre2-ac1/drivers/char/drm/r128_drv.h --- linux.20pre2/drivers/char/drm/r128_drv.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/r128_drv.h 2002-08-06 15:42:07.000000000 +0100 @@ -469,7 +469,7 @@ DRM_ERROR( "ring space check failed!\n" ); \ return -EBUSY; \ } \ - __ring_space_done: \ + __ring_space_done: ; \ } while (0) #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/r128_state.c linux.20pre2-ac1/drivers/char/drm/r128_state.c --- linux.20pre2/drivers/char/drm/r128_state.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/r128_state.c 2002-08-06 15:42:07.000000000 +0100 @@ -1519,10 +1519,75 @@ { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_r128_buf_priv_t *buf_priv; + drm_r128_indirect_t indirect; +#if 0 + RING_LOCALS; +#endif LOCK_TEST_WITH_RETURN( dev ); - /* Indirect buffer firing is not supported at this time. + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return -EINVAL; + } + + if ( copy_from_user( &indirect, (drm_r128_indirect_t *)arg, + sizeof(indirect) ) ) + return -EFAULT; + + DRM_DEBUG( "indirect: idx=%d s=%d e=%d d=%d\n", + indirect.idx, indirect.start, + indirect.end, indirect.discard ); + + if ( indirect.idx < 0 || indirect.idx >= dma->buf_count ) { + DRM_ERROR( "buffer index %d (of %d max)\n", + indirect.idx, dma->buf_count - 1 ); + return -EINVAL; + } + + buf = dma->buflist[indirect.idx]; + buf_priv = buf->dev_private; + + if ( buf->pid != current->pid ) { + DRM_ERROR( "process %d using buffer owned by %d\n", + current->pid, buf->pid ); + return -EINVAL; + } + if ( buf->pending ) { + DRM_ERROR( "sending pending buffer %d\n", indirect.idx ); + return -EINVAL; + } + + if ( indirect.start < buf->used ) { + DRM_ERROR( "reusing indirect: start=0x%x actual=0x%x\n", + indirect.start, buf->used ); + return -EINVAL; + } + + RING_SPACE_TEST_WITH_RETURN( dev_priv ); + VB_AGE_TEST_WITH_RETURN( dev_priv ); + + buf->used = indirect.end; + buf_priv->discard = indirect.discard; + +#if 0 + /* Wait for the 3D stream to idle before the indirect buffer + * containing 2D acceleration commands is processed. */ - return -EINVAL; + BEGIN_RING( 2 ); + RADEON_WAIT_UNTIL_3D_IDLE(); + ADVANCE_RING(); +#endif + + /* Dispatch the indirect buffer full of commands from the + * X server. This is insecure and is thus only available to + * privileged clients. + */ + r128_cce_dispatch_indirect( dev, buf, indirect.start, indirect.end ); + + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/radeon_drv.h linux.20pre2-ac1/drivers/char/drm/radeon_drv.h --- linux.20pre2/drivers/char/drm/radeon_drv.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/radeon_drv.h 2002-08-06 15:42:07.000000000 +0100 @@ -660,7 +660,7 @@ DRM_ERROR( "ring space check failed!\n" ); \ return -EBUSY; \ } \ - __ring_space_done: \ + __ring_space_done: ; \ } while (0) #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm/sis_mm.c linux.20pre2-ac1/drivers/char/drm/sis_mm.c --- linux.20pre2/drivers/char/drm/sis_mm.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm/sis_mm.c 2002-08-12 12:53:22.000000000 +0100 @@ -125,7 +125,7 @@ if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) retval = -1; - DRM_DEBUG("free fb, offset = %d\n", fb.free); + DRM_DEBUG("free fb, offset = %ld\n", fb.free); return retval; } @@ -223,7 +223,7 @@ if(!del_alloc_set(agp.context, AGP_TYPE, agp.free)) retval = -1; - DRM_DEBUG("free agp, free = %d\n", agp.free); + DRM_DEBUG("free agp, free = %ld\n", agp.free); return retval; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm-4.0/ffb_drv.c linux.20pre2-ac1/drivers/char/drm-4.0/ffb_drv.c --- linux.20pre2/drivers/char/drm-4.0/ffb_drv.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm-4.0/ffb_drv.c 2002-08-06 15:42:07.000000000 +0100 @@ -710,8 +710,7 @@ /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - current->policy |= SCHED_YIELD; - schedule(); + yield(); if (signal_pending(current)) { ret = -ERESTARTSYS; break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm-4.0/i810_dma.c linux.20pre2-ac1/drivers/char/drm-4.0/i810_dma.c --- linux.20pre2/drivers/char/drm-4.0/i810_dma.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm-4.0/i810_dma.c 2002-08-06 15:42:07.000000000 +0100 @@ -83,7 +83,7 @@ *(volatile unsigned int *)(virt + outring) = n; \ outring += 4; \ outring &= ringmask; \ -} while (0); +} while (0) static inline void i810_print_status_page(drm_device_t *dev) { @@ -231,7 +231,7 @@ #else retcode = do_munmap(current->mm, (unsigned long)buf_priv->virtual, - (size_t) buf->total); + (size_t) buf->total, 1); #endif up_write(¤t->mm->mmap_sem); } @@ -279,7 +279,7 @@ address = __get_free_page(GFP_KERNEL); if(address == 0UL) return 0; - + get_page(virt_to_page(address)); LockPage(virt_to_page(address)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/drm-4.0/tdfx_drv.c linux.20pre2-ac1/drivers/char/drm-4.0/tdfx_drv.c --- linux.20pre2/drivers/char/drm-4.0/tdfx_drv.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/drm-4.0/tdfx_drv.c 2002-08-06 15:42:07.000000000 +0100 @@ -554,7 +554,6 @@ lock.context, current->pid, j, dev->lock.lock_time, jiffies); current->state = TASK_INTERRUPTIBLE; - current->policy |= SCHED_YIELD; schedule_timeout(DRM_LOCK_SLICE-j); DRM_DEBUG("jiffies=%d\n", jiffies); } @@ -578,10 +577,7 @@ /* Contention */ atomic_inc(&dev->total_sleeps); -#if 1 - current->policy |= SCHED_YIELD; -#endif - schedule(); + yield(); if (signal_pending(current)) { ret = -ERESTARTSYS; break; @@ -604,8 +600,7 @@ when dev->last_context == lock.context NOTE WE HOLD THE LOCK THROUGHOUT THIS TIME! */ - current->policy |= SCHED_YIELD; - schedule(); + yield(); current->state = TASK_RUNNING; remove_wait_queue(&dev->context_wait, &entry); if (signal_pending(current)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/i810-tco.c linux.20pre2-ac1/drivers/char/i810-tco.c --- linux.20pre2/drivers/char/i810-tco.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/i810-tco.c 2002-08-12 15:30:43.000000000 +0100 @@ -223,7 +223,10 @@ /* scan to see wether or not we got the magic character */ for (i = 0; i != len; i++) { - if (data[i] == 'V') + u8 c; + if(get_user(c, data+i)) + return -EFAULT; + if (c == 'V') tco_expect_close = 42; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/isicom.c linux.20pre2-ac1/drivers/char/isicom.c --- linux.20pre2/drivers/char/isicom.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/isicom.c 2002-08-06 16:00:52.000000000 +0100 @@ -1255,11 +1255,7 @@ created more space in xmit_buf when the ctrl gets back here */ sti(); - if (copy_from_user(tmp_buf, buf, cnt)) { - up(&tmp_buf_sem); - restore_flags(flags); - return -EFAULT; - } + copy_from_user(tmp_buf, buf, cnt); cli(); cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/joystick/analog.c linux.20pre2-ac1/drivers/char/joystick/analog.c --- linux.20pre2/drivers/char/joystick/analog.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/joystick/analog.c 2002-08-12 10:42:15.000000000 +0100 @@ -137,10 +137,9 @@ */ #ifdef __i386__ -#define TSC_PRESENT (test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability)) -#define GET_TIME(x) do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0) -#define DELTA(x,y) (TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0))) -#define TIME_NAME (TSC_PRESENT?"TSC":"PIT") +#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0) +#define DELTA(x,y) (cpu_has_tsc?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0))) +#define TIME_NAME (cpu_has_tsc?"TSC":"PIT") #elif __x86_64__ #define GET_TIME(x) rdtscl(x) #define DELTA(x,y) ((y)-(x)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/keyboard.c linux.20pre2-ac1/drivers/char/keyboard.c --- linux.20pre2/drivers/char/keyboard.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/keyboard.c 2002-08-06 15:42:07.000000000 +0100 @@ -42,6 +42,9 @@ #include #include #include +#include /* for mdelay() */ + +#include #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -100,20 +103,21 @@ typedef void (*k_hand)(unsigned char value, char up_flag); typedef void (k_handfn)(unsigned char value, char up_flag); + static k_handfn do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, - do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, - do_ignore; + do_meta, do_ascii, do_lock, do_lowercase, do_slock, + do_spkup, do_dead2, do_ignore; -static k_hand key_handler[16] = { +static k_hand key_handler[17] = { do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, - do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, - do_ignore, do_ignore + do_meta, do_ascii, do_lock, do_lowercase, do_slock, + do_spkup, do_dead2, do_ignore, do_ignore }; /* Key types processed even in raw modes */ -#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT)) +#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT) | (1 << KT_SPKUP)) typedef void (*void_fnp)(void); typedef void (void_fn)(void); @@ -137,7 +141,7 @@ 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, 255, - NR_LOCK - 1, 255 + NR_LOCK - 1, NR_SPKUP - 1, 255, 255 }; const int NR_TYPES = SIZE(max_vals); @@ -257,6 +261,7 @@ raw_mode = 1; /* Most key classes will be ignored */ } + /* * Small change in philosophy: earlier we defined repetition by * rep = keycode == prev_keycode; @@ -286,24 +291,26 @@ type = KTYP(keysym); if (type >= 0xf0) { - type -= 0xf0; - if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) - goto out; - if (type == KT_LETTER) { - type = KT_LATIN; - if (vc_kbd_led(kbd, VC_CAPSLOCK)) { - key_map = key_maps[shift_final ^ (1<slockstate = 0; + if (!up_flag) + speakup_reset(fg_console, type); + (*key_handler[type])(keysym & 0xff, up_flag); + if (type != KT_SLOCK) + kbd->slockstate = 0; } else { - /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ - if (!up_flag && !raw_mode) - to_utf8(keysym); + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag && !raw_mode) + to_utf8(keysym); } } else { /* maybe beep? */ @@ -315,7 +322,7 @@ keysym = U(key_maps[0][keycode]); type = KTYP(keysym); if (type == KT_SHIFT) - (*key_handler[type])(keysym & 0xff, up_flag); + (*key_handler[type])(keysym & 0xff, up_flag); #endif } } @@ -528,6 +535,138 @@ compute_shiftstate(); } +#ifdef CONFIG_SPEAKUP /* speech output for linux */ +static void do_spkup(unsigned char value, char up_flag) +{ + speakup_savekey(0); /* clear! brzzzot */ + if (up_flag) + return; /* do nothing on key release */ + + if (value == SPEECH_KILL) { + speakup_kill(fg_console); + return; + } + + if (speakup_console[fg_console]->shut_up & 0x40) return; + + switch(value) { + case (QUICK_QUIET): + /* -x- */ + spkup_write("\x18", 1); + return; + case (LINE_QUIET): + return; + case (FULL_QUIET): + spkup_write("\x18", 1); + speakup_shut_up(fg_console); + return; + case (SAY_CHAR): + say_curr_char(fg_console); + return; + case (SAY_PREV_CHAR): + say_prev_char(fg_console); + return; + case (SAY_NEXT_CHAR): + say_next_char(fg_console); + return; + case (SAY_WORD): + say_curr_word(fg_console); + return; + case (SAY_PREV_WORD): + say_prev_word(fg_console); + return; + case (SAY_NEXT_WORD): + say_next_word(fg_console); + return; + case (SAY_LINE): + say_curr_line(fg_console); + return; + case (SAY_PREV_LINE): + say_prev_line(fg_console); + return; + case (SAY_NEXT_LINE): + say_next_line(fg_console); + return; + case (TOP_EDGE): + top_edge(fg_console); + return; + case (BOTTOM_EDGE): + bottom_edge(fg_console); + return; + case (LEFT_EDGE): + left_edge(fg_console); + return; + case (RIGHT_EDGE): + right_edge(fg_console); + return; + case (SAY_PHONETIC_CHAR): + say_phonetic_char(fg_console); + return; + case (SPELL_WORD): + spell_word(fg_console); + return; + case (SPELL_PHONETIC_WORD): + return; + case (SAY_SCREEN): + say_screen(fg_console); + return; + case (SAY_WINDOW): + return; + case (SET_SPEED): + return; + case (SET_PITCH): + return; + case (SET_PUNCTUATION): + return; + case (SET_VOICE): + return; + case (SET_TONE): + return; + case (SAY_POSITION): + say_position(fg_console); + return; + case (SAY_CHAR_NUM): + say_char_num(fg_console); + return; + case (SPEECH_OFF): + speakup_off(fg_console); + return; + case (SPEAKUP_CURSORING): + speakup_cursoring(fg_console); + return; + case (SPEAKUP_CUT): + speakup_cut(fg_console, tty); + return; + case (SPEAKUP_PASTE): + speakup_paste(tty); + return; + case (SAY_ATTRIBUTES): + say_attributes(fg_console); + return; + case (SPEAKUP_PARKED): + speakup_parked(fg_console); + return; + case (SAY_FROM_TOP): + say_from_top(fg_console); + return; + case (SAY_TO_BOTTOM): + say_to_bottom(fg_console); + return; + case (SAY_FROM_LEFT): + say_from_left(fg_console); + return; + case (SAY_TO_RIGHT): + say_to_right(fg_console); + return; + default: + spkup_write("SpeakUp: Invalid command", 25); + return; +} +} +#else +static void do_spkup(unsigned char value, char up_flag) {}; +#endif + static void do_spec(unsigned char value, char up_flag) { if (up_flag) @@ -538,6 +677,7 @@ !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) return; spec_fn_table[value](); + speakup_control(fg_console, kbd, value); } static void do_lowercase(unsigned char value, char up_flag) @@ -551,7 +691,8 @@ return; /* no action, if this is a key release */ if (diacr) - value = handle_diacr(value); + if ((value = handle_diacr(value)) == 0xff) /* speakup goto pos trigger*/ + return; if (dead_key_next) { dead_key_next = 0; @@ -559,6 +700,7 @@ return; } + speakup_savekey(value); put_queue(value); } @@ -568,8 +710,10 @@ #define A_TILDE '~' #define A_DIAER '"' #define A_CEDIL ',' +#define SPEAKUP_DIACR '$' + static unsigned char ret_diacr[NR_DEAD] = - {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL }; + {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL, SPEAKUP_DIACR}; /* Obsolete - for backwards compatibility only */ static void do_dead(unsigned char value, char up_flag) @@ -588,6 +732,12 @@ if (up_flag) return; + if (value == SPEAKUP_DIACR) { /*beep to alert that speakup's waiting */ + kd_mksound(1250,10); + mdelay(100); + kd_mksound(1500,15); + } + diacr = (diacr ? handle_diacr(value) : value); } @@ -604,6 +754,12 @@ int d = diacr; int i; + if (d == '$') { + if (speakup_diacr(ch,fg_console)) + diacr = 0; + return 0xff; + } + diacr = 0; for (i = 0; i < accent_table_size; i++) { @@ -657,7 +813,7 @@ do_fn(KVAL(K_REMOVE), 0); return; case KVAL(K_P0): - do_fn(KVAL(K_INSERT), 0); + do_fn(KVAL(K_INSERT), 0); return; case KVAL(K_P1): do_fn(KVAL(K_SELECT), 0); @@ -717,6 +873,10 @@ clr_vc_kbd_led(kbd, VC_CAPSLOCK); } + /* shift = 0, altgr = 1, ctrl=2, alt=3 */ + if (!up_flag) + speakup_control(fg_console, kbd, value); + if (up_flag) { /* handle the case that two shift or control keys are depressed simultaneously */ @@ -805,6 +965,7 @@ if (up_flag || rep) return; chg_vc_kbd_lock(kbd, value); + } static void do_slock(unsigned char value, char up_flag) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/Makefile linux.20pre2-ac1/drivers/char/Makefile --- linux.20pre2/drivers/char/Makefile 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/Makefile 2002-08-13 14:21:38.000000000 +0100 @@ -178,6 +178,7 @@ obj-$(CONFIG_ISI) += isicom.o obj-$(CONFIG_ESPSERIAL) += esp.o obj-$(CONFIG_SYNCLINK) += synclink.o +obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_SPECIALIX) += specialix.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o @@ -225,6 +226,7 @@ obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o obj-$(CONFIG_AMD_RNG) += amd768_rng.o +obj-$(CONFIG_AMD_PM768) += amd76x_pm.o obj-$(CONFIG_ITE_GPIO) += ite_gpio.o obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o @@ -242,6 +244,14 @@ obj-y += ftape/ftape.o endif +ifeq ($(CONFIG_SPEAKUP),y) +subdir-y += speakup +obj-y += speakup/spk.o +ifeq ($(CONFIG_SPEAKUP_KEYMAP),y) +KEYMAP = speakup/speakupmap.o +endif +endif + obj-$(CONFIG_H8) += h8.o obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_DZ) += dz.o @@ -270,10 +280,12 @@ obj-$(CONFIG_SH_WDT) += shwdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o +obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o subdir-$(CONFIG_MWAVE) += mwave ifeq ($(CONFIG_MWAVE),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/mwave/mwavedd.c linux.20pre2-ac1/drivers/char/mwave/mwavedd.c --- linux.20pre2/drivers/char/mwave/mwavedd.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/mwave/mwavedd.c 2002-08-06 15:42:07.000000000 +0100 @@ -279,7 +279,6 @@ pDrvData->IPCs[ipcnum].bIsHere = FALSE; pDrvData->IPCs[ipcnum].bIsEnabled = TRUE; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - current->nice = -20; /* boost to provide priority timing */ #else current->priority = 0x28; /* boost to provide priority timing */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/n_r3964.c linux.20pre2-ac1/drivers/char/n_r3964.c --- linux.20pre2/drivers/char/n_r3964.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/n_r3964.c 2002-08-06 15:42:07.000000000 +0100 @@ -1364,7 +1364,7 @@ pHeader->owner = pClient; } - copy_from_user (pHeader->data, data, count); /* We already verified this */ + __copy_from_user(pHeader->data, data, count); /* We already verified this */ if(pInfo->flags & R3964_DEBUG) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/nwflash.c linux.20pre2-ac1/drivers/char/nwflash.c --- linux.20pre2/drivers/char/nwflash.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/nwflash.c 2002-08-06 15:42:07.000000000 +0100 @@ -154,12 +154,11 @@ if (down_interruptible(&nwflash_sem)) return -ERESTARTSYS; - ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count); - if (ret == 0) { - ret = count; - *ppos += count; - } + ret = count - copy_to_user(buf, (void *)(FLASH_BASE + p), count); + *ppos += ret; up(&nwflash_sem); + if (ret == 0) + ret = -EFAULT; } return ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/pc_keyb.c linux.20pre2-ac1/drivers/char/pc_keyb.c --- linux.20pre2/drivers/char/pc_keyb.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/pc_keyb.c 2002-08-06 15:42:07.000000000 +0100 @@ -64,7 +64,6 @@ static void kbd_write_command_w(int data); static void kbd_write_output_w(int data); #ifdef CONFIG_PSMOUSE -static void aux_write_ack(int val); static void __aux_write_ack(int val); static int aux_reconnect = 0; #endif @@ -1001,6 +1000,7 @@ kb_wait(); } +#ifdef INITIALIZE_MOUSE static void aux_write_ack(int val) { unsigned long flags; @@ -1009,6 +1009,7 @@ __aux_write_ack(val); spin_unlock_irqrestore(&kbd_controller_lock, flags); } +#endif static unsigned char get_from_queue(void) { @@ -1066,6 +1067,9 @@ static int open_aux(struct inode * inode, struct file * file) { + unsigned long flags; + int cnt, status; + if (aux_count++) { return 0; } @@ -1077,7 +1081,30 @@ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on controller. */ - aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ + + spin_lock_irqsave(&kbd_controller_lock, flags); + __aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ + for(cnt = 50; cnt > 0; --cnt) { + status = handle_kbd_event(); + if (mouse_reply_expected == 0 || + (status & (KBD_STAT_GTO | KBD_STAT_PERR))) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + schedule_timeout(2); + spin_lock_irqsave(&kbd_controller_lock, flags); + set_current_state(TASK_RUNNING); + } + if (cnt == 0 || (status & (KBD_STAT_GTO | KBD_STAT_PERR))) { + --aux_count; + spin_unlock_irqrestore(&kbd_controller_lock, flags); + kbd_write_cmd(AUX_INTS_OFF); + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + aux_free_irq(AUX_DEV); + return -ENXIO; + } + spin_unlock_irqrestore(&kbd_controller_lock, flags); + kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ mdelay(2); /* Ensure we follow the kbc access delay rules.. */ @@ -1217,41 +1244,13 @@ #endif /* CONFIG_PSMOUSE */ -static int blink_frequency = HZ/2; +void pckbd_blink (char led) { + led = led ? (0x01 | 0x04) : 0x00; -/* Tell the user who may be running in X and not see the console that we have - panic'ed. This is to distingush panics from "real" lockups. - Could in theory send the panic message as morse, but that is left as an - exercise for the reader. */ -void panic_blink(void) -{ - static unsigned long last_jiffie; - static char led; - /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is - different. */ - if (!blink_frequency) - return; - if (jiffies - last_jiffie > blink_frequency) { - led ^= 0x01 | 0x04; while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); kbd_write_output(KBD_CMD_SET_LEDS); mdelay(1); while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); mdelay(1); kbd_write_output(led); - last_jiffie = jiffies; - } -} - -static int __init panicblink_setup(char *str) -{ - int par; - if (get_option(&str,&par)) - blink_frequency = par*(1000/HZ); - return 1; } - -/* panicblink=0 disables the blinking as it caused problems with some console - switches. otherwise argument is ms of a blink period. */ -__setup("panicblink=", panicblink_setup); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/random.c linux.20pre2-ac1/drivers/char/random.c --- linux.20pre2/drivers/char/random.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/random.c 2002-08-12 10:42:15.000000000 +0100 @@ -412,13 +412,13 @@ * deal with a variable rotate of x bits. So we use a bit of asm magic. */ #if (!defined (__i386__)) -extern inline __u32 rotate_left(int i, __u32 word) +static inline __u32 rotate_left(int i, __u32 word) { return (word << i) | (word >> (32 - i)); } #else -extern inline __u32 rotate_left(int i, __u32 word) +static inline __u32 rotate_left(int i, __u32 word) { __asm__("roll %%cl,%0" :"=r" (word) @@ -735,7 +735,7 @@ int entropy = 0; #if defined (__i386__) - if ( test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability) ) { + if (cpu_has_tsc) { __u32 high; rdtsc(time, high); num ^= high; @@ -1643,7 +1643,7 @@ return -EINVAL; if (size > random_state->poolinfo.poolwords) size = random_state->poolinfo.poolwords; - if (copy_to_user(p, random_state->pool, size * 4)) + if (copy_to_user(p, random_state->pool, size * sizeof(__u32))) return -EFAULT; return 0; case RNDADDENTROPY: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/raw.c linux.20pre2-ac1/drivers/char/raw.c --- linux.20pre2/drivers/char/raw.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/raw.c 2002-08-06 15:42:07.000000000 +0100 @@ -23,6 +23,7 @@ struct block_device *binding; int inuse, sector_size, sector_bits; struct semaphore mutex; + int can_do_vary; } raw_device_data_t; static raw_device_data_t raw_devices[256]; @@ -119,6 +120,8 @@ if (raw_devices[minor].inuse++) goto out; + raw_devices[minor].can_do_vary = + get_blkdev_varyio(MAJOR(rdev), MINOR(rdev)); /* * Don't interfere with mounted devices: we cannot safely set * the blocksize on a device which is already mounted. @@ -128,6 +131,7 @@ if (is_mounted(rdev)) { if (blksize_size[MAJOR(rdev)]) sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)]; + raw_devices[minor].can_do_vary = 0; } else { if (hardsect_size[MAJOR(rdev)]) sector_size = hardsect_size[MAJOR(rdev)][MINOR(rdev)]; @@ -135,6 +139,7 @@ set_blocksize(rdev, sector_size); raw_devices[minor].sector_size = sector_size; + filp->f_iobuf->dovary = raw_devices[minor].can_do_vary; for (sector_bits = 0; !(sector_size & 1); ) sector_size>>=1, sector_bits++; @@ -201,9 +206,10 @@ /* First, find out which raw minor we want */ - err = copy_from_user(&rq, (void *) arg, sizeof(rq)); - if (err) + if (copy_from_user(&rq, (void *) arg, sizeof(rq))) { + err = -EFAULT; break; + } minor = rq.raw_minor; if (minor <= 0 || minor > MINORMASK) { @@ -260,6 +266,8 @@ rq.block_major = rq.block_minor = 0; } err = copy_to_user((void *) arg, &rq, sizeof(rq)); + if (err) + err = -EFAULT; } break; @@ -322,6 +330,7 @@ if (err) goto out; new_iobuf = 1; + iobuf->dovary = raw_devices[minor].can_do_vary; } dev = to_kdev_t(raw_devices[minor].binding->bd_dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/serial.c linux.20pre2-ac1/drivers/char/serial.c --- linux.20pre2/drivers/char/serial.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/serial.c 2002-08-13 14:21:58.000000000 +0100 @@ -62,6 +62,10 @@ * Robert Schwebel , * Juergen Beisert , * Theodore Ts'o + * 4/02: added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUTS + * to waiting processes + * Sapan Bhatia + * */ static char *serial_version = "5.05c"; @@ -203,6 +207,7 @@ #include #include #include +#include #if (LINUX_VERSION_CODE >= 131343) #include #endif @@ -1213,7 +1218,7 @@ if (!page) return -ENOMEM; - save_flags(flags); cli(); + spin_lock_irqsave( &info->irq_spinlock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -1451,11 +1456,11 @@ change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return 0; errout: - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return retval; } @@ -1479,7 +1484,7 @@ state->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ + spin_lock_irqsave( &info->irq_spinlock, flags); /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq @@ -1487,41 +1492,6 @@ */ wake_up_interruptible(&info->delta_msr_wait); - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[state->irq] = info->next_port; - figure_IRQ_timeout(state->irq); - - /* - * Free the IRQ, if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - free_irq(state->irq, &IRQ_ports[state->irq]); - retval = request_irq(state->irq, rs_interrupt_single, - SA_SHIRQ, "serial", - &IRQ_ports[state->irq]); - - if (retval) - printk("serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(state->irq, &IRQ_ports[state->irq]); - } - - if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = 0; - free_page(pg); - } - info->IER = 0; serial_outp(info, UART_IER, 0x00); /* disable all intrs */ #ifdef CONFIG_SERIAL_MANY_PORTS @@ -1578,7 +1548,43 @@ serial_outp(info, UART_IER, UART_IERX_SLEEP); } info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, &IRQ_ports[state->irq]); + retval = request_irq(state->irq, rs_interrupt_single, + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, &IRQ_ports[state->irq]); + } + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); + } + + spin_unlock_irqrestore( &info->irq_spinlock, flags); } #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ @@ -3123,6 +3129,7 @@ info->tqueue.routine = do_softint; info->tqueue.data = info; info->state = sstate; + spin_lock_init(&info->irq_spinlock); if (sstate->info) { kfree(info); *ret_info = sstate->info; @@ -3237,6 +3244,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("rs_open ttys%d successful...", info->line); #endif + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); return 0; } @@ -3650,6 +3658,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; save_flags(flags); cli(); @@ -3902,7 +3911,14 @@ case 6: /* BAR 4*/ case 7: base_idx=idx-2; /* BAR 5*/ } - + + /* AFAVLAB uses a different mixture of BARs and offsets */ + /* Not that ugly ;) -- HW */ + if (dev->vendor == PCI_VENDOR_ID_AFAVLAB && idx >= 4) { + base_idx = 4; + offset = (idx - 4) * 8; + } + /* Some Titan cards are also a little weird */ if (dev->vendor == PCI_VENDOR_ID_TITAN && (dev->device == PCI_DEVICE_ID_TITAN_400L || @@ -4306,9 +4322,11 @@ pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, + pbn_b0_bt_8_115200, pbn_b0_bt_1_460800, pbn_b0_bt_2_460800, pbn_b0_bt_2_921600, + pbn_b0_bt_4_460800, pbn_b1_1_115200, pbn_b1_2_115200, @@ -4387,9 +4405,11 @@ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 8, 115200 }, /* pbn_b0_bt_8_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 460800 }, /* pbn_b0_bt_4_460800 */ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ @@ -4854,6 +4874,12 @@ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_1_115200 }, @@ -4866,6 +4892,11 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, + /* AFAVLAB serial card, from Harald Welte */ + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, + /* EKF addition for i960 Boards form EKF with serial port */ { PCI_VENDOR_ID_INTEL, 0x1960, 0xE4BF, PCI_ANY_ID, 0, 0, @@ -4885,6 +4916,7 @@ 0x1048, 0x1500, 0, 0, pbn_b1_1_115200 }, + /* SGI IOC3 board */ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, 0xFF00, 0, 0, 0, pbn_sgi_ioc3 }, @@ -5537,12 +5569,22 @@ tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + state->line); } +#ifdef CONFIG_SERIAL_GSC + probe_serial_gsc(); +#endif +#ifdef CONFIG_SUPERIO + superio_serial_init(); +#endif #ifdef ENABLE_SERIAL_PCI probe_serial_pci(); #endif #ifdef ENABLE_SERIAL_PNP probe_serial_pnp(); #endif + // FIXME: Clean this one up +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_PARISC) + serial_console_init(); +#endif return 0; } @@ -5652,6 +5694,7 @@ info->io_type = req->io_type; info->iomem_base = req->iomem_base; info->iomem_reg_shift = req->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; } autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -5959,6 +6002,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); #if defined(__powerpc__) || defined(__alpha__) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/serial_tx3912.h linux.20pre2-ac1/drivers/char/serial_tx3912.h --- linux.20pre2/drivers/char/serial_tx3912.h 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/serial_tx3912.h 2002-08-14 14:41:30.000000000 +0100 @@ -12,6 +12,27 @@ #include #include +/* UART Interrupt (Interrupt 2) bits (UARTA,UARTB) */ +#define UART_RX_INT 9 /* receiver holding register full (31, 21) */ +#define UART_RXOVERRUN_INT 8 /* receiver overrun error (30, 20) */ +#define UART_FRAMEERR_INT 7 /* receiver frame error (29, 19) */ +#define UART_BREAK_INT 6 /* received break signal (28, 18) */ +#define UART_PARITYERR_INT 5 /* receiver parity error (27, 17) */ +#define UART_TX_INT 4 /* transmit holding register empty (26, 16) */ +#define UART_TXOVERRUN_INT 3 /* transmit overrun error (25, 15) */ +#define UART_EMPTY_INT 2 /* both trans/recv regs empty (24, 14) */ +#define UART_DMAFULL_INT 1 /* DMA at end of buffer (23, 13) */ +#define UART_DMAHALF_INT 0 /* DMA halfway through buffer (22, 12) */ + +#define UARTA_SHIFT 22 +#define UARTB_SHIFT 12 + +#define INTTYPE(interrupttype) (1 << interrupttype) + +/* + * This driver can spew a whole lot of debugging output at you. If you + * need maximum performance, you should disable the DEBUG define. + */ #undef TX3912_UART_DEBUG #ifdef TX3912_UART_DEBUG diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/sonypi.h linux.20pre2-ac1/drivers/char/sonypi.h --- linux.20pre2/drivers/char/sonypi.h 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/sonypi.h 2002-08-14 14:41:30.000000000 +0100 @@ -214,6 +214,7 @@ /* The set of possible back button events */ static struct sonypi_event sonypi_backev[] = { { 0x20, SONYPI_EVENT_BACK_PRESSED }, + { 0x3b, SONYPI_EVENT_HELP_PRESSED }, { 0x00, 0x00 } }; @@ -258,7 +259,7 @@ while (--n && (command)) \ udelay(1); \ if (!n && (verbose || !quiet)) \ - printk(KERN_WARNING "sonypi command failed at " __FILE__ " : " __FUNCTION__ "(line %d)\n", __LINE__); \ + printk(KERN_WARNING "sonypi command failed at " __FILE__ " : %s (line %d)\n", __FUNCTION__, __LINE__); \ } #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/BUGS linux.20pre2-ac1/drivers/char/speakup/BUGS --- linux.20pre2/drivers/char/speakup/BUGS 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/BUGS 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,10 @@ +Well, there are probably just thousands to squash, but these are the +ones I think of as bugs. + +There is a problem with speakup interrogating LiteTalks with rom +versions of at least 3.22 and earlier. (kirk) + +I define bugs as things which aren't working correctly although +they've been implemented. NOT features which haven't been added yet. + + Kirk diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/ChangeLog linux.20pre2-ac1/drivers/char/speakup/ChangeLog --- linux.20pre2/drivers/char/speakup/ChangeLog 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/ChangeLog 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,1214 @@ +2001-10-18 Thursday 08:53 jim + + Removed the cut and paste bug description from the BUGS file. (Jim) + +2001-10-14 Sunday 15:28 jim + + Part two of the selection.c patch for 2.2. This process sure was fun! (Jim) + +2001-10-14 Sunday 15:21 jim + + Just adding the new patch file for selection.c in the diff-v22 patch + directory. (Jim) + +2001-10-14 Sunday 14:45 kirk + + Just adding the new patch file for selection.c in the diff-v24 patch + directory. (kirk) + +2001-10-14 Sunday 14:42 kirk + + Changed selection.c to test if call is coming from userspace or kernel + space and using GFP_ATOMIC if it is being called from kernel-space. + This works around kmalloc not returning and hanging the system in + set_selection for the block and paste function of speakup. (Jim) + +2001-10-12 Friday 12:10 jim + + speakup.c: + Removed statements which were appending 0x00 to buffers to be spoken + from functions say_curr_line and say_line_from_to. + + Inspected and modified all spkup_write() calls to be consistent, + that is, end in \n and count is correct. + (Jim Danley) + +2001-10-09 Tuesday 08:34 kirk + + Updated the BUGS and Todo list to reflect current speakup + states. (kirk) + +2001-10-07 Sunday 21:19 jim + + speakup.c: + Moved following variable declarations to top of function speakup_cut(). + int ret; + unsigned char args[6*sizeof(short)]; + unsigned short *arg; + static char *buf = "speakup_cut: set_selection failed: "; + (Jim Danley) + +2001-10-07 Sunday 17:11 jim + + Put speakup_dectlk.c back to its original state. Sorry about that! + + Also added a clear_selection() call to speakup.c when hitting the "mark" + key to remove (if any) hi-lighting of a previous mark/cut from the screen. + (Jim Danley) + +2001-10-05 Friday 09:14 kirk + + Checking in a slight change to speakupmap.map to uncomment alt-keypad + five to allow ascii five for extended character sets. (kirk) + +2001-10-02 Tuesday 12:34 kirk + + Modified installation and readme files for the version 1.0 release in + linux/Documentation/speakup. (kirk) + +2001-10-02 Tuesday 11:00 kirk + + Start of the check-ins for the official speakup v-1.00 release. + Modified checkin to change cvsversion format. Modified install to + remove reference to touching speakupmap.map. Modified speakup.c to + reflect version now moved to v-1.00. (kirk) + +2001-10-02 Tuesday 01:18 jim + + Modified the way that cut/paste variables are stored. No longer in spk_t + structure but stand-alone (one per speakup rather than one per console). + + speakup.c: + eliminated unsigned short mode = 0; /* char-by-char selection */ + by assigning it directly. + + Added globals + char mark_cut_flag; + unsigned short mark_x, mark_y; + + /usr/include/linux/include/linux/speakup.h: + removed mark_x and mark_y from the spk_t structure and the associated + defines. + (Jim Danley) + +2001-09-17 Monday 19:58 jim + + speakup.c: + Added: + #define Mark_Cut_Bit 0x04 + #define Mark_Cut_Bit_Mask 0xFB + + Changed from using bit 2 of spk_shut_up to bit 2 of spk_sound to + indicate mark/cut state. + + Removed statement that was assigning 2 to second byte of first short + in args array. + (Jim Danley) + +2001-09-14 Friday 15:43 kirk + + Removed the blank line at the bottom of drivers/char/Makefile which I + must have dreamed I removed in the last log. (kirk) + +2001-09-14 Friday 15:28 kirk + + Added a couple of missing key definitions in DefaultKeyAssignments. + Removed the blank line at the bottom of drivers/char/Makefile. + Rewrote spell_word() to use say_curr_char() and super stream line + it. (kirk) + +2001-09-14 Friday 14:11 jim + + speakup_dectlk.c: + Changed the valid pitch range from 0-99 to 50-350. + (Jim Danley) + +2001-09-14 Friday 01:28 jim + + Made similar changes to add cut and paste feature to 2.2 kernels. (Jim Danley + +2001-09-13 Thursday 23:13 jim + + diff-v2[24]/^usr^src^linux^Documentation^speakup^DefaultKeyAssignments.copy: + Added: + KeyPad-/ Mark and Cut screen region. + InsKeyPad-/ Paste screen region into any console. + (Jim Danley) + +2001-09-13 Thursday 21:41 jim + + Wrote mark/cut/paste feature. + + Usage: + 1. Move reading cursor to one end of the block of text you wish to cut + 2. Press the mark/cut key. You should hear "mark". + 3. Move reading cursor to other end of block of text to be cut. + 4. Press the mark/cut key. You should hear "cut". + 5. The cut buffer is now saved. + 6. Move to a program in any console where you wish to copy the cut buffer. + 7. Press the paste key. You should hear "paste" and text from + the cut buffer will be output just as if you had entered it + at the keyboard. + + Note: Trailing whitespace is stripped and newlines added where appropriate. + + speakup.c: + Added two new functions; speakup_cut() and speakup_paste() + + speakupmap.map: + Modified default keymap so that keypad divide toggles mark/cut and + insert-keypad divide is paste. + + /usr/src/linux/include/linux/speakup.h: + Added two new variables to the spk_t structure; unsigned long mark_x, mark_y + to store the coordinates of the beginning of the mark area to be cut. + Added: + #define spk_mx speakup_console[currcons]->mark_x + #define spk_my speakup_console[currcons]->mark_y + #define SPEAKUP_CUT 0x27 + #define SPEAKUP_PASTE 0x28 + Added two new prototypes: + extern void speakup_cut(unsigned int, struct tty_struct *); + extern void speakup_paste(struct tty_struct *); + + /usr/src/linux/drivers/char/keyboard.c: + In function do_spkup(): + Added case blocks for SPEAKUP_CUT and SPEAKUP_PASTE. + + /usr/src/linux/include/linux/keyboard.h: + Added: + #define K_SPEAKUP_CUT K(KT_SPKUP,SPEAKUP_CUT) + #define K_SPEAKUP_PASTE K(KT_SPKUP,SPEAKUP_PASTE) + and modified: (was 27) + #define NR_SPKUP 0x29 + + Also modified patch/copy files below in both diff-v22 and diff-v24 directories. + ^usr^src^linux^include^linux^keyboard.h.patch + ^usr^src^linux^drivers^char^keyboard.c.patch + ^usr^src^linux^include^linux^speakup.h.copy + +2001-09-08 Saturday 22:22 kirk + + Re-implementing the alpha patch for kernels 2.4.x which somehow keeps + getting lost. I also removed the bottom three lines of the checkout + script which are not needed anymore because we include a + speakupmap.c. (Kirk) + +2001-08-30 Thursday 17:25 kirk + + Modified drivers/char/Makefile to work with the new speakupmap.c + changes to 2.4.x. These changes include a portion of Shane's patch as + well as other rewrites by me. (kirk) + +2001-08-30 Thursday 16:17 kirk + + Modified drivers/char/Makefile and speakup/Makefile to accomodate the + new 2.4.9ac3 Makefile changes. This will also include a new + speakupmap.c moving towards Shane's Makefile patches for the 2.2.x + kernels, not included yet. (kirk) + +2001-08-29 Wednesday 21:26 kirk + + Just adding new patch against linux/init/main.c to cvs. (kirk) + +2001-08-29 Wednesday 21:23 kirk + + Rewrote speakup_init() to call a function speakup_register_devsynth() + which gets called from do_basic_setup in init/main.c. We need to do + this so that miscdevice will get called after the mm has been set up. + This should allow devfs to work with speakup. (kirk) + +2001-08-26 Sunday 13:54 kirk + + Removed an old comment line from console.c which prevent clean + patching against 2.4.8ac11. (kirk) + +2001-08-25 Saturday 18:46 kirk + + Modified keyboard.c, keyboard.h, speakup.c and speakup.h to conform with the standard kernel source tree under 2.4.x kernels. (Kirk) + +2001-08-25 Saturday 18:30 kirk + + Removing lxdialog patch files and removing their entries from + patchlist-22. These are now part of the standard 2.2.19+ kernel + tree. (Kirk) + ---------------------------------------------------------------------- + patchlist-v22 speakupmap.map symbols.h CVS: + diff-v22/^usr^src^linux^Documentation^speakup^DefaultKeyAssignments.copy + diff-v22/^usr^src^linux^Documentation^speakup^keymap-tutorial.copy + Removed Files: CVS: + diff-v22/^usr^src^linux^scripts^lxdialog^menubox.c.patch CVS: + ---------------------------------------------------------------------- + +2001-08-25 Saturday 18:15 kirk + + Changed keyboard.c, keyboard.h, speakup.c and speakup.h to conform to + the standard linux kernel tree code style for the 2.2.x + kernels. (Kirk) + +2001-08-18 Saturday 03:31 jim + + diff-v22/^usr^src^linux^drivers^char^keyboard.c.patch: Modified patch + to allow raw keyboard for version 2.2 kernels. (Jim Danley) + +2001-08-02 Thursday 13:47 kirk + + Adding \x20 to the flush string for the Audapter synths. (Kirk) + +2001-07-31 Tuesday 19:07 jim + + speakup_ltlk.c: appended \x20 to flush string of \x18 for litetalk driver. + This seems to fix the bug that was causing first chars to be dropped by + the double lt and litetalk synths for some users. (Jim Danley) + +2001-07-26 Thursday 20:12 kirk + + A few small clean ups trying to get 2.4.7 to work. (Kirk) + +2001-07-16 Monday 11:30 kirk + + Added KT_SPKUP to allowed_in_raw_mode macro so speakup's review + functions are available in raw mode for v-2.4.x kernels. (Kirk) + +2001-03-17 Saturday 15:40 jim + + speakup.c: + Added silent feature. + The print screen key kills and revives speakup. Sending specific values to + /proc/speakup/silent now allows the same control without having to press a key. + Valid settings are 0 through 3. + 0 and 2 turn on speakup if not already alive. + 1 and 3 turn off speakup if not already killed. + 0 and 1 announce the changes as the print screen key does, + 2 and 3 act silently. + (Jim Danley) + +2001-03-17 Saturday 08:45 jim + + speakup.c and symbols.h: + Added bell position feature. + When a letter is typed in column bell_pos, console beeps. + Valid settings are 0 through video_num_columns. Zero disables. + Get/set via /proc/speakup/bell_pos. + (Brian Borowski) + +2001-03-13 Tuesday 14:50 jim + + speakup.c: + Added code in say_screen() to insert a space at the end of full lines. + (Gene Collins) + +2001-03-13 Tuesday 14:40 jim + + speakup.c: + Found and fixed a couple of places where synth_write() was writing len of + string plus 1 which caused a NULL to be sent to the synth which causes + problems for the Doubletalk LT. + + speakup.c and keyboard.c for 2.2 and 2.4 + Corrected the length parameter on several spkup_write() statements which + were also sending unnecessary NULLs. + + Corrected spelling of /proc/speakup/transport directory. (Jim Danley) + +2001-02-28 Wednesday 10:55 kirk + + Removing the make menuconfig patches for checklist.c and menubox.c + because they have been included in linux 2.4.2. (Kirk) + +2001-02-11 Sunday 14:05 kirk + + Checking support for alpha support in 2.4.x kernels. (Kirk) + +2001-01-30 Tuesday 20:55 kirk + + Fixed arch/ppc/config.in to source drivers/char/Config.in which had + gotten broken in the post 2.4.0 ac patches. (Kirk) + +2001-01-28 Sunday 23:53 jim + + Reduced duplicate code in proc_speakup_synth_init() by creating two arrays + of strings, read_only[] and root_writable[] and using these arrays in + for loops. + Bumped version numbers on remaining serial synth drivers. (Jim Danley) + +2001-01-28 Sunday 20:26 kirk + + Made modifications to speakup.h for v2.2 and the remainder of the + serial synth drivers to use the initialize_uart() function in + speakup_drvcommon.c. (Kirk) + +2001-01-28 Sunday 19:15 kirk + + Made changes to 2.4.0 to move uart initialization code into + speakup_drvcommon.c and modified speakup_dectlk.c to use that + change. (Kirk) + +2001-01-28 Sunday 00:26 jim + + Modified the serprobe() function in the Accent SA driver. + This should allow the Accent SA to start talking from a cold boot with + no help from the lilo serial= or speakup_ser= options. + Ran speakup_acntsa.c through Lindent. + Bumped speakup_acntsa.c version number. (Jim Danley) + +2001-01-27 Saturday 23:26 jim + + Modified the serprobe() function in the Dectalk Express driver. + My Dectalk Express now starts talking just fine from a cold boot with + no help from the lilo serial= or speakup_ser= options. + Ran speakup_dectlk.c through Lindent and cleaned up some comments. + Bumped Dectalk Express driver version number. (Jim Danley) + +2001-01-25 Thursday 17:58 jim + + Worked on the write handler for /proc/speakup/synth. + It error-checks new_synth_name, prints out msg if synth selected is + already in use, looks for new_synth_name in list of synths compiled into + kernel, and prepares to switch to new synth. + Ran speakup.c through Lindent and cleaned up some comments. (Jim Danley) + +2001-01-24 Wednesday 22:59 jim + + + Modified speakup_drvcommon.c so that those synth-specific /proc file + entries which are writable will now accept "" to trigger resetting of + the default value. + Ran speakup_drvcommon.c through Lindent and cleaned up some comments. + (Jim Danley) + +2001-01-24 Wednesday 12:33 kirk + + Made changes for Maintaners to v-24. (Kirk) + +2001-01-24 Wednesday 12:31 kirk + + Another typo fix in Configure.help and an update to the URL in Maintaners. (Kirk) + +2001-01-24 Wednesday 11:57 kirk + + Fixed clarification in Configure.help in v-24. (Kirk) + +2001-01-24 Wednesday 11:56 kirk + + Fixed spelling error in Config.in and modified Configure.help yet again. (Kirk) + +2001-01-24 Wednesday 11:47 kirk + + Fixed formatting in v-24 configure.help. (Kirk) + +2001-01-24 Wednesday 11:46 kirk + + Fixed indentation and spelling errors in configure.help. (Kirk) + +2001-01-24 Wednesday 10:49 kirk + + Fixing the v-2.4 version of the Configure.help file. (Kirk) + +2001-01-24 Wednesday 10:47 kirk + + Updated the Configure.help documentation and re-arranged the speakup + Config.in file. (Kirk) + +2001-01-23 Tuesday 15:45 jim + + + Modified speakup.c to handle input in either upper or lower case written + to the /proc file entries for those settings that accept a range of + values that includes alpha chars. + The value is forced to lower case before any comparisons. + Modified the synth driver range parameters to accept only lower case as follows: + rate in both speakup_acntpc.c and speakup_acntsa.c, + pitch and volume in speakup_apolo.c, + tone in speakup_txprt.c. + Bumped synth driver version numbers. + (Jim Danley) + +2001-01-23 Tuesday 11:58 jim + + + Fixed typo in speakup_dectlk.c. + (Jim Danley) + +2001-01-23 Tuesday 11:39 jim + + + Moved full_time into the spk_synth structure for all synths and created + /proc/speakup/synth-specific/full_time entry. + Modified /usr/include/linux/speakup.h and associated files in diff-v22 and diff-v24. + (Jim Danley) + +2001-01-23 Tuesday 01:14 jim + + + Added to the TODO list. + (Jim Danley) + +2001-01-23 Tuesday 00:42 jim + + + Moved delay_time, trigger_time, and jiffy_delta into the spk_synth + structure for all synths. + Modified /usr/include/linux/speakup.h and associated files in diff-v22 and diff-v24. + Assigned following default values for Accent SA and Audapter drivers: + delay_time = 400, trigger_time = 5, jiffy_delta = 3. + Bumped synth driver version numbers. + (Jim Danley) + +2001-01-22 Monday 21:32 jim + + + Moved INIT_STRING and REINIT_STRING into the spk_synth structure for all synths. + Modified /usr/include/linux/speakup.h and associated files in diff-v22 and diff-v24. + Commented out some unused driver code that caused compile warnings. + (Jim Danley) + +2001-01-22 Monday 17:44 jim + + + Test number 2. + (Jim Danley) + +2001-01-22 Monday 16:28 kirk + + + Testing my new CVS login. + (Jim Danley) + +2001-01-21 Sunday 19:48 kirk + + Wrote char *strlwr(char *) and now use it to be certain that the + synth_name (provided by the user in config or at boot time) is forced + to lower case. + (Jim Danley) + +2001-01-21 Sunday 13:53 kirk + + Added /proc/speakup/synth entry -- read-only so far. + Removed old ioctl functions from speakup.c + Wrote xlate function to translate escape chars in user provided strings. + Added synth_name to "unknown synthesizer" message at boot up. + Check for length of synth_name. + Made certain that synth_name is NULL terminated. + (Jim Danley) + +2001-01-21 Sunday 09:03 kirk + + Changed synth_write("\n", 2); + to synth_write("\n", 1); + when sending user provided synth settings via /proc to the synth. + This *might* fix the problem reported by litetalk users. + Cleaned up some comments and indenting. + (Jim Danley) + +2001-01-14 Sunday 21:05 matt + + Checking in 2.2.x patches for the last modification. (Matt) + +2001-01-14 Sunday 20:49 kirk + + Checking in Matt Campbells driver rewrite to include all the synths in + the kernel at the same time. (Kirk) + +2001-01-10 Wednesday 12:16 kirk + + Fixed bug when writing to /proc/speakup files caps_start, caps_stop, + punc_some, and punc_most. + Defined PUNC_CHARS and PUNC_CHARS_SIZE in symbols.h. + Added MULTI_CHAR to list of possible spk_variable.flags, necessary to + define a list of chars that must belong to another list of chars -- + used for punc_some and punc_most. + Set arbitrary limit of 33 chars on caps_*. + Set PUNC_CHARS_SIZE char limit on user supplied value to punc_some and punc_most. + Fixed erroneous error strings. + #define'd error conditions to make code more clear. + Added STRING_TOO_LONG and CHAR_NOT_ONE_OF. + Added missing volume setting to DEFAULT_STATIC for Dectalk Express. + (Jim Danley) + +2001-01-08 Monday 19:08 kirk + + Made more changes to the cursoring. I got backspace working in and + out of cursoring. (Kirk) + +2001-01-08 Monday 16:25 kirk + + I have rewritten the cursoring routine speakup_check() to hopefully + improve it. We are not there yet! (Kirk) + +2001-01-07 Sunday 16:05 kirk + + Just fixing some indentation settings. (Kirk) + +2001-01-07 Sunday 13:37 kirk + + added a single line to the top of speakup.c for testing. + (Jim Danley) + +2001-01-07 Sunday 12:58 kirk + + Fixed char/Makefile to build depends which it wasn't doing for some + reason under 2.2.18. (Kirk) + +2001-01-07 Sunday 12:16 kirk + + Fixed char/Makefile to create the speakup/.depend correctly. I don't + know why it wasn't working before. Everything else did. (Kirk) + +2001-01-07 Sunday 12:05 kirk + + modified range checking code in speakup.c to handle negative numbers in + user provided parameter to /proc/speakup/* and also in spk_variable.valid. + (Jim Danley) + +2001-01-07 Sunday 09:02 kirk + + cleaned up and commented symbols.h. + re-wrote some of the range logic in symbols.h and speakup.c. + changed char valid[33] to char *valid in spk_variable struct. + dropped 0xff as char string terminator for spk_variable.valid member. + removed NUMERIC from rate flags for accents. + made /proc/speakup/tone read-only for dectalk express. + (Jim Danley) + +2001-01-06 Saturday 15:52 kirk + + Reorganized the Todo list and placed bugs in the bugs file. (Kirk) + +2001-01-05 Friday 21:19 kirk + + Made modifications to fix the make menuconfig bug in 2.4.0. (Kirk) + +2001-01-05 Friday 20:42 kirk + + Modified menubox.c in lxdialog to fix bug with initial menus not being + shown completely. (Kirk) + +2001-01-05 Friday 15:54 kirk + + merged symbols_*.h into symbols.h and removed symbols_*.h from CVS. + cleaned up the format a bit along the way. + (Jim Danley) + +2001-01-04 Thursday 18:33 kirk + + Modified the console.c, speakup.h and speakup.c for the 2.4.0 kernels. + I have also removed vt.c in preparation for just using the + /proc/speakup configuration system. (Kirk) + +2001-01-04 Thursday 12:11 kirk + + Starting major changes for merging into the kernel source tree. Files + updated are console.c speakup.c speakup.h and vt.c. I have built a + new set of functions to interact with the kernel which will be speakup + functions if speakup is configured in and null stubs if speakup is not + configured in. So far they include: speakup_allocate(), speakup_bs(), + speakup_con_update(), speakup_con_write() and speakup_init(). These + changes only affect the 2.2.18 tree currently. (Kirk) + +2001-01-03 Wednesday 10:04 kirk + + Fixed transport driver by giving the uart time to settle before + testing for the port. (Kirk) + +2001-01-02 Tuesday 20:18 kirk + + First attempt to change checkout to work with an installed tarball and + update it to cvs. (Kirk) + +2001-01-02 Tuesday 14:09 kirk + + Made tchanges to make v24 compatible with 2.4.0-prerelease. (Kirk) + +2001-01-02 Tuesday 09:50 kirk + + Added code to correctly parse range string for /proc file speech + parameters which use a range of chars. + Added a priority of KERN_ALERT to printk statements that need to be + displayed on user's console regardless. + Enhanced warning output if user attempts to assign a value out of range + to a /proc variable. + (Jim Danley) + +2000-12-31 Sunday 13:20 kirk + + Rewrote checkclean and changed semee to semi in the character + array. (Kirk) + +2000-12-31 Sunday 12:12 kirk + + Fixed syntax errors in speakup_txprt.c and modified the install + script. (Kirk) + +2000-12-31 Sunday 11:43 kirk + + Fixing typo's in the documentation files. (Kirk) + +2000-12-30 Saturday 23:33 kirk + + Rewrote install and INSTALLATION for a different installing + design. (Kirk) + +2000-12-30 Saturday 17:03 kirk + + We are officially version v-0.10. (Kirk) + +2000-12-30 Saturday 16:58 kirk + + Modified the installation file and created an install script. (Kirk) + +2000-12-30 Saturday 15:13 kirk + + Fixed a syntax problem with speakup_audptr.c. (Kirk) + +2000-12-30 Saturday 14:58 kirk + + Placed a length limit on reading of version number in + speakup_audptr.c. (Kirk) + +2000-12-30 Saturday 13:12 kirk + + Adding file changes for v22. (Kirk) + +2000-12-30 Saturday 13:10 kirk + + Removing files related to version changes. (Kirk) + +2000-12-30 Saturday 13:00 kirk + + Changed structure of Documentation/speakup and related files to remove + references to speakup version for ease in updating documentation. + (Kirk) + +2000-12-29 Friday 14:00 kirk + + echo "" > /proc/speakup/characters now resets to defaults for consistency. + wrote script to reset all speakup defaults + added key_echo toggle to speakup vars controllable by user + via /proc/speakup/key_echo + key_echo is not 100% -- keypad slash talks even if key_echo == 0 + (Jim Danley) + +2000-12-24 Sunday 16:46 kirk + + finished ability to write to /proc files, changed some default char descs, added "direct" to /proc + +2000-12-22 Friday 15:04 kirk + + These are the cursoring fixes for the 2.4.0-testxx kernels. They also + include the requested changes I was experimenting with by Alan Cox in + preparation for kernel source tree inclusion. (Kirk) + +2000-12-22 Friday 13:54 kirk + + Fixed up some of the cursoring issues and have started making the + changes requested by Alan Cox in preparation for kernel source tree + inclusion. (Kirk) + +2000-12-21 Thursday 08:56 kirk + + rewrite of speakup_characters_write_proc() to handle fragmented buffers when called by dd, cp, or cat in kernel 2.4 (Jim Danley) + +2000-12-20 Wednesday 12:17 kirk + + Cleaned up some warnings. (Kirk) + +2000-12-20 Wednesday 11:32 kirk + + Fixed toggle for synth timeout to set it off when waking up the + synth. (Kirk) + +2000-12-19 Tuesday 19:31 kirk + + This is atest fix to see if I have helped eliminate the synth bleed + through problem with all of the synths. (Kirk) + +2000-12-19 Tuesday 16:29 kirk + + quick change to speakup_audptr.c to fix synth_ver typo for kernel 2.2.18 (Jim Danley) + +2000-12-19 Tuesday 15:35 kirk + + Checking in the 2.2.18 fixes for the synth hanging problems. (Kirk) + +2000-12-19 Tuesday 15:10 kirk + + Finally fixed the synth hanging problem on synth turn off. (Kirk) + +2000-12-18 Monday 14:44 kirk + + Just updating BUGS to put the backspace problem to bed. (Kirk) + +2000-12-18 Monday 14:40 kirk + + Checking in the backspace fix for 2.4.0-test11. Yeah! Finally + fixed. (Kirk) + +2000-12-18 Monday 14:14 kirk + + Fixed the backspace bug at last! In 2.2.18 so far. (Kirk) + +2000-12-18 Monday 10:03 kirk + + Checking in Jim Danleys changes again. When will I learn to checkout + before checking in?? (Kirk) + +2000-12-15 Friday 13:50 kirk + + Checking first draft of menubox.c and checklist.c for + v-2.4.0-testxx. (Kirk) + +2000-12-15 Friday 13:48 kirk + + Taking first diff of menubox.c and checklist.c for v2.4.0-test11 for + make menuconfig cursoring. (Kirk) + +2000-12-15 Friday 13:17 kirk + + Checking in the new diffs of menubox.c and checklist.c for the first + time. (Kirk) + +2000-12-15 Friday 13:14 kirk + + Taking first diff of the make menuconfig patches from checklist.c and + menubox.c. (Kirk) + +2000-12-12 Tuesday 18:56 kirk + + Fixed a spelling error added to Todo list and fix speakup.c to not + need the is_alive() function. (Kirk) + +2000-12-12 Tuesday 15:21 kirk + + Fixed speakup to patch correctly with 2.2.18. Unfortunately it won't + work with kernels less than 2.2.18 anymore. It was totally agreed + upon by the folks on the reflector. It's not my fault mom! (Kirk) + +2000-12-12 Tuesday 10:41 kirk + + Fix a problem with a conflict in cvsversion.h. (Kirk) + +2000-12-11 Monday 20:40 kirk + + Attempt to fix the Audapter driver by limiting how long it can stay in + kernel space. (Kirk) + +2000-12-11 Monday 17:37 kirk + + Made a slight fix to spk_reset() and moved it's call up a bit in + handle_scancodes(); (Kirk) + +2000-12-11 Monday 16:28 kirk + + Just checking in the cvs adds for the new diff-v24 patch files. (Kirk) + +2000-12-11 Monday 16:25 kirk + + Checking in the 2.4.0 kernel patches for Jim Danley's /proc file + system additions. (Kirk) + +2000-12-11 Monday 14:34 kirk + + Checking in added proc files. (Kirk) + +2000-12-11 Monday 14:31 kirk + + Added two new files to v22 kernel for /proc file system, + linux/include/linux/proc_fs.h and linux/fs/proc/root.c. (Kirk) + +2000-12-11 Monday 12:59 kirk + + Checking in Jim Danleys /proc file system additions to speakup. (Kirk) + +2000-12-09 Saturday 19:14 kirk + + Changed spk_control to test for zero specifically on say_control. (Kirk) + +2000-12-09 Saturday 18:29 kirk + + Changed spk_control to say capslock scroll_lock and num_lock even when + say_control isn't on. (Kirk) + +2000-12-08 Friday 16:21 kirk + + Removing the linux version 2.3.xx stuff again. (Kirk) + +2000-12-08 Friday 15:40 kirk + + patched Configure.help by hand from v2.4 and committing. (Kirk) + +2000-12-08 Friday 14:47 kirk + + Checked in diff-v22/^usr^src^linux^Documentation^Configure.help.patch + which seems to have been missed as well as the init/main.c stuff. + This is really weird (Kirk) + +2000-12-08 Friday 14:40 kirk + + Added the -d flag to updat in checkout to see if we get cleanup + improvement. (Kirk) + +2000-12-08 Friday 13:13 kirk + + Removing patchlist and the linux 2.3.xx support. (Kirk) + +2000-12-08 Friday 13:07 kirk + + Edited check.orig and fix.orig to use the new patchlist filename + convention. (Kirk) + +2000-12-07 Thursday 22:17 kirk + + Just checking in the new files, three to be exact. (kirk) + +2000-12-07 Thursday 22:14 kirk + + rewrote checkin, checkout and moved patchlist to patchlist-v22 and + patchlist-v24 because we were missing the linux/init/main.c patches + and we didn't have a way to handle different files for different + versions. (kirk) + +2000-12-06 Wednesday 19:06 kirk + + Added support for the codepage 437 extended character set. (Jim and Kirk) + +2000-11-29 Wednesday 11:30 kirk + + Fixed the 2.2.xx kernels to have the almost correct backspace code. + Also move the new character output in do_con_write() to lf(). I've + experimentally put a 'space' in to see if that helps the wrapping + during console output. (Kirk) + +2000-11-27 Monday 15:38 kirk + + Fix or partial to the backspace problem at least on 2.4.0-test11. I + probably broke cursoring. + +2000-11-22 Wednesday 20:12 kirk + + Fixed a stupid unused variable by deleting it. + Fixed speakup_file_write to send raw user data to the synth. (Thanx Matt) + +2000-11-21 Tuesday 15:10 kirk + + Adjusted console.c patch for test11 of 2.4.0. + +2000-11-16 Thursday 11:42 kirk + + Modified all drivers to test for no port when clearing the holding + register. + +2000-11-16 Thursday 07:56 kirk + + Fixed console.c patch to compensate for the line movement. in Test10. + +2000-10-24 Tuesday 11:10 kirk + + Fix to the LiteTalk driver to get around the hanging when the synth isn't + on. + +2000-10-23 Monday 12:15 kirk + + Fixed dtlk driver so non-valid ports are released correctly in + dev_probe. Also added externs for synth_request_region and + release. (Kirk) + +2000-08-28 Monday 13:29 kirk + + Fixed Makefile for 2.4.0-test7 in drivers/char. + +2000-08-17 Thursday 16:21 kirk + + Birth of cursoring for version 2.4.xx kernels. + +2000-08-17 Thursday 12:06 kirk + + Okay, I proclaim the birth of cursoring, at least in the 2.2.x kernels. Next we'll try the 2.3/4.x kernels. + +2000-08-17 Thursday 11:01 kirk + + Fixed CFLAGS to EXTRA_CFLAGS in Makefile to get speakup to compile + again. The break took place between 2.4.0-test4 and test5. + +2000-07-20 Thursday 10:43 kirk + + Changed krealloc to just use kfree instead of kfree_s. Kirk + +2000-07-03 Monday 14:19 kirk + + Fixed one line in keyboard.c and changes to cvs + +2000-06-29 Thursday 16:32 andy + + Fixed checkin / cvsversion.h + +2000-06-29 Thursday 16:27 andy + + v2.3 keyboard.c + speakup_kill() fix + +2000-06-29 Thursday 16:26 andy + + v2.2.x keyboard.c + speakup_kill() fix + +2000-06-29 Thursday 16:03 andy + + v2.3 addition of speakup_kill() function (bound to sysreq key) + +2000-06-29 Thursday 16:00 andy + + v2.2 addition of speakup_kill() function (bound to sysreq key) + +2000-06-29 Thursday 15:56 andy + + v2.4 addition of speakup_kill() function (bound to sysrq key) + +2000-06-26 Monday 16:19 andy + + Added (very minimal) read() and ioctl() functions for /dev/synth. + +2000-06-23 Friday 11:16 andy + + Fixed miscdevice.h bad patch + +2000-06-22 Thursday 15:47 andy + + Fixed defkeymap.c not being built properly. + +2000-06-22 Thursday 15:17 andy + + Fixed v2.2.x zero-byte patch bug + +2000-06-22 Thursday 14:48 andy + + Checkout prunes now. + +2000-06-22 Thursday 12:48 andy + + Forgot to kill the old patch files... cleaning up. + +2000-06-22 Thursday 12:45 andy + + Changed checkin/checkout philosophy... + v2.2.x, v2.3.x, v2.4.x trees are all in this release + +2000-06-21 Wednesday 16:27 andy + + More checkin/checkout fixes. + +2000-06-21 Wednesday 16:19 andy + + Changed checkin/checkout philosophy, so 0-byte files aren't such a headache + +2000-06-21 Wednesday 14:13 andy + + New checkout script, fixing non-updating of previously patched files. + +2000-06-20 Tuesday 15:14 andy + + /dev/synth (MAJOR 10, MINOR 25) fix for v2.2.x tree + +2000-06-19 Monday 16:02 andy + + checkin script that fixes busted/nonexstant .orig files + +2000-06-19 Monday 13:08 andy + + cvsversion.h fix + speakup_decext.c fix for v2.2.x (no such member 'list' problem) + +2000-06-14 Wednesday 16:00 andy + + TODO update + +2000-06-14 Wednesday 15:25 andy + + Fixed: + checkin 'older than' bug + disabled -lock speech when spk_shut_up is set + +2000-06-14 Wednesday 13:15 andy + + Added a cvsversion.h and cvs date tracking into speakup. + +2000-06-14 Wednesday 12:44 andy + + Oops. Forgot these. + +2000-06-14 Wednesday 08:06 kirk + + Put SYNTH_MINOR #ifdefs in miscdevices.h for v2.2.x kernels. + Updated Todo file and temporarily incremented version number of speakup. (Kirk) + +2000-06-13 Tuesday 16:30 andy + + v2.4.x spanky checkin + +2000-06-13 Tuesday 15:36 andy + + v2.4.x checkin for /dev/synth stuff. + +2000-06-13 Tuesday 15:28 andy + + typo fix. + +2000-06-13 Tuesday 15:23 andy + + v2.2.x checkin for the new /dev/synth stuff. + +2000-06-13 Tuesday 15:17 andy + + Added a /dev/synth fops to speakup (MAJOR 10, MINOR 25), so that users can + use the synth without speakup (but why?). :) + + Also fixed a couple of issues with the check* scripts, and added a -p option + to checkin to just create patches. + +2000-06-12 Monday 14:36 andy + + Had a 0-byte defkeymap.c file... + +2000-06-12 Monday 14:26 andy + + Fixed the screwed up v2.2.x patch files, and added a fixorig script which + copies .orig files from /usr/src/linux.orig as stated in the + patchlist file + +2000-06-09 Friday 16:03 andy + + TODO change + +2000-06-09 Friday 14:21 andy + + added checkclean script + +2000-06-09 Friday 12:46 andy + + updates to the v2.2.x tree. + +2000-06-08 Thursday 14:59 andy + + Fixed v2.2.x diffs, and made a few changes to checkin/checkout/checkorig.. + + Namely, + checkin: + fixed bailout on CVSROOT set + diffs only for new or files that have changed since last patch + cvs adds directories properly + checks exit values of cvs commands + checkout/checkorig: + zeroes out .orig files that should exist and should be zeroed + patchlist: + now specifies patchfiles in the form: + <0|1>, + where the first number is a flag to copy the file to create + a .orig, or create a zero-byte file (0) for .orig + +2000-06-07 Wednesday 15:52 kirk + + [no log message] + +2000-06-07 Wednesday 14:15 andy + + checkin mod + +2000-06-07 Wednesday 14:14 andy + + date test added to ./checkin + +2000-06-07 Wednesday 14:11 andy + + test + +2000-06-07 Wednesday 14:09 andy + + test patch + +2000-06-07 Wednesday 13:02 kirk + + test of checkin on spanky + +2000-06-07 Wednesday 12:32 andy + + more checkin/checkout updates + +2000-06-07 Wednesday 12:19 andy + + quick print fix for checkin script + +2000-06-07 Wednesday 12:17 andy + + Fixed new tree commit/checkout/update bugs with checkin and checkout + +2000-06-07 Wednesday 12:10 kirk + + v24 tree added to cvs + +2000-06-07 Wednesday 11:30 andy + + logic error in ./checkin + + New diff-vXX directories are added now... just cp -a diff-vYY div-vXX, and + kill the CVS/ dir. + +2000-06-05 Monday 15:54 andy + + Fixed ./checkin to 'cvs add' created patch directories. + +2000-06-05 Monday 15:39 andy + + Added synth_release_region, and seperated out a speakup_drvcommon.c file, + which contains common driver stuff -- current just synth_release_region(), + and synth_request_region(). + +2000-06-02 Friday 15:32 andy + + Final test?? + +2000-06-02 Friday 14:11 andy + + bleah + +2000-06-02 Friday 13:58 andy + + another test.. *sigh* + +2000-06-02 Friday 13:57 andy + + foo + +2000-06-02 Friday 13:56 andy + + adding speakup.h.patch + +2000-06-02 Friday 13:55 andy + + bleah + +2000-06-02 Friday 13:49 andy + + test 342.7 + +2000-06-02 Friday 12:56 andy + + wrong checkout script. + +2000-06-02 Friday 12:51 andy + + Yet another test. + +2000-06-01 Thursday 15:45 andy + + test #2 + +2000-06-01 Thursday 15:40 andy + + ./checkin script test + +2000-06-01 Thursday 15:38 andy + + Initial revision + +2000-06-01 Thursday 15:38 andy + + Initial version of speakup in CVS. + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/Config.in linux.20pre2-ac1/drivers/char/speakup/Config.in --- linux.20pre2/drivers/char/speakup/Config.in 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/Config.in 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,18 @@ +bool 'Speakup console speech' CONFIG_SPEAKUP +if [ "$CONFIG_SPEAKUP" != "n" ]; then + comment 'Type "y" for each synthesizer you want built into the kernel.' + bool "Accent SA, acntsa" CONFIG_SPEAKUP_ACNTSA + bool "Accent PC, acntpc" CONFIG_SPEAKUP_ACNTPC + bool "Apollo, apolo" CONFIG_SPEAKUP_APOLO + bool "Audapter, audptr" CONFIG_SPEAKUP_AUDPTR + bool "Braille 'n' Speak, bns" CONFIG_SPEAKUP_BNS + bool "DECtalk Express, dectlk" CONFIG_SPEAKUP_DECTLK + bool "DECtalk External (old), decext" CONFIG_SPEAKUP_DECEXT + bool "DoubleTalk PC, dtlk" CONFIG_SPEAKUP_DTLK + bool "DoubleTalk LT or LiteTalk, ltlk" CONFIG_SPEAKUP_LTLK + bool "Speak Out, spkout" CONFIG_SPEAKUP_SPKOUT + bool "Transport, txprt" CONFIG_SPEAKUP_TXPRT + comment 'Enter the four to six character synth string from above or none.' + string "Default synthesizer for Speakup" CONFIG_SPEAKUP_DEFAULT "none" + bool "Use Speakup keymap by default" CONFIG_SPEAKUP_KEYMAP +fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/Makefile linux.20pre2-ac1/drivers/char/speakup/Makefile --- linux.20pre2/drivers/char/speakup/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/Makefile 2002-08-07 14:56:06.000000000 +0100 @@ -0,0 +1,25 @@ +# +# Makefile for the speakup speech output system. +# + +O_TARGET := spk.o + +obj-$(CONFIG_SPEAKUP) += speakup.o speakup_drvcommon.o +obj-$(CONFIG_SPEAKUP_DTLK) += speakup_dtlk.o +obj-$(CONFIG_SPEAKUP_LTLK) += speakup_ltlk.o +obj-$(CONFIG_SPEAKUP_ACNTPC) += speakup_acntpc.o +obj-$(CONFIG_SPEAKUP_ACNTSA) += speakup_acntsa.o +obj-$(CONFIG_SPEAKUP_TXPRT) += speakup_txprt.o +obj-$(CONFIG_SPEAKUP_BNS) += speakup_bns.o +obj-$(CONFIG_SPEAKUP_AUDPTR) += speakup_audptr.o +obj-$(CONFIG_SPEAKUP_DECTLK) += speakup_dectlk.o +obj-$(CONFIG_SPEAKUP_DECEXT) += speakup_decext.o +obj-$(CONFIG_SPEAKUP_APOLO) += speakup_apolo.o +obj-$(CONFIG_SPEAKUP_SPKOUT) += speakup_spkout.o +obj-$(CONFIG_SPEAKUP_KEYMAP) += speakupmap.o + +speakupmap.c: speakupmap.map + set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@ + +include $(TOPDIR)/Rules.make + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_acnt.h linux.20pre2-ac1/drivers/char/speakup/speakup_acnt.h --- linux.20pre2/drivers/char/speakup/speakup_acnt.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_acnt.h 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,17 @@ +/* speakup_acntpc.h - header file for speakups Accent-PC driver. */ + +#define SYNTH_IO_EXTENT 0x02 + +#define SYNTH_CLEAR 0x18 /* stops speech */ + + /* Port Status Flags */ +#define SYNTH_READABLE 0x01 /* mask for bit which is nonzero if a + byte can be read from the data port */ +#define SYNTH_WRITABLE 0x02 /* mask for RDY bit, which when set to + 1, indicates the data port is ready + to accept a byte of data. */ +#define SYNTH_QUIET 'S' /* synth is not speaking */ +#define SYNTH_FULL 'F' /* synth is full. */ +#define SYNTH_ALMOST_EMPTY 'M' /* synth has les than 2 seconds of text left */ +#define SYNTH_SPEAKING 's' /* synth is speaking and has a fare way to go */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_acntpc.c linux.20pre2-ac1/drivers/char/speakup/speakup_acntpc.c --- linux.20pre2/drivers/char/speakup/speakup_acntpc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_acntpc.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,240 @@ +/* + * speakup_acntpc.c - Accent PC driver for Linux kernel 2.3.x and speakup + * + * author: Kirk Reiser + + Copyright (C) 1998-99 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + +/* These routines are written to control the Accent PC speech + synthesizer by Aicom. They are not ment to be thought of as a device driver + in that they do not register themselves as a chr device and there + is no file_operations structure. They are strictly to provide an + interface to the Accent-pc from the speakup screen review package. +*/ + +#define KERNEL +#include +#include +#include +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include + +#include +#include "speakup_acnt.h" /* local header file for Accent values */ + +#define synth_readable() (inb_p(synth_port_control) & SYNTH_READABLE) +#define synth_writable() (inb_p(synth_port_control) & SYNTH_WRITABLE) +#define synth_full() (inb_p(synth_port_tts) == 'F') +static int synth_port_control; +/* 160 ms delay and ctrl-x as flush */ +static unsigned int synth_portlist[] = { 0x2a8, 0 }; + +static void do_catch_up(unsigned long data) +{ + unsigned long jiff_in = jiffies; + + synth_stop_timer(); + while ((synth_sent_bytes < synth_queued_bytes) && !synth_full()) { + while (synth_writable()); + + outb_p(*(synth_buffer + synth_sent_bytes++), synth_port_tts); + if (jiffies >= jiff_in + synth_jiffy_delta && + *(synth_buffer + synth_sent_bytes - 1) == ' ') { + while (synth_writable()); + + outb_p('\r', synth_port_tts); + synth_delay(synth_delay_time); + return; + } + } + if (synth_full()) { + synth_delay(synth_full_time); + return; + } + while (synth_writable()); + + outb_p('\r', synth_port_tts); + synth_sent_bytes = synth_queued_bytes = synth_timer_active = 0; + + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static void synth_write_tts(char ch) +{ + if (ch < 0x00) + return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = 0x0D; + if (ch == SYNTH_CLEAR) { /* clear all and wake sleeping */ + outb_p(ch, synth_port_tts); /* output to data port */ + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + + synth_buffer_add(ch); + + if (synth_buffering && !synth_timer_active) + synth_delay(synth_trigger_time); +} + +static int __init synth_dev_probe(void) +{ + unsigned int port_val = 0; + int i = 0; + + printk(KERN_INFO "Probing for Accent PC.\n"); + if (synth_port_tts) { + printk(KERN_INFO "probe forced to %x by kernel command line\n", + synth_port_tts); + + if (synth_request_region(synth_port_tts - 1, SYNTH_IO_EXTENT)) { + printk(KERN_WARNING "sorry, port already reserved\n"); + return -EBUSY; + } + + port_val = inw(synth_port_tts-1); + synth_port_control = synth_port_tts-1; + } else { + for (i = 0; synth_portlist[i]; i++) { + if (synth_request_region(synth_portlist[i], + SYNTH_IO_EXTENT)) { + printk(KERN_WARNING "request_region: failed " + "with 0x%x, %d\n", + synth_portlist[i], SYNTH_IO_EXTENT); + continue; + } + + port_val = inw(synth_portlist[i]); + if ((port_val &= 0xfffc) == 0x53fc) { + /* 'S' and out & input bits */ + synth_port_control = synth_portlist[i]; + synth_port_tts = synth_port_control+1; + break; + } + } + } + + if ((port_val &= 0xfffc) != 0x53fc) { /* 'S' and out&input bits */ + printk(KERN_WARNING "Accent PC: not found\n"); + synth_release_region(synth_portlist[i], SYNTH_IO_EXTENT); + return -ENODEV; + } + + printk(KERN_INFO "Accent-PC: %03x-%03x, driver version %s,\n", + synth_port_control, synth_port_control + SYNTH_IO_EXTENT - 1, + synth->version); + synth_write(synth->init, strlen(synth->init)); + return 0; +} + +static int synth_alive(void) +{ + return 1; +} + +static const char init_string[] = "\x1b=X \x1bOi\x1bT2\x1b=M\x1bN1\x1bR9\n" + "Accent PC Found\n"; +static const char reinit_string[] = ""; + +static struct spk_variable vars[] = { + { + .id = "flush", + .param = "\x18", + .build = "_", + .flags = BUILDER | HARD_DIRECT | USE_RANGE | NO_USER, + .valid = "*", + }, + { + .id = "pitch", + .param = "5", + .build = "\x1bP_", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "0,9", + }, + { + .id = "caps_start", + .param = "\x1bP8", + .build = "_", + .flags = 0, + .valid = "*", + }, + { + .id = "caps_stop", + .param = "\x1bP5", + .build = "_", + .flags = 0, + .valid = "*", + }, + { + .id = "rate", + .param = "9", + .build = "\x1bR_", + .flags = HARD_DIRECT, + .valid = "0123456789abcdefgh", + }, + { + .id = "tone", + .param = "5", + .build = "\x1bV_", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "0,9", + }, + { + .id = "volume", + .param = "9", + .build = "\x1b\x41_", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "0,9", + }, + { NULL, } +}; + +static char *config[] = { "\x18", "\x1bP5", "\x1bP8", "\x1bP5", "\x1bR9", + "\x1bV5", "\x1b\x41\x39"}; + +struct spk_synth synth_acntpc = { + .name = "acntpc", + .version = "Version-0.9", + .proc_name = "accent_pc", + .init = init_string, + .reinit = reinit_string, + .delay_time = 500, + .trigger_time = 50, + .jiffy_delta = 5, + .full_time = 1000, + .vars = vars, + .config = config, + .config_map = 0, + .probe = synth_dev_probe, + .catch_up = do_catch_up, + .write = synth_write_tts, + .is_alive = synth_alive, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_acntsa.c linux.20pre2-ac1/drivers/char/speakup/speakup_acntsa.c --- linux.20pre2/drivers/char/speakup/speakup_acntsa.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_acntsa.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,352 @@ +/* + * speakup_acntsa.c - Accent SA driver for Linux kernel 2.3.x and speakup + * + * author: Kirk Reiser + + Copyright (C) 1998-99 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + +/* These routines are written to control the Accent SA speech + synthesizer by Aicom. They are not ment to be thought of as a device driver + in that they do not register themselves as a chr device and there + is no file_operations structure. They are strictly to provide an + interface to the Accent-SA from the speakup screen review package. +*/ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +/* #include */ +#include /* for put_user_byte */ +/* #include */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants & + serial_uart_config */ +#include /* for more serial constants */ +#include /* for struct serial_state */ +#include + +#include +#include "speakup_acnt.h" /* local header file for Accent values */ + +#define synth_full() (inb_p(synth_port_tts) == 'F') +/* countdown values for serial timeouts */ +#define SPK_SERIAL_TIMEOUT 1000000 +/* countdown values transmitter/dsr timeouts */ +#define SPK_XMITR_TIMEOUT 1000000 +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 +#define NUM_DISABLE_TIMEOUTS 3 /* # of timeouts permitted before disable */ + +static int acntsa_alive; + /* 160 ms delay and ctrl-x as flush */ +#ifdef OLDSUCKYWAY +#define INIT_LEN 45 +static char INIT_STRING[] = "\x1bT2\x1b=M\x1bN1\x1bRD\x1bOp\x1bOL\x1bOi\x1b=" + "B\x1bM2\nAccent S A found\n"; +#define REINIT_LEN 49 +static char *REINIT_STRING = "\x1bT2\x1b=M\x1bN1\x1bRB\x1bOp\x1bOL\x1bOi\x1b" + "=B\x1bM3\nAccent S A restarted\n"; +#endif + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] __initdata = { + SERIAL_PORT_DFNS +}; + +static int timeouts; /* sequential number of timeouts */ + +static int wait_for_xmitr(void) +{ + int check, tmout = SPK_XMITR_TIMEOUT; + + if (acntsa_alive && timeouts >= NUM_DISABLE_TIMEOUTS) { + acntsa_alive = 0; + return 0; + } + + /* holding register empty? */ + do { + check = inb_p(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk(KERN_WARNING "Accent-SA: timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + + tmout = SPK_XMITR_TIMEOUT; + /* CTS */ + do { + check = inb_p(synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int spk_serial_out(const char ch) +{ + if (acntsa_alive && synth_port_tts) { + if (wait_for_xmitr()) { + outb_p(ch, synth_port_tts); + return 1; + } + } + return 0; +} + +static void do_catch_up(unsigned long data) +{ + unsigned long jiff_in = jiffies; + + synth_stop_timer(); + while ((synth_sent_bytes < synth_queued_bytes) && !synth_full()) { + if (!spk_serial_out(*(synth_buffer + synth_sent_bytes))) { + synth_delay(synth_full_time); + return; + } + synth_sent_bytes++; + if (jiffies >= jiff_in + synth_jiffy_delta + && *(synth_buffer + synth_sent_bytes - 1) == ' ') { + spk_serial_out('\r'); + synth_delay(synth_delay_time); + return; + } + } + + synth_sent_bytes = synth_queued_bytes = 0; + spk_serial_out('\r'); + synth_timer_active = 0; + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static void synth_write_tts(char ch) +{ + if (!acntsa_alive) + return; + if (ch < 0x00) + return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = 0x0D; + if (ch == SYNTH_CLEAR) { /* clear all and wake sleeping */ + spk_serial_out(ch); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + + synth_buffer_add(ch); + if (synth_buffering) + return; + if (synth_timer_active == 0) + synth_delay(synth_trigger_time); +} + +static inline void synth_immediate_tts(const char *buf, size_t count) +{ + while (count--) + spk_serial_out(*buf++); + return; +} + +/* + * Setup initial baud/bits/parity. Swiped from serial.c (console section) + * Return non-zero if we didn't find a serial port. + */ +static int __init serprobe(int index) +{ + struct serial_state *ser = NULL; + unsigned char test = 0; + + if (synth_port_tts) { + for (test = 0; test <= SPK_HI_TTY; test++) + if ((rs_table + test)->port == synth_port_tts) { + ser = rs_table + test; + break; + } + } else + ser = rs_table + index; + + /* don't do output yet... */ + if (synth_request_region(ser->port, 8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb(ser->port + UART_LSR) == 0xff) { + synth_release_region(ser->port, 8); + return -1; + } + outb(0x0d, ser->port); + mdelay(1); + + acntsa_alive = 1; + /* ignore any error results, if port was forced */ + if (synth_port_tts) + return 0; + + synth_port_tts = ser->port; + /* check for accent s.a now... */ + if (spk_serial_out(0x18)) + return 0; + + synth_release_region(ser->port, 8); + timeouts = acntsa_alive = synth_port_tts = 0; /* not ignoring */ + return -1; +} + +static int __init synth_dev_probe(void) +{ + int i = 0; + + printk(KERN_INFO "Probing for Accent-SA.\n"); + if (synth_port_tts) + printk(KERN_INFO "probe forced to 0x%x by " + "kernel command line\n", synth_port_tts); + + /* check ttyS0-ttyS3 */ + for (i = SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe(i) == 0) + break; /* found it */ + } + + if (acntsa_alive) { + printk(KERN_INFO "Acnt-SA: %03x-%03x, Driver Version %s,\n", + synth_port_tts, synth_port_tts + 7, synth->version); + synth_immediate_tts("\x1b=R\r", 5); + synth_write(synth->init, strlen(synth->init)); + return 0; + } + + printk(KERN_INFO "Accent-SA: not found\n"); + return -ENODEV; +} + +static int synth_alive(void) +{ + if (acntsa_alive) + return 1; /* already on */ + else if (!acntsa_alive && synth_port_tts) { + if (wait_for_xmitr() > 0) { /* restart */ + acntsa_alive = 1; + synth_write(synth->reinit, strlen(synth->reinit)); + return 2; /* reenabled */ + } else + printk(KERN_INFO "Accent-SA: can't restart synth\n"); + } + return 0; +} + +static const char init_string[] = "\x1bT2\x1b=M\x1bOi\x1bN1\x1bRB\n" + "Accent S A Found\n"; +static const char reinit_string[] = "\x1bT2\x1bOi\x1b=M\x1bN1\x1bR9\n" + "Accent S A restarted\n"; + +static struct spk_variable vars[] = { + { + .id = "flush", + .param = "\x18", + .build = "_", + .flags = BUILDER | HARD_DIRECT | USE_RANGE | NO_USER, + .valid = "*", + }, + { + .id = "pitch", + .param = "5", + .build = "\x1bP_", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "0,9", + }, + { + .id = "caps_start", + .param = "\x1bP8", + .build = "_", + .flags = 0, + .valid = "*", + }, + { + .id = "caps_stop", + .param = "\x1bP5", + .build = "_", + .flags = 0, + .valid = "*", + }, + { + .id = "rate", + .param = "9", + .build = "\x1bR_", + .flags = HARD_DIRECT, + .valid = "0123456789abcdefgh", + }, + { + .id = "tone", + .param = "5", + .build = "\x1bV_", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "0,9", + }, + { + .id = "volume", + .param = "9", + .build = "\x1b\x41_", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "0,9", + }, + { NULL, } +}; + +static char *config[] = { "\x18", "\x1bP5", "\x1bP8", "\x1bP5", "\x1bR9", + "\x1bV5", "\x1b\x41\x39" }; + +struct spk_synth synth_acntsa = { + .name = "acntsa", + .version = "Version-0.14", + .proc_name = "accent_sa", + .init = init_string, + .reinit = reinit_string, + .delay_time = 400, + .trigger_time = 5, + .jiffy_delta = 3, + .full_time = 1000, + .vars = vars, + .config = config, + .config_map = 0, + .probe = synth_dev_probe, + .catch_up = do_catch_up, + .write = synth_write_tts, + .is_alive = synth_alive, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_apolo.c linux.20pre2-ac1/drivers/char/speakup/speakup_apolo.c --- linux.20pre2/drivers/char/speakup/speakup_apolo.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_apolo.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,346 @@ +/* + * speakup_apolo.c for linux kernels 2.2.x and speakup + * + * author: Kirk Reiser + + Copyright (C) 2000 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + + +/* These routines are written to control the Apolo serial speech + synthesizer. They are not ment to be thought of as a device driver + in that they do not register themselves as a chr device and there + is no file_operations structure. They are strictly to provide an + interface to the apolo from the speakup screen review package. */ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants and + serial_uart_config */ +#include /* for more serial constants */ +#include /* for struct serial_state */ +#include +#include + +#define SYNTH_CLEAR 0x18 +#define PROCSPEECH '\r' +#define SPK_TIMEOUT 100 /* buffer timeout in ms */ +#define NUM_DISABLE_TIMEOUTS 3 /* disable synth if n timeouts */ +/* countdown values for serial timeouts */ +#define SPK_SERIAL_TIMEOUT 1000000 +/* countdown values transmitter/dsr timeouts */ +#define SPK_XMITR_TIMEOUT 1000000 +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 + +static int apolo_alive; + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +static int timeouts; /* sequential number of timeouts */ + +static int wait_for_xmitr(void) +{ + int check, tmout = SPK_XMITR_TIMEOUT; + + if (apolo_alive && timeouts >= NUM_DISABLE_TIMEOUTS) { + apolo_alive = 0; + timeouts = 0; + return 0; + } + + /* holding register empty? */ + do { + check = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk(KERN_WARNING "APOLO: timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + + tmout = SPK_XMITR_TIMEOUT; + /* CTS */ + do { + check = inb(synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int spk_serial_out(const char ch) +{ + if (apolo_alive && synth_port_tts) { + if (wait_for_xmitr()) { + outb(ch, synth_port_tts); + return 1; + } + } + return 0; +} + +static void do_catch_up(unsigned long data) +{ + unsigned long jiff_in = jiffies; + + synth_stop_timer(); + while (synth_sent_bytes < synth_queued_bytes) { + if (!spk_serial_out(*(synth_buffer+synth_sent_bytes))) { + outb(UART_MCR_DTR, synth_port_tts + UART_MCR); + outb(UART_MCR_DTR | UART_MCR_RTS, + synth_port_tts + UART_MCR); + synth_delay(synth_full_time); + return; + } + synth_sent_bytes++; + if (jiffies >= jiff_in + synth_jiffy_delta && + synth_sent_bytes > 10) { + spk_serial_out(PROCSPEECH); + synth_delay(synth_delay_time); + return; + } + } + + synth_sent_bytes = synth_queued_bytes = 0; + spk_serial_out(PROCSPEECH); + synth_timer_active = 0; + + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static void synth_write_tts(char ch) +{ + if (!apolo_alive) + return; + if (ch < 0x00) + return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = PROCSPEECH; + if (ch == SYNTH_CLEAR) { /* clear all and wake sleeping */ + spk_serial_out(ch); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + + synth_buffer_add(ch); + + if (!synth_buffering && !synth_timer_active) + synth_delay(synth_trigger_time); +} + +static inline void synth_immediate_tts(const char *buf, short count) +{ + while (count--) + spk_serial_out(*buf++); +} + +static int __init serprobe(int index) +{ + struct serial_state *ser = NULL; + + if (synth_port_tts) { + unsigned char test; + + for (test = 0; test <= SPK_HI_TTY; test++) + if ((rs_table + test)->port == synth_port_tts) { + ser = rs_table + test; + break; + } + } else + ser = rs_table + index; + + if (synth_request_region(ser->port, 8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb (ser->port + UART_LSR) == 0xff) { + synth_release_region(ser->port,8); + return -1; + } + outb(0x0d, ser->port); /* wake it up if older BIOS */ + mdelay(1); + + apolo_alive = 1; + if (synth_port_tts) + return 0; + synth_port_tts = ser->port; + + /* check for apolo now... */ + if (spk_serial_out(0x18)) + return 0; + else + printk(KERN_WARNING "port %x failed\n", synth_port_tts); + + synth_release_region(ser->port,8); + timeouts = apolo_alive = synth_port_tts = 0; + return -1; +} + +static int __init synth_dev_probe(void) +{ + int i; + + printk(KERN_INFO "Probing for Apolo.\n"); + if (synth_port_tts) + printk(KERN_INFO "Probe forced to 0x%x by " + "kernel command line\n", synth_port_tts); + for (i = SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe(i) == 0) + break; /* found it */ + } + + if (apolo_alive) { + /* found 'em */ + printk(KERN_INFO "Apolo: %03x-%03x, Driver version %s,\n", + synth_port_tts, synth_port_tts + 7, synth->version); + synth_immediate_tts(synth->init, strlen(synth->init)); + return 0; + } + + printk(KERN_INFO "Apolo: not found\n"); + return -ENODEV; +} + +static int synth_alive(void) +{ + if (apolo_alive) + return 1; /* already on */ + + if (!apolo_alive && synth_port_tts) { + if (wait_for_xmitr() > 0) { /* restart */ + apolo_alive = 1; + synth_write(synth->reinit, strlen(synth->reinit)); + return 2; /* reenabled */ + } + + printk(KERN_INFO "Apolo: can't restart synth\n"); + } + + return 0; +} + +static const char init_string[] = "@R0@D0@K1@W5\rApolo found\r"; +static const char reinit_string[] = "@R0@D0@K1@W5\rApolo Restarted\r"; + +static struct spk_variable vars[] = { + { + .id = "flush", + .param = "\x18", + .build = "_", + .flags = BUILDER | HARD_DIRECT | NO_USER, + .valid = "*", + }, + { + .id = "pitch", + .param = "8", + .build = "@F_", + .flags = HARD_DIRECT, + .valid = "0123456789abcdef", + }, + { + .id = "caps_start", + .param = "cap ", + .build = "_", + .flags = 0, + .valid = "*", + }, + { + .id = "caps_stop", + .param = "", + .build = "_", + .flags = 0, + .valid = "*", + }, + { + .id = "rate", + .param = "5", + .build = "@W_", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "1,9", + }, + { + .id = "voice", + .param = "1", + .build = "@V_", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "1,6", + }, + { + .id = "volume", + .param = "A", + .build = "@A_", + .flags = HARD_DIRECT, + .valid = "0123456789abcdef", + }, + { + .id = "language", + .param = "1", + .build = "@=_,", + .flags = NUMERIC | HARD_DIRECT | USE_RANGE, + .valid = "1,4", + }, + { NULL, }, +}; + +static char *config[] = { "\x18", "@F8", "cap ", "", "@W5", + "@V1", "@AA", "@=1,"}; + +struct spk_synth synth_apolo = { + .name = "apolo", + .version = "Version-0.10", + .proc_name = "apolo", + .init = init_string, + .reinit = reinit_string, + .delay_time = 500, + .trigger_time = 50, + .jiffy_delta = 5, + .full_time = 5000, + .vars = vars, + .config = config, + .config_map = 0, + .probe = synth_dev_probe, + .catch_up = do_catch_up, + .write = synth_write_tts, + .is_alive = synth_alive, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_audptr.c linux.20pre2-ac1/drivers/char/speakup/speakup_audptr.c --- linux.20pre2/drivers/char/speakup/speakup_audptr.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_audptr.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,311 @@ +/* + * speakup_audapter.c for linux kernels 2.2.x and speakup + * + * author: Kirk Reiser and William Acker + + Copyright (C) 1998-2000 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + + +/* These routines are written to control the audapter serial speech + synthesizer. They are not ment to be thought of as a device driver + in that they do not register themselves as a chr device and there + is no file_operations structure. They are strictly to provide an + interface to the audapter from the speakup screen review package. +*/ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants and + serial_uart_config */ +#include /* for more serial constants */ +#if (LINUX_VERSION_CODE >= 0x20332) /* v 2.3.50+ */ +#include /* for struct serial_state */ +#endif +#include +#include + +#define SYNTH_CLEAR 0x18 /* flush synth buffer */ +#define PROCSPEECH '\r' /* start synth processing speech char */ +#define SPK_TIMEOUT 100 /* buffer timeout in ms */ +#define NUM_DISABLE_TIMEOUTS 3 /* disable synth if n timeouts */ +#define SPK_SERIAL_TIMEOUT 1000000 /* countdown values for serial timeouts */ +#define SPK_XMITR_TIMEOUT 1000000 /* countdown values transmitter/dsr timeouts */ +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 + +static int audptr_alive = 0; + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] __initdata = { + SERIAL_PORT_DFNS +}; + +static int timeouts = 0; /* sequential number of timeouts */ + +static int wait_for_xmitr(void) +{ +int check, tmout = SPK_XMITR_TIMEOUT; + + if ((audptr_alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { + audptr_alive = 0; + timeouts = 0; + return 0; + } + + /* holding register empty? */ + do { + check = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk("Audapter: timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + + tmout = SPK_XMITR_TIMEOUT; + /* CTS */ + do { + check = inb(synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int spk_serial_out(const char ch) +{ + if (audptr_alive && synth_port_tts) { + if (wait_for_xmitr()) { + outb(ch, synth_port_tts); + return 1; + } + } + return 0; +} + +static unsigned char __init spk_serial_in(void) +{ +int c, lsr, tmout = SPK_SERIAL_TIMEOUT; + + do { + lsr = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) return 0xff; + } while (!(lsr & UART_LSR_DR)); + c = inb(synth_port_tts + UART_RX); + return (unsigned char) c; +} + +static void do_catch_up(unsigned long data) +{ + unsigned long jiff_in = jiffies; + +synth_stop_timer(); + while (synth_sent_bytes < synth_queued_bytes) + { + if (!spk_serial_out(*(synth_buffer+synth_sent_bytes))) { + synth_delay(synth_full_time); + return; + } + synth_sent_bytes++; + if ((jiffies >= jiff_in+synth_jiffy_delta && *(synth_buffer+synth_sent_bytes-1) == ' ') + || (jiffies > jiff_in+HZ/10)) { + spk_serial_out(PROCSPEECH); + synth_delay(synth_delay_time); + return; + } + } + +synth_sent_bytes = synth_queued_bytes = 0; +synth_timer_active = 0; +spk_serial_out(PROCSPEECH); +if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static inline void clear_it(char ch) +{ + while ((inb(synth_port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY); + outb(ch, synth_port_tts); +} + +static void synth_write_tts(char ch) +{ + if (!audptr_alive) return; + if (ch < 0x00) return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = '\r'; + if (ch == SYNTH_CLEAR) /* clear all and wake sleeping */ + { + clear_it(ch); + spk_serial_out(PROCSPEECH); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + +synth_buffer_add(ch); +if (synth_buffering) return; +if (synth_timer_active == 0) synth_delay( synth_trigger_time ); +} + +static inline void synth_immediate_tts(const char *buf, short count) +{ + while (count--) spk_serial_out(*buf++); +return; +} + +static char synth_id[40] = ""; + +static int __init serprobe(int index) +{ + struct serial_state *ser = NULL; + unsigned char test=0; + + if (synth_port_tts) { + for (test=0; test <= SPK_HI_TTY; test++) + if ( (rs_table+test)->port == synth_port_tts) { + ser = rs_table+test; + break; + } + } else ser = rs_table + index; + + if (synth_request_region(ser->port,8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb (ser->port + UART_LSR) == 0xff) { + synth_release_region(ser->port,8); + return -1; + } + mdelay(1); + + audptr_alive = 1; + /* ignore any error results, if port was forced */ + if (synth_port_tts) + return 0; + + synth_port_tts = ser->port; + test = 0; + spk_serial_out(0x05); + spk_serial_out('['); + spk_serial_out('Q'); /* query command */ + spk_serial_out(']'); /* close the query. */ + + if ((synth_id[test] = spk_serial_in()) == 'A') { + do { /* read version string from synth */ + synth_id[++test] = spk_serial_in(); + } while (synth_id[test] != '\n' && test < 32); + synth_id[++test] = 0x00; + if (test != 32) + return 0; + } + + synth_release_region(ser->port,8); + timeouts = audptr_alive = synth_port_tts = 0; /* not ignoring */ + return -1; +} + +static int __init synth_dev_probe(void) +{ +int i=0; + + printk("Probing for Audapter.\n"); + if (synth_port_tts != 0) /* set from commandline */ + printk("Probe forced to 0x%x by kernel command line.\n",synth_port_tts); + + for (i=SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe(i) == 0) break; /* found it */ + } + + if (audptr_alive) { + /* found 'em */ + printk("Audapter: %03x-%03x, Driver %s,\n", + synth_port_tts, synth_port_tts + 7, synth->version); + if (synth_id[0] == 'A') + printk("Audapter version: %s", synth_id); + synth_immediate_tts(synth->init, strlen(synth->init)); + return 0; + } + + printk("Audapter: not found\n"); + return -ENODEV; +} + + /* this is a new function required by speakup: + * if synth is not active, make it active and return 2 + * if synth is already active, return 1 + * otherwise (if it can't be made active), return 0 + */ +static int synth_alive(void) +{ + if (audptr_alive) + return 1; /* already on */ + else if ((!audptr_alive) && (synth_port_tts)) { + if (wait_for_xmitr() > 0) { /* restart */ + audptr_alive = 1; + synth_write(synth->reinit, strlen(synth->reinit)); + return 2; /* reenabled */ + } else printk("Audapter: can't restart synth\n"); + } + return 0; +} + +static const char init_string[] = "\x05[An]\x05[D1]\x05[Ol]Audapter found\r"; +static const char reinit_string[] = "\x05[An]\x05[D1]\x05[Ol]Audapter found\r"; + +static struct spk_variable vars[] = +{{"flush", "\x18\x20", "_", (BUILDER|HARD_DIRECT|NO_USER), "*"}, + {"pitch", "80", "\x05[f_]", (NUMERIC|HARD_DIRECT|USE_RANGE), "39,4500"}, + {"caps_start", "\x05[f99]", "_", 0, "*"}, + {"caps_stop", "\x05[f80]", "_", 0, "*"}, + {"rate", "0", "\x05[r_]", (NUMERIC|HARD_DIRECT|USE_RANGE), "-100,100"}, + {"tone", "9", "\x05[s_]", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,63"}, + {"volume", "21", "\x05[g_]", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,40"}, + {"punct", "n", "\x05[A_]", HARD_DIRECT, "nmsa"}, + END_VARS}; + +static char *config[] = +{"\x18\x20", "\x05[f80]", "\x05[f99]", "\x05[f80]", "\x05[r0]", "\x05[s9]", + "\x05[g21]", "\x05[An]"}; + +struct spk_synth synth_audptr = {"audptr", "Version-0.13", "audapter", + init_string, reinit_string, 400, 5, 3, 5000, + vars, config, 0, synth_dev_probe, do_catch_up, + synth_write_tts, synth_alive}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_bns.c linux.20pre2-ac1/drivers/char/speakup/speakup_bns.c --- linux.20pre2/drivers/char/speakup/speakup_bns.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_bns.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,286 @@ +/* + * speakup_bns.c for linux kernels 2.2.x and speakup + * + * author: Kirk Reiser + + Copyright (C) 1998-99 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + + +/* These routines are written to control the Braille 'n Speak serial + speech synthesizer in speech box mode. They are not ment to be + thought of as a device driver in that they do not register + themselves as a chr device and there is no file_operations + structure. They are strictly to provide an interface to the bns + from the speakup screen review package. */ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants and + serial_uart_config */ +#include /* for more serial constants */ +#if (LINUX_VERSION_CODE >= 0x20300) /* v 2.3.50+ */ +#include /* for struct serial_state */ +#endif +#include +#include + +#define SYNTH_CLEAR 0x18 +#define SPK_TIMEOUT 100 /* buffer timeout in ms */ +#define NUM_DISABLE_TIMEOUTS 3 /* disable synth if n timeouts */ +#define SPK_SERIAL_TIMEOUT 1000000 /* countdown values for serial timeouts */ +#define SPK_XMITR_TIMEOUT 1000000 /* countdown values transmitter/dsr timeouts */ +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 +#define PROCSPEECH '\r' /* process speech char */ + +static int bns_alive = 0; + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +static int wait_for_xmitr(void) +{ +static int timeouts = 0; /* sequential number of timeouts */ +int check, tmout = SPK_XMITR_TIMEOUT; + + if ((bns_alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { + bns_alive = 0; + timeouts = 0; + return 0; + } + + /* holding register empty? */ + do { + check = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk("BNS: timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + + tmout = SPK_XMITR_TIMEOUT; + /* CTS */ + do { + check = inb(synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int spk_serial_out(const char ch) +{ + if (bns_alive && synth_port_tts) { + if (wait_for_xmitr()) { + outb(ch, synth_port_tts); + return 1; + } + } + return 0; +} + +#if 0 +static unsigned char __init spk_serial_in(void) +{ +int c, lsr, tmout = SPK_SERIAL_TIMEOUT; + + do { + lsr = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) return 0xff; + } while (!(lsr & UART_LSR_DR)); + c = inb(synth_port_tts + UART_RX); + return (unsigned char) c; +} +#endif + +static void do_catch_up(unsigned long data) +{ + unsigned long jiff_in = jiffies; + +synth_stop_timer(); + while (synth_sent_bytes < synth_queued_bytes) + { + if (!spk_serial_out(*(synth_buffer+synth_sent_bytes))) { + synth_delay(synth_full_time); + return; + } + synth_sent_bytes++; + if (jiffies >= jiff_in+synth_jiffy_delta && *(synth_buffer+synth_sent_bytes-1) == ' ') + { + spk_serial_out(PROCSPEECH); + synth_delay(synth_delay_time); + return; + } + } + +synth_sent_bytes = synth_queued_bytes = 0; +spk_serial_out(PROCSPEECH); +synth_timer_active = 0; +if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static void synth_write_tts(char ch) +{ + if (!bns_alive) return; + if (ch < 0x00) return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = PROCSPEECH; + if (ch == SYNTH_CLEAR) /* clear all and wake sleeping */ + { + spk_serial_out(ch); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + +synth_buffer_add(ch); +if (synth_buffering) return; +if (synth_timer_active == 0) synth_delay( synth_trigger_time ); +return; +} + +static inline void synth_immediate_tts(const char *buf, short count) +{ + while (count--) spk_serial_out(*buf++); +return; +} + +static int __init serprobe(int index) +{ + struct serial_state *ser = NULL; + unsigned char test=0; + + if (synth_port_tts) { + for (test=0; test <= SPK_HI_TTY; test++) + if ( (rs_table+test)->port == synth_port_tts) { + ser = rs_table+test; + break; + } + } else ser = rs_table + index; + + if (synth_request_region(ser->port,8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb (ser->port + UART_LSR) == 0xff) { + synth_release_region(ser->port,8); + return -1; + } + mdelay(1); + outb('\r', ser->port); + + bns_alive = 1; + if (synth_port_tts) return 0; + synth_port_tts = ser->port; + + /* check for bns now... */ + if (spk_serial_out(SYNTH_CLEAR)) return 0; + /*spk_serial_out('\r'); * flush buffer for safety * + spk_serial_out(0x06); + mdelay(10); + if (spk_serial_in() == 0x06) return 0;*/ + + synth_release_region(ser->port,8); + bns_alive = synth_port_tts = 0; + return -1; +} + +static int __init synth_dev_probe(void) +{ +int i; + + printk("Probing for Braille 'N Speak.\n"); + if (synth_port_tts) + printk("Probe forced to 0x%x by kernel command line\n", synth_port_tts); + for (i=SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe(i) == 0) break; /* found it */ + } + + if (bns_alive) { + /* found 'em */ + printk("Braille 'N Speak: %03x-%03x, Driver version %s,\n", + synth_port_tts, synth_port_tts + 7, synth->version); + synth_immediate_tts(synth->init, strlen(synth->init)); + return 0; + } + + printk("Braille 'N Speak: not found\n"); + return -ENODEV; +} + +static int synth_alive(void) +{ + if (bns_alive) + return 1; /* already on */ + else if ((!bns_alive) && (synth_port_tts)) { + if (wait_for_xmitr() > 0) { /* restart */ + bns_alive = 1; + synth_write(synth->reinit, strlen(synth->reinit)); + return 2; /* reenabled */ + } else printk("Braille 'N Speak: can't restart synth\n"); + } + return 0; +} + +static const char init_string[] = "\x05Z\x05\x38P\x05\x43 Braille 'n Speak found\r"; +static const char reinit_string[] = "\x05Z\x05\x38P\x05\x43 Braille 'N Speak initialized\r"; + +static struct spk_variable vars[] = +{{"flush", "\x18", "_", (BUILDER|HARD_DIRECT|NO_USER), "*"}, + {"pitch", "8", "\x05_P", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,16"}, + {"caps_start", "\x05\x31\x32P", "_", 0, "*"}, + {"caps_stop", "\x05\x38P", "_", 0, "*"}, + {"rate", "8", "\x05_E", (NUMERIC|HARD_DIRECT|USE_RANGE), "1,16"}, + {"tone", "8", "\x05_T", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,16"}, + {"volume", "8", "\x05_V", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,16"}, + END_VARS}; + +static char *config[] = +{"\x18", "\x05\x38P", "\x05\x31\x32P", "\x05\x38P", "\x05\x38\x45", + "\x05\x38T", "\x05\x38V"}; + +struct spk_synth synth_bns = {"bns", "Version-0.10", "bns", + init_string, reinit_string, 500, 50, 5, 5000, + vars, config, 0, synth_dev_probe, do_catch_up, + synth_write_tts, synth_alive}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup.c linux.20pre2-ac1/drivers/char/speakup/speakup.c --- linux.20pre2/drivers/char/speakup/speakup.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,2246 @@ +/* speakup.c + review functions for the speakup screen review package. + written by: Kirk Reiser and Andy Berdan. + + Thanks to Barry Pollock for the more responsive diacritical code. + + Thanx eternal to Jim Danley for help with the extended codepage 437 + character array! Very nice job on the /proc file system entries as + well. + + Thanks also to Matt Campbell for a fine job on the driver code + building in the ability to include a number of drivers in at the + same time. + + Copyright (C) 1998 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 */ + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include +#include +#include +#include +#include /* __get_free_page() and friends */ +#include +#include +#include +#include +#include /* copy_from|to|user() and others */ +#include +#include /* for mdelay() */ +#include /* for __init */ +#include /* for misc_register, and SYNTH_MINOR */ + +#ifdef CONFIG_PROC_FS +#include +#endif + +#include +#include /* for alloc_bootmem */ + +#include "../console_macros.h" /* for x, y, attr and pos macros */ +#include /* for KT_SHIFT */ +#include /* for vc_kbd_* and friends */ +#include +#include +#include +#include + +#include /* for isdigit() and friends */ +#include +#include "symbols.h" + + +#define SPEAKUP_VERSION "Speakup v-1.00" + +/* these are globals from the kernel code */ +extern void *kmalloc (size_t, int); +extern void kfree (const void *); +extern struct tty_struct *tty; +extern int fg_console; + +/* These are ours from synth drivers. */ +extern void proc_speakup_synth_init (void); // init /proc synth-specific subtree +#ifdef CONFIG_SPEAKUP_ACNTPC +extern struct spk_synth synth_acntpc; +#endif +#ifdef CONFIG_SPEAKUP_ACNTSA +extern struct spk_synth synth_acntsa; +#endif +#ifdef CONFIG_SPEAKUP_APOLO +extern struct spk_synth synth_apolo; +#endif +#ifdef CONFIG_SPEAKUP_AUDPTR +extern struct spk_synth synth_audptr; +#endif +#ifdef CONFIG_SPEAKUP_BNS +extern struct spk_synth synth_bns; +#endif +#ifdef CONFIG_SPEAKUP_DECEXT +extern struct spk_synth synth_decext; +#endif +#ifdef CONFIG_SPEAKUP_DECTLK +extern struct spk_synth synth_dectlk; +#endif +#ifdef CONFIG_SPEAKUP_DTLK +extern struct spk_synth synth_dtlk; +#endif +#ifdef CONFIG_SPEAKUP_LTLK +extern struct spk_synth synth_ltlk; +#endif +#ifdef CONFIG_SPEAKUP_SPKOUT +extern struct spk_synth synth_spkout; +#endif +#ifdef CONFIG_SPEAKUP_TXPRT +extern struct spk_synth synth_txprt; +#endif + +#define MIN(a,b) ( ((a) < (b))?(a):(b) ) +#define krealloc(ptr,newsize) ( kfree(ptr), ptr = kmalloc(newsize,GFP_KERNEL) ) +#define toctrl(x) ( ( ((x) >= 'A') && ((x) <='Z')) ? ((x) - 'A') : \ + (((x) >= 'a') && ((x) <= 'z')) ? ((x) - 'a') : 0 ) +#define allowable(c) ( ((c) > 0x2f && (c) < 0x3a) \ + || (((c)&0x5f) > 0x40 && ((c)&0x5f) < 0x5b) \ + || (strchr(" \n,.'-:?!", (c)) != NULL) \ + ) + +static int errno; +char *spk_cfg[] = { DEFAULT_SPKUP_VARS }; +long spk_cfg_map; /* which ones have been re'alloc'ed */ +int synth_file_inuse; +static struct spk_variable spk_vars[] = { SPKUP_VARS }; +static unsigned char pitch_shift; +char saved_punc_level = 0x30; +char mark_cut_flag; +unsigned short mark_x; +unsigned short mark_y; +static char synth_name[10] = CONFIG_SPEAKUP_DEFAULT; +static struct spk_synth *synths[] = { +#ifdef CONFIG_SPEAKUP_ACNTPC + &synth_acntpc, +#endif +#ifdef CONFIG_SPEAKUP_ACNTSA + &synth_acntsa, +#endif +#ifdef CONFIG_SPEAKUP_APOLO + &synth_apolo, +#endif +#ifdef CONFIG_SPEAKUP_AUDPTR + &synth_audptr, +#endif +#ifdef CONFIG_SPEAKUP_BNS + &synth_bns, +#endif +#ifdef CONFIG_SPEAKUP_DECEXT + &synth_decext, +#endif +#ifdef CONFIG_SPEAKUP_DECTLK + &synth_dectlk, +#endif +#ifdef CONFIG_SPEAKUP_DTLK + &synth_dtlk, +#endif +#ifdef CONFIG_SPEAKUP_LTLK + &synth_ltlk, +#endif +#ifdef CONFIG_SPEAKUP_SPKOUT + &synth_spkout, +#endif +#ifdef CONFIG_SPEAKUP_TXPRT + &synth_txprt, +#endif + NULL, /* Leave room for one dynamically registered synth. */ + NULL +}; + +#define LineWrapBleep 0x01 +#define LineWrapMask 0xFE +#define AttributeChangeBleep 0x02 +#define AttributeChangeMask 0xFD + +#define punc_level (*(spk_cfg[PUNCT_LEVEL])) +#define spell_delay (*(spk_cfg[SPELL_DELAY])-0x30) +#define key_echo (*(spk_cfg[KEY_ECHO])-0x30) + +/* how about a couple of arrays to index our colours and attributes */ +char *fg_color[] = { + "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", + "grey", "bright blue", "bright green", "bright cyan", "bright red", + "bright magenta", "bright yellow", "bright white" +}; + +char *bg_color[] = { + "black", "blue", "green", "cyan", "red", "magenta", "yellow", "white", + "blinking black", "blinking blue", "blinking green", "blinking cyan", + "blinking red", "blinking magenta", "blinking yellow", "blinking white" +}; + +char *phonetic[] = { + "alpha", "beta", "charley", "delta", "echo", "fox", "gamma", "hotel", + "india", "juleiet", "keelo", "leema", "mike", "november", "oscar", + "papa", + "quebec", "romeo", "seeara", "tango", "uniform", "victer", "wiskey", + "x ray", + "yankee", "zooloo" +}; + +// array of 256 char pointers (one for each ASCII character description) +// initialized to default_chars and user selectable via /proc/speakup/characters +char *characters[256]; + +char *default_chars[256] = { + "null", "control-a", "control-b", "control-c", "control-d", "control-e", + "control-f", "control-g", "control-h", "control-i", "control-j", + "control-k", + "control-l", "control-m", "control-n", "control-o", "control-p", + "control-q", + "control-r", "control-s", "control-t", "control-u", "control-v", + "control-w", + "control-x", "control-y", "control-z", NULL, NULL, NULL, NULL, NULL, + "space", "bang!", "quote", "number", "dollars", "percent", "and", + "tick", + "left paren", "right paren", "star", "plus", "comma,", "dash", "dot", + "slash", + "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", + "nine", + "colon", "semi", "less", "equals", "greater", "question?", "at", "eigh", + "b", + "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", + "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", + "y", "zehd", "left bracket", "backslash", "right bracket", "caret", + "line", + "accent", "eigh", "b", "c", "d", "e", "f", "g", "h", "i", "j", + "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", + "v", "w", "x", "y", "zehd", "left brace", "bar", "right brace", + "tihlduh", "cap delta", "cap see cedilla", "u oomlout", "e acute", + "eigh circumflex", "eigh oomlout", "eigh grave", "eigh ring", + "see cedilla", + "e circumflex", "e oomlout", "e grave", "i oomlout", "i circumflex", + "i grave", "cap eigh oomlout", "cap eigh ring", "cap e acute", + "eigh e dipthong", "cap eigh cap e dipthong", "o circumflex", + "o oomlout", + "o grave", "u circumflex", "u grave", "y oomlout", "cap o oomlout", + "cap u oomlout", "cents", "pounds", "yen", "peseta", "florin", + "eigh acute", + "i acute", "o acute", "u acute", "n tilde", "cap n tilde", + "feminine ordinal", + "masculin ordinal", "inverted question", + "reversed not", "not", "half", "quarter", "inverted bang", + "much less than", "much greater than", "dark shading", "medium shading", + "light shading", "verticle line", "left tee", "double left tee", + "left double tee", "double top right", "top double right", + "double left double tee", "double vertical line", + "double top double right", + "double bottom double right", "double bottom right", + "bottom double right", + "top right", "left bottom", "up tee", "tee down", "tee right", + "horizontal line", "cross bars", "tee double right", "double tee right", + "double left double bottom", "double left double top", + "double up double tee", + "double tee double down", "double tee double right", + "double horizontal line", + "double cross bars", "up double tee", "double up tee", + "double tee down", + "tee double down", "double left bottom", "left double bottom", + "double left top", "left double top", "double vertical cross", + "double horizontal cross", "bottom right", "left top", "solid square", + "solid lower half", "solid left half", "solid right half", + "solid upper half", + "alpha", "beta", "cap gamma", "pie", "cap sigma", "sigma", "mu", "tou", + "cap phigh", "cap thayta", "cap ohmega", "delta", "infinity", "phigh", + "epsilaun", "intersection", "identical to", "plus or minus", + "equal grater than", "less than equal", "upper integral", + "lower integral", + "divided by", "almost equal", "degrees", "centre dot", + "bullet", "square root", "power", "squared", "black square", + "white space" +}; + +int spk_keydown; +int bell_pos; +static int spk_lastkey; + +struct spk_t *speakup_console[MAX_NR_CONSOLES]; + +int spk_setup (char *str) +{ + int ints[4]; + str = get_options (str, ARRAY_SIZE (ints), ints); + if (ints[0] > 0 && ints[1] >= 0) + synth_port_tts = ints[1]; + return 1; +} + +int spk_ser_setup (char *str) +{ + int lookup[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; + int ints[4]; + str = get_options (str, ARRAY_SIZE (ints), ints); + if (ints[0] > 0 && ints[1] >= 0) + synth_port_tts = lookup[ints[1]]; + return 1; +} + +int spk_synth_setup (char *str) +{ + size_t len = MIN (strlen (str), 9); + memcpy (synth_name, str, len); + synth_name[len] = '\0'; + return 1; +} + +__setup ("speakup_port=", spk_setup); +__setup ("speakup_ser=", spk_ser_setup); +__setup ("speakup_synth=", spk_synth_setup); + +void speakup_savekey (unsigned char ch) +{ + /* keydown is seperate since they are handled by two + seperate routines */ + if (ch) + spk_keydown++; + else + spk_keydown = 0; + // keypad slash key is not calling this function as it should -- jd + spk_lastkey = ch; +} + +static void spk_control (int currcons, int value) +{ + if (spk_shut_up || (synth == NULL)) + return; + /* interrupt active + not shut up + not shift key (value == 0) */ + if ((*spk_cfg[NO_INTERRUPT] - 0x30) && value) { + synth_write (synth->config[FLUSH], + strlen (synth->config[FLUSH])); + synth_write (synth->config[PITCH], + strlen (synth->config[PITCH])); + } + + if ((*spk_cfg[SAY_CONTROL] - 0x30 == 0) && (value < 4)) + return; + switch (value) { + case 0: + spkup_write ("shift\n", 6); + break; + case 1: + spkup_write ("insert\n", 7); + break; + case 2: + spkup_write ("control\n", 8); + break; + case 3: + spkup_write ("ault\n", 5); + break; + + case 10: + spkup_write ("caps lock on\n", 13); + break; + case 11: + spkup_write ("caps lock off\n", 14); + break; + case 12: + spkup_write ("numm lock on\n", 13); + break; + case 13: + spkup_write ("numm lock off\n", 14); + break; + case 14: + spkup_write ("scroll lock on\n", 15); + break; + case 15: + spkup_write ("scroll lock off\n", 16); + break; + } +} + +static void s2i (char *start, int length, int *dest) +{ + int i; + for (i = 0; i < length; i++) { + *dest *= 10; + *dest += start[i] - 0x30; + } +} + +static inline void bleep (unsigned short val) +{ + int time = 0; + val = (val + 1) * 75 + 75; + time = *(spk_cfg[BLEEP_TIME]) - 0x30; + if (*(spk_cfg[BLEEP_TIME] + 1) != '\0') { + time *= 10; + time += (*(spk_cfg[BLEEP_TIME] + 1) - 0x30); + } + kd_mksound (val, time); +} + +void speakup_reset (int currcons, unsigned char type) +{ + + spk_shut_up &= 0xfe; + if (spk_killed) + return; + spk_parked &= 0xfe; + if (*(spk_cfg[NO_INTERRUPT]) - 0x30) + return; + spk_keydown++; + + if (synth == NULL) + return; + synth_write (synth->config[FLUSH], strlen (synth->config[FLUSH])); + if (pitch_shift) { + synth_write (synth->config[PITCH], + strlen (synth->config[PITCH])); + pitch_shift = 0; + } +} + +void speakup_shut_up (unsigned int currcons) +{ + spk_shut_up |= 0x01; + speakup_date (currcons); + if (synth == NULL) + return; + synth_write (synth->config[FLUSH], strlen (synth->config[FLUSH])); + synth_write (synth->config[PITCH], strlen (synth->config[PITCH])); +} + +int speakup_diacr (unsigned char ch, unsigned int currcons) +{ + static unsigned char *buf = "\0\0\0\0\0"; + static int num; + int tmp = 0; + + buf[num++] = ch; + buf[num] = '\0'; + + if ((ch == '$' || ch == 27 || (ch > 47 && ch < 58) || ch == 'x' + || ch == 'y' || ch == '+' || ch == '-') && num < 5) + switch (ch) { + case '$': + case 0x1b: /* cancel */ + num = 0; + buf[0] = '\0'; + return 1; + case 'x': + case 'y': + if (buf[0] == '+' || buf[0] == '-') { + s2i (buf + 1, num - 2, &tmp); + tmp = (buf[0] == '+') ? tmp : -tmp; + + /* set tmp to new position */ + if (ch == 'x') + tmp = tmp + spk_x; + else + tmp = tmp + spk_y; + } else { + s2i (buf, num - 1, &tmp); + --tmp; + } + + /* range checking */ + if (ch == 'x') { + if (tmp > video_num_columns) + tmp = video_num_columns; + if (tmp < 0) + tmp = 0; + } else { + if (tmp > video_num_lines) + tmp = video_num_lines; + if (tmp < 0) + tmp = 0; + } + + /* move it, baby... */ + if (ch == 'x') { + spk_pos -= spk_x * 2; + /* set x */ + spk_x = tmp; + spk_pos += tmp * 2; + } else { + /* zero y */ + spk_pos -= spk_y * video_size_row; + /* set y */ + spk_y = tmp; + spk_pos += tmp * video_size_row; + } + num = 0; + buf[0] = '\0'; + return 1; /* no more characters req'd */ + } else { + /* no valid terminator characters or wrong key */ + num = 0; + buf[0] = '\0'; + if (!spk_killed) + spkup_write ("Error\n", 6); + return -1; + } + return 0; /* I want more! */ +} + +void speakup_kill (unsigned int currcons) +{ + if (spk_killed) { /* dead */ + spk_shut_up &= ~0x40; + spkup_write ("Eyem a Lighve!\n", 15); + } else { + spkup_write ("You killed speak up!\n", 21); + spk_shut_up |= 0x40; + } +} + +void speakup_off (unsigned int currcons) +{ + char val = 0; + + if (spk_shut_up & 0x40) + return; /* if speech is killed don't bother. */ + if ((synth == NULL) || (val = synth->is_alive ())) { + /* re-enables synth, if disabled */ + if (spk_shut_up & 0x80 || (val == 2)) { + spk_shut_up &= 0x7f; + spkup_write ("hey. That's better!\n", 20); + } else { + spk_shut_up |= 0x80; + spkup_write ("You turned me off!\n", 19); + } + } + speakup_date (currcons); +} + +void function_announce (unsigned int currcons) +{ + if (spk_sound & 0x40) { + spk_sound &= 0xbf; + spkup_write ("Function announce off.\n", 23); + } else { + spk_sound |= 0x40; + spkup_write ("Function announce on.\n", 22); + } +} + +void speakup_parked (unsigned int currcons) +{ + if (spk_parked & 0x80) { + spk_parked = 0; + spkup_write ("unparked!\n", 10); + } else { + spk_parked |= 0x80; + spkup_write ("parked!\n", 8); + } +} + +void speakup_cursoring (unsigned int currcons) +{ + if (spk_shut_up & 0x02) { + spk_shut_up &= 0xfd; + spkup_write ("cursoring off!\n", 15); + } else { + spk_shut_up |= 0x02; + spkup_write ("cursoring on!\n", 14); + } +} + +void speakup_cut (unsigned int currcons, struct tty_struct *tty) +{ + int ret; + unsigned char args[6*sizeof(short)]; + unsigned short *arg; + static char *buf = "speakup_cut: set_selection failed: "; + + if (mark_cut_flag) { + /* cut */ + arg = (unsigned short *)args + 1; + arg[0] = mark_x + 1; + arg[1] = mark_y + 1; + arg[2] = (unsigned short)spk_x + 1; + arg[3] = (unsigned short)spk_y + 1; + arg[4] = 0; /* char-by-char selection */ + mark_cut_flag = 0; + spkup_write ("cut\n", 4); + + if ((ret = set_selection ((const unsigned long)args+sizeof(short)-1, tty, 0))) { + switch (ret) { + case -EFAULT : + printk(KERN_WARNING "%sEFAULT\n", buf); + break; + case -EINVAL : + printk(KERN_WARNING "%sEINVAL\n", buf); + break; + case -ENOMEM : + printk(KERN_WARNING "%sENOMEM\n", buf); + break; + } + } + } else { + /* mark */ + mark_cut_flag = 1; + mark_x = spk_x; + mark_y = spk_y; + spkup_write ("mark\n", 5); + clear_selection(); + } +} + +void speakup_paste (struct tty_struct *tty) +{ + spkup_write ("paste\n", 6); + paste_selection (tty); +} + +void say_attributes (int currcons) +{ + char buf[80], cnt; + + if (synth == NULL) + return; + spk_parked |= 0x01; + cnt = sprintf (buf, "%s on %s\n", *(fg_color + (spk_attr & 0x0f)), + *(bg_color + (spk_attr >> 4))); + synth_write (buf, cnt); +} + +void say_curr_char (unsigned int currcons) +{ + unsigned short ch; + char buf[128]; + + if (synth == NULL) + return; + spk_parked |= 0x01; + spk_old_attr = spk_attr; + ch = scr_readw ((unsigned short *) spk_pos); + spk_attr = ((ch & 0xff00) >> 8); + if (spk_attr != spk_old_attr && spk_sound & AttributeChangeBleep) + bleep (spk_y); + if ((ch & 0x00ff) > 0x40 && (ch & 0x00ff) < 0x5b) { + pitch_shift++; + ch = sprintf (buf, "%s %s %s", synth->config[CAPS_START], + characters[(unsigned char) ch], + synth->config[CAPS_STOP]); + } else + ch = sprintf (buf, " %s ", characters[(unsigned char) ch]); + synth_write (buf, ch); +} + +void say_phonetic_char (unsigned int currcons) +{ + unsigned short ch; + char buf[64]; + + if (synth == NULL) + return; + spk_parked |= 0x01; + spk_old_attr = spk_attr; + ch = scr_readw ((unsigned short *) spk_pos); + spk_attr = ((ch & 0xff00) >> 8); + if ((ch & 0x00ff) > 0x40 && (ch & 0x00ff) < 0x5b) + ch = ((ch - 0x41) & 0x00ff); + else if ((ch & 0x00ff) > 0x60 && (ch & 0x00ff) < 0x7b) + ch = ((ch - 0x61) & 0x00ff); + else { + say_curr_char (currcons); + return; + } + ch = sprintf (buf, "%s\n", *(phonetic + ch)); + synth_write (buf, ch); +} + +void say_prev_char (unsigned int currcons) +{ + spk_parked |= 0x01; + if (spk_x == 0) { + spkup_write ("left edge\n", 10); + return; + } + spk_x--; + spk_pos -= 2; + say_curr_char (currcons); +} + +void say_next_char (unsigned int currcons) +{ + spk_parked |= 0x01; + if (spk_x == video_num_columns - 1) { + spkup_write ("right edge\n", 11); + return; + } + spk_x++; + spk_pos += 2; + say_curr_char (currcons); +} + +void say_curr_word (unsigned int currcons) +{ + unsigned long cnt = 0, tmpx = 0, tmp_pos = spk_pos; + char buf[video_num_columns + 2]; + + spk_parked |= 0x01; + spk_old_attr = spk_attr; + tmpx = spk_x; + if (((char) scr_readw ((unsigned short *) tmp_pos) == 0x20) + && ((char) scr_readw ((unsigned short *) tmp_pos + 1) > 0x20)) { + tmp_pos += 2; + tmpx++; + } else + while ((tmpx > 0) + && ((scr_readw ((unsigned short *) tmp_pos - 1) & 0x00ff) + != 0x20)) { + tmp_pos -= 2; + tmpx--; + } + spk_attr = + (unsigned char) (scr_readw ((unsigned short *) tmp_pos) >> 8); + while (tmpx < video_num_columns) { + if ((*(buf + cnt) = + (char) scr_readw ((unsigned short *) tmp_pos)) == 0x20) + break; + tmpx++; + tmp_pos += 2; + cnt++; + } + *(buf + cnt++) = '\n'; + saved_punc_level = punc_level; + punc_level = ALL; + spkup_write (buf, cnt); + punc_level = saved_punc_level; +} + +void say_prev_word (unsigned int currcons) +{ + spk_parked |= 0x01; + if (((scr_readw ((unsigned short *) spk_pos) & 0x00ff) > 0x20) + && (((scr_readw ((unsigned short *) spk_pos - 1) & 0x00ff) == 0x20) + || spk_x == 0)) { + if (spk_x > 0) { + spk_x--; + spk_pos -= 2; + } else { + if (spk_y > 0) { + spk_y--; + spk_pos -= 2; + spk_x = video_num_columns - 1; + if (spk_sound & LineWrapBleep) + bleep (spk_y); + else + spkup_write ("left edge.\n", 11); + } else { + spkup_write ("top edge.\n", 10); + return; + } + } + } + + while (!(((scr_readw ((unsigned short *) spk_pos) & 0x00ff) > 0x20) + && + (((scr_readw ((unsigned short *) spk_pos - 1) & 0x00ff) == + 0x20) + || spk_x == 0))) { + if (spk_x > 0) { + spk_x--; + spk_pos -= 2; + } else { + if (spk_y > 0) { + spk_y--; + spk_pos -= 2; + spk_x = video_num_columns - 1; + if (spk_sound & LineWrapBleep) + bleep (spk_y); + else + spkup_write ("left edge.\n", 11); + } else { + spkup_write ("top edge.\n", 10); + break; + } + } + } + + say_curr_word (currcons); +} + +void say_next_word (unsigned int currcons) +{ + spk_parked |= 0x01; + if (((scr_readw ((unsigned short *) spk_pos) & 0x00ff) > 0x20) + && (((scr_readw ((unsigned short *) spk_pos - 1) & 0x00ff) == 0x20) + || spk_x == 0)) { + if (spk_x < video_num_columns - 1) { + spk_x++; + spk_pos += 2; + } else { + if (spk_y < video_num_lines - 1) + spk_y++; + else { + spkup_write ("bottom edge.\n", 13); + return; + } + spk_x = 0; + spk_pos += 2; + if (spk_sound & LineWrapBleep) + bleep (spk_y); + else + spkup_write ("right edge.\n", 12); + } + } + + while (!(((scr_readw ((unsigned short *) spk_pos) & 0x00ff) > 0x20) + && + (((scr_readw ((unsigned short *) spk_pos - 1) & 0x00ff) == + 0x20) + || spk_x == 0))) { + if (spk_x < video_num_columns - 1) { + spk_x++; + spk_pos += 2; + } else { + if (spk_y < video_num_lines - 1) + spk_y++; + else { + spkup_write ("bottom edge.\n", 13); + break; + } + spk_x = 0; + spk_pos += 2; + if (spk_sound & LineWrapBleep) + bleep (spk_y); + else + spkup_write ("right edge.\n", 12); + } + } + + say_curr_word (currcons); +} + +void spell_word (unsigned int currcons) +{ + unsigned long tmpx = spk_x, tmp_pos = spk_pos; + char *delay_str[] = { " ", ", ", ". ", ". . ", ". . . " }; + char dnum[] = { 1, 2, 2, 4, 6 }; + + if (synth == NULL) + return; + spk_parked |= 0x01; + if (((char) scr_readw ((unsigned short *) spk_pos) == 0x20) + && ((char) scr_readw ((unsigned short *) spk_pos + 1) > 0x20)) { + spk_pos += 2; + spk_x++; + } else + while ((spk_x > 0) + && ((scr_readw ((unsigned short *) spk_pos - 1) & 0x00ff) + != 0x20)) { + spk_pos -= 2; + spk_x--; + } + + for (; spk_x < video_num_columns; spk_x++, spk_pos += 2) { + if ((char) scr_readw ((unsigned short *) spk_pos) == 0x20) + break; + synth_write (delay_str[spell_delay - 1], dnum[spell_delay - 1]); + say_curr_char (currcons); + } + + spk_pos = tmp_pos; + spk_x = tmpx; +} + +void say_curr_line (unsigned int currcons) +{ + unsigned long tmp; + unsigned char buf[video_num_columns + 2], i = 0, not_blank = 0; + + spk_parked |= 0x01; + spk_old_attr = spk_attr; + spk_attr = + (unsigned char) (scr_readw ((unsigned short *) spk_pos) >> 8); + for (tmp = spk_pos - (spk_x * 2); + tmp < spk_pos + ((video_num_columns - spk_x) * 2); tmp += 2) { + *(buf + i) = (unsigned char) scr_readw ((unsigned short *) tmp); + if (*(buf + i++) != 0x20) + not_blank++; + } + *(buf + i++) = '\n'; + + if (not_blank) + spkup_write (buf, i); + else + spkup_write ("blank\n", 6); +} + +void say_prev_line (unsigned int currcons) +{ + spk_parked |= 0x01; + if (spk_y == 0) { + spkup_write ("top edge.\n", 10); + return; + } + + spk_y--; + spk_pos -= video_size_row; + say_curr_line (currcons); +} + +void say_next_line (unsigned int currcons) +{ + spk_parked |= 0x01; + if (spk_y == video_num_lines - 1) { + spkup_write ("bottom edge.\n", 13); + return; + } + + spk_y++; + spk_pos += video_size_row; + say_curr_line (currcons); +} + +static inline void say_line_from_to (unsigned int currcons, unsigned long from, unsigned long to) +{ + unsigned long tmp; + unsigned char buf[video_num_columns + 2], i = 0, not_blank = 0; + + spk_parked |= 0x01; + spk_old_attr = spk_attr; + spk_attr = + (unsigned char) (scr_readw ((unsigned short *) spk_pos) >> 8); + for (tmp = origin + (spk_y * video_size_row) + (from * 2); + tmp < origin + (spk_y * video_size_row) + (to * 2); tmp += 2) { + *(buf + i) = (unsigned char) scr_readw ((unsigned short *) tmp); + if (*(buf + i++) != 0x20) + not_blank++; + } + *(buf + i++) = '\n'; + + if (not_blank) + spkup_write (buf, i); + else + spkup_write ("blank\n", 6); +} + +void say_screen (unsigned int currcons) +{ + unsigned long tmp_pos = origin; + unsigned char c, blank = 0; + + spk_parked |= 0x01; + while (tmp_pos < origin + (video_num_lines * video_size_row)) { + if ((c = + (unsigned char) scr_readw ((unsigned long *) tmp_pos)) == + 0x20) + blank++; + else + blank = 0; + tmp_pos += 2; + if (blank > 1) + continue; + spkup_write (&c, 1); +/* insert a space at the end of full lines */ + if ((tmp_pos - origin) % video_size_row == 0 && blank == 0) + spkup_write(" ", 1); + } +} + +static inline void say_screen_from_to (unsigned int currcons, unsigned long from, unsigned long to) +{ + unsigned long tmp_pos; + unsigned char c, blank = 0; + + spk_parked |= 0x01; + if (from > 0) + tmp_pos = origin + ((from - 1) * video_size_row); + else + tmp_pos = origin; + if (to > video_num_lines) + to = video_num_lines; + while (tmp_pos < origin + (to * video_size_row)) { + if ((c = + (unsigned char) scr_readw ((unsigned long *) tmp_pos)) == + 0x20) + blank++; + else + blank = 0; + tmp_pos += 2; + if (blank > 1) + continue; + spkup_write (&c, 1); + } +} + +void top_edge (unsigned int currcons) +{ + spk_parked |= 0x01; + spk_pos -= spk_y * video_size_row; + spk_y = 0; + say_curr_line (currcons); +} + +void bottom_edge (unsigned int currcons) +{ + spk_parked |= 0x01; + spk_pos += (video_num_lines - spk_y - 1) * video_size_row; + spk_y = video_num_lines - 1; + say_curr_line (currcons); +} + +void left_edge (unsigned int currcons) +{ + spk_parked |= 0x01; + spk_pos -= spk_x * 2; + spk_x = 0; + say_curr_char (currcons); +} + +void right_edge (unsigned int currcons) +{ + spk_parked |= 0x01; + spk_pos += (video_num_columns - spk_x - 1) * 2; + spk_x = video_num_columns - 1; + say_curr_char (currcons); +} + +void say_position (unsigned int currcons) +{ + char buf[40]; + int count; + + spk_parked |= 0x01; + count = + sprintf (buf, "line %ld, position %ld, t t y. %d\n", spk_y + 1, + spk_x + 1, currcons + 1); + spkup_write (buf, count); +} + +// Added by brianb +void say_char_num (unsigned int currcons) +{ + char buf[32]; + unsigned short ch; + + spk_parked |= 0x01; + ch = scr_readw ((unsigned short *) spk_pos); + ch &= 0x0ff; + ch = sprintf (buf, "hex %02x, decimal %d\n", ch, ch); + spkup_write (buf, ch); +} + +/* these are stub functions to keep keyboard.c happy. */ + +void say_from_top (unsigned int currcons) +{ + say_screen_from_to (currcons, 0, spk_y + 1); +} + +void say_to_bottom (unsigned int currcons) +{ + say_screen_from_to (currcons, spk_y + 1, video_num_lines); +} + +void say_from_left (unsigned int currcons) +{ + say_line_from_to (currcons, 0, spk_x); +} + +void say_to_right (unsigned int currcons) +{ + say_line_from_to (currcons, spk_x, video_num_columns); +} + +/* end of stub functions. */ + +extern int synth_init (void); +extern char synth_buffering; /* flag to indicate we're buffering */ +unsigned short skip_count = 0; + +void spk_skip (unsigned short cnt) +{ + skip_count += cnt; +} + +int spkup_write (const char *buf, int count) +{ + static unsigned short rep_count; + static char old_ch, oldest_ch, count_buf[30], punc_buf[128]; + int in_count = count; + char *punc_search = NULL; + + if (synth == NULL) + return count; + spk_keydown = 0; + while (count--) { + if (rep_count) { + if (*buf == old_ch) { + buf++; + rep_count++; + continue; + } else { + if (rep_count > 3) { + synth_write (count_buf, + sprintf (count_buf, + " repeated %d times. \n", + rep_count)); + } + rep_count = 0; + } + } + if (!key_echo && (*buf == spk_lastkey)) + goto forget_about_it; + // keypad slash is the only key that slips through and speaks when + // key_echo is 0, not sure why -- bug + if (((*buf == spk_lastkey) || + ((punc_search = + strchr (*(spk_cfg + PUNC_OFFSET + (punc_level - 0x30)), + *buf)) != NULL)) + && *buf != 0x00) { + if ((*buf == spk_lastkey) && (*buf & 0x00ff) > 0x40 + && (*buf & 0x00ff) < 0x5b) { + /* keyboard caps character */ + pitch_shift++; + synth_write (punc_buf, + sprintf (punc_buf, "%s %s %s", + synth->config[CAPS_START], + *(characters + *buf), + synth-> + config[CAPS_STOP])); + } else + synth_write (punc_buf, + sprintf (punc_buf, " %s ", + *(characters + *buf))); + } else if (allowable (*buf)) + synth->write (*buf); + + forget_about_it: + if (*buf == old_ch && *buf == oldest_ch && rep_count == 0 + && punc_search != NULL) + rep_count = 3; + oldest_ch = old_ch; + old_ch = *buf++; + } + + spk_lastkey = 0; + if (in_count > 3 && rep_count > 3) { + synth_write (count_buf, + sprintf (count_buf, " repeated %d times. \n", + rep_count)); + rep_count = 0; + } + return 0; +} + +char *strlwr (char *s) +{ + char *p = s; + while (*p) + { + *p = tolower (*p); + p++; + } + return s; +} + +void __init speakup_open (unsigned int currcons) +{ + int i = 0; + + strlwr (synth_name); + while ((synth == NULL) && (synths[i] != NULL)) { + if (strcmp (synths[i]->name, synth_name) == 0) + synth = synths[i]; + else + i++; + } + + if ((synth == NULL) && (strcmp (synth_name, "none") != 0)) + printk (KERN_WARNING "Speakup: unknown synthesizer \"%s\"\n", + synth_name); + + if ((synth != NULL) && synth_init ()) { + spk_shut_up |= 0x80; /* hopefully let the system work without the synth */ + return; + } + synth_buffering = 0; +} + +// provide a file to users, so people can send to /dev/synth + +static ssize_t speakup_file_write (struct file *fp, const char *buf, + size_t nbytes, loff_t * ppos) +{ + size_t count = nbytes; + const char *ptr = buf; + + int bytes; + char tbuf[256]; + + while (count > 0) { + bytes = MIN (count, sizeof (tbuf)); + if (copy_from_user (&tbuf, ptr, bytes)) + return -EFAULT; + + count -= bytes; + ptr += bytes; + + synth_write (tbuf, bytes); + } + return (ssize_t) nbytes; +} + +static int speakup_file_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return 0; // silently ignore +} + +static ssize_t speakup_file_read (struct file *fp, char *buf, size_t nbytes, loff_t * ppos) +{ + /* *nod* *nod* We'll take care of that, ma'am. *flush* */ + return 0; +} + +static int speakup_file_open (struct inode *ip, struct file *fp) +{ + if (synth_file_inuse) + return -EBUSY; + else if (synth == NULL) + return -ENODEV; + + synth_file_inuse++; + return 0; +} + +static int speakup_file_release (struct inode *ip, struct file *fp) +{ + synth_file_inuse = 0; + return 0; +} + +static struct file_operations synth_fops = { + .owner = THIS_MODULE, + .read = speakup_file_read, + .write = speakup_file_write, + .ioctl = speakup_file_ioctl, + .open = speakup_file_open, + .release = speakup_file_release, +}; + +void speakup_register_devsynth (void) +{ + static struct miscdevice synth_device; + + synth_device.minor = SYNTH_MINOR; + synth_device.name = "synth"; + synth_device.fops = &synth_fops; + + if (misc_register (&synth_device)) + printk ("speakup: Couldn't initialize miscdevice /dev/synth.\n"); + else + printk + ("speakup: initialized device: /dev/synth, node (MAJOR 10, MINOR 25)\n"); +} + +static void reset_default_chars (void) +{ + static int first_pass = 1; + int i; + + for (i = 0; i < 256; ++i) { + // if pointing to allocated memory, free it! + if (first_pass || characters[i] != default_chars[i]) { + if (!first_pass) + kfree (characters[i]); + characters[i] = default_chars[i]; + } + } + first_pass = 0; +} + +#ifdef CONFIG_PROC_FS + +// speakup /proc interface code + +/* +Notes: +currently, user may store an unlimited character definition + +Usage: +cat /proc/speakup/version + +cat /proc/speakup/characters > foo +less /proc/speakup/characters +vi /proc/speakup/characters + +cat foo > /proc/speakup/characters +cat > /proc/speakup/characters +echo 39 apostrophe > /proc/speakup/characters +echo 87 w > /proc/speakup/characters +echo 119 w > /proc/speakup/characters +echo defaults > /proc/speakup/characters +echo reset > /proc/speakup/characters +*/ + +// the /proc/speakup directory inodes +// static struct proc_dir_entry *proc_speakup_device; +// synth-specific directory created in synth driver file + +// this is the handler for /proc/speakup/version +static int speakup_version_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = sprintf (page, "%s\n", SPEAKUP_VERSION); + *start = 0; + *eof = 1; + return len; +} + +// this is the read handler for /proc/speakup/characters +static int speakup_characters_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int i; + int len = 0; + off_t begin = 0; + + for (i = 0; i < 256; ++i) { + if (characters[i]) + len += + sprintf (page + len, "%d\t%s\n", i, characters[i]); + else + len += sprintf (page + len, "%d\tNULL\n", i); + if (len + begin > off + count) + break; + if (len + begin < off) { + begin += len; + len = 0; + } + } + if (i >= 256) + *eof = 1; + if (off >= len + begin) + return 0; + *start = page + (off - begin); + return ((count < begin + len - off) ? count : begin + len - off); +} + +static volatile int chars_timer_active; // indicates when a timer is set +static DECLARE_WAIT_QUEUE_HEAD (chars_sleeping_list); +static struct timer_list chars_timer; + +static inline void chars_stop_timer (void) +{ + if (chars_timer_active) + del_timer (&chars_timer); +} + +static int strings, rejects, updates; + +static void show_char_results (unsigned long data) +{ + int len; + char buf[80]; + + chars_stop_timer (); + // tell what happened + len = sprintf (buf, " updated %d of %d character descriptions", + updates, strings); + if (rejects) + sprintf (buf + len, " with %d reject%s\n", + rejects, rejects > 1 ? "s" : ""); + else + sprintf (buf + len, "\n"); + printk (buf); + chars_timer_active = 0; +} + +/* this is the write handler for /proc/speakup/silent */ +static int speakup_silent_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned int currcons = fg_console; + char ch = 0; + if (count < 0 || count > 2) + goto msg_out; + if (count) + get_user (ch, buffer); + if (!count || ch == '\n') + ch = '0'; + switch (ch) { + case '0' : + if (spk_killed) + speakup_kill(currcons); + goto out; + case '1' : + if (!spk_killed) + speakup_kill(currcons); + goto out; + case '2' : + if (spk_killed) + spk_shut_up &= ~0x40; + goto out; + case '3' : + if (!spk_killed) + spk_shut_up |= 0x40; + goto out; + } + +msg_out: + printk (KERN_ALERT "setting silent: value not in range (0,3)\n"); + +out: + return count; +} + +// this is the write handler for /proc/speakup/characters +static int speakup_characters_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + static const int max_description_len = 72; + static int cnt, num, state; + static char desc[max_description_len + 1]; + static unsigned long jiff_last; + int i; + char ch, *s1, *s2; + + // reset certain vars if enough time has elapsed since last called + if (jiffies - jiff_last > HZ/10) { + state = strings = rejects = updates = 0; + } + jiff_last = jiffies; + // walk through the buffer + for (i = 0; i < count; ++i) { + get_user (ch, buffer + i); + switch (state) { + case 0: // initial state, only happens once per "write" + // if input matches "defaults" or "reset" reset_default_chars() and return + if ((ch == '\n' && count == 1) || strchr ("dDrR", ch)) { + reset_default_chars (); + printk (KERN_ALERT + "character descriptions reset to defaults\n"); + return count; + } + ++state; + // intentionally fall through to next state + case 1: // check for comment and skip whitespace + if (ch == '#') { // comment + num = -1; // don't count as rejected + state = 6; // ignore remainder of line + break; // and don't process + } + if (ch == ' ' || ch == '\t') // skip whitespace + break; + if (!isdigit (ch)) { + state = 6; + break; + } + num = ch - '0'; // convert first digit from ASCII + ++state; // now expecting only digits or whitespace + break; + case 2: // building number + if (isdigit (ch)) { + num *= 10; + num += ch - '0'; // convert from ASCII + break; + } + if (ch != ' ' && ch != '\t') { // not whitespace + state = 6; + break; + } + // pointing to 1st whitespace past digits -- number is complete + if (num < 0 || num > 255) { // not in range + state = 6; + break; + } + if (num >= 27 && num <= 31) { // no descriptions for these + num = -1; // don't count as rejected + state = 6; // but don't process either + break; + } + ++state; // now looking for 1st char of description + break; + case 3: /* skipping whitespace prior to description */ + if (ch == ' ' || ch == '\t') // skip whitespace + break; + if (ch == '\n') { // reached EOL + state = 6; + break; + } + cnt = 0; // starting new description + desc[cnt++] = ch; + ++state; // now looking for EOL + break; + case 4: // looking for newline + if (ch != '\n') { // not yet + // add char to description + desc[cnt++] = ch; + if (cnt < max_description_len) + break; // building description + // maximum description length reached, truncate remainder + state = 5; + } + // prepare to work on next string + state = state == 5 ? state : 1; + // description string is complete + desc[cnt] = '\0'; // NULL terminate + // if new description matches old, we don't need to update + s1 = desc; // point to new description + s2 = characters[num]; // point to old/current + while (*s1 == *s2) { + if (!*s1) // reached end of strings + break; + ++s1; + ++s2; + } + if (*s1 == *s2) { // strings match + ++strings; + break; + } + // handle new description + // is this description the default or has it already been modified? + if (characters[num] == default_chars[num]) // original + characters[num] = + (char *) kmalloc (sizeof (char) * + (strlen (desc) + 1), + GFP_KERNEL); + else // already redefined/allocated + krealloc (characters[num], strlen (desc) + 1); + if (!characters[num]) { // allocation failed + characters[num] = default_chars[num]; // reset to default + return -ENOMEM; + } + // got mem, copy the string + strcpy (characters[num], desc); + ++updates; + ++strings; + break; + case 5: // truncating oversized description + if (ch == '\n') + state = 1; // ready to start anew + // all other chars go to the bit bucket + break; + case 6: // skipping all chars while looking for newline + // we only get here if the data is invalid + if (ch == '\n') { + state = 1; + // -1 indicates chars with no description (ASCII 27-31) + if (num != -1) + ++rejects; + ++strings; + } + break; + } // end switch + } // finished processing entire buffer + + chars_stop_timer (); + init_timer (&chars_timer); + chars_timer.function = show_char_results; + init_waitqueue_head (&chars_sleeping_list); + + chars_timer.expires = jiffies + HZ/20; + if (!chars_timer.list.prev) + add_timer (&chars_timer); + chars_timer_active++; + return count; +} + +static int human_readable (char *s, struct spk_variable *var, char *buf) +{ + char *fmt = var->build; // point to start of it's format + int len = 0; + char *end = s + strlen (s) - 1; // point to end of string holding value + char *end_fmt = fmt + strlen (fmt) - 1; // point to end of it's format + + while (*fmt != '_' && *s == *fmt) { + ++s; + ++fmt; + } + // s now points to beginning of unformatted value, find the end + while (*end_fmt != '_' && *end == *end_fmt) { + --end; + --end_fmt; + } + // end now points to last char of unformatted value + // store value converting to human readable if necessary + for (; s <= end; ++s) { + if (*s < 32) { // don't print these directly + // convert to hex, 0x00 - 0xff + *(buf + len++) = '\\'; + *(buf + len++) = 'x'; + if (*s > 15) + *(buf + len++) = '1'; + else + *(buf + len++) = '0'; + if ((*s % 16) < 10) + *(buf + len++) = (*s % 16) + '0'; + else + *(buf + len++) = (*s % 16) + 'a' - 10; + } else + *(buf + len++) = *s; + if (*s == '\\') + *(buf + len++) = *s; // double up on escape char + } + // append a newline + *(buf + len++) = '\n'; + return len; +} + +static int find_config_var (const char *name, char ***value, + struct spk_variable **var, long **cfg_map) +{ + int i; + + if (synth != NULL) + for (i = 0; synth->vars[i].id != NULL; i++) { + if (strcmp (synth->vars[i].id, name) == 0) { + *value = &(synth->config[i]); + *var = &(synth->vars[i]); + *cfg_map = &(synth->config_map); + return i; + } + } + + for (i = 0; spk_vars[i].id != NULL; i++) { + if (strcmp (spk_vars[i].id, name) == 0) { + *value = &(spk_cfg[i]); + *var = &(spk_vars[i]); + *cfg_map = &spk_cfg_map; + return i; + } + } + + return -1; +} + +// this is the read handler for /proc/speakup/settings +int speakup_settings_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct proc_dir_entry *ent = data; + char **value; + struct spk_variable *var; + long *cfg_map; + int index = find_config_var (ent->name, &value, &var, &cfg_map); + + *start = 0; + *eof = 1; + + if (index == -1) + return sprintf (page, "%s slipped through the cracks!\n", + ent->name); + + return human_readable (*value, var, page); +} + +char *xlate (char *s) +{ + char *p = s, c; + size_t len = strlen (s); + int num, num_len; + + while ((p = strchr (p, '\\'))) { + num_len = 1; + switch (*(p + 1)) { + case '\\': + break; + case 'r': + *p = '\r'; + break; + case 'n': + *p = '\n'; + break; + case 't': + *p = '\t'; + break; + case 'v': + *p = '\v'; + break; + case 'a': + *p = '\a'; + break; +#ifdef fix_octal + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + if (sscanf (p + 1, "%3o%n", &num, &num_len)) + *p = (char) num; + break; +#endif + case 'x': + c = *(p + 2); + if (isdigit (c)) + num = c - '0'; + else if (isxdigit (c)) + num = tolower (c) - 'a' + 10; + else + break; + num *= 0x10; + c = *(p + 3); + if (isdigit (c)) + num += c - '0'; + else if (isxdigit (c)) + num += tolower (c) - 'a' + 10; + else + break; + num_len = 3; + *p = (char) num; + break; + default: + *p = *(p + 1); + } + num = p - s + num_len; + ++p; + memmove (p, p + num_len, len - num); + } + return s; +} + +#define NOT_IN_RANGE -1 +#define NOT_ONE_OF -2 +#define STRING_TOO_LONG -3 +#define RESET_DEFAULT -4 + +// this is the write handler for /proc/speakup/settings +static int speakup_settings_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct proc_dir_entry *ent = data; + int ret = NOT_IN_RANGE, i, limit, val = 0; + long *cfg_map; + char *p = NULL, *parm, *formatted, *src, *dest, **value; + struct spk_variable *sv; + int index = find_config_var (ent->name, &value, &sv, &cfg_map); + int currcons = 0; + + if (count < 0 || count > 1024) + return -EINVAL; + if (!(parm = (char *) __get_free_page (GFP_KERNEL))) + return -ENOMEM; + if (copy_from_user (parm, buffer, count)) { + ret = -EFAULT; + goto out; + } + // NULL terminate + if (*(parm + count - 1) == '\n') + *(parm + count - 1) = '\0'; + else + *(parm + count) = '\0'; + xlate (parm); + formatted = parm + strlen (parm) + 1; + if (index == -1) { + printk (KERN_ALERT "%s slipped through the cracks!\n", + ent->name); + ret = count; + goto out; + } + // wildcard + if (!sv->flags && *sv->valid == '*') { + // arbitrary 33 char limit + if (strlen (parm) > PUNC_CHARS_SIZE) { + ret = STRING_TOO_LONG; + goto msg_out; + } + // all is well + } else if (*parm && (sv->flags & USE_RANGE)) { + // check range + if (sv->flags & NUMERIC) { + int neg = 0; + // atoi on user provided value + p = parm; + if (*p == '-') { + ++neg; + ++p; + } + for (val = 0; *p; ++p) { + if (!isdigit (*p)) + goto msg_out; + val *= 10; + val += *p - '0'; + } + if (neg) { + val = -val; + neg = 0; + } + // atoi on lower limit of range + p = sv->valid; + if (*p == '-') { + ++neg; + ++p; + } + for (limit = 0; *p && *p != ','; ++p) { + // valid range? + if (!isdigit (*p)) + goto msg_out; + limit *= 10; + limit += *p - '0'; + } + if (neg) { + limit = -limit; + neg = 0; + } + if (val < limit) + goto msg_out; + // should be pointing to the comma in range + if (*p == ',') + ++p; + else + goto msg_out; + // atoi on upper limit of range + /* if bell_pos, this value is video_num_columns */ + dest = p; + if (*p == '-') { + ++neg; + ++p; + } + for (limit = 0; *p; ++p) { + // valid range? + if (!isdigit (*p)) + goto msg_out; + limit *= 10; + limit += *p - '0'; + } + if (neg) + limit = -limit; + if (index == BELL_POS) { + limit = video_num_columns; + sprintf (dest, "%-d", limit); + } + if (val > limit) + goto msg_out; + // numeric val is in range + } else { + // range of chars + p = sv->valid; + // parm should be exactly 1 char + if (*(parm + 1)) { + ret = NOT_ONE_OF; + goto msg_out; + } + *parm = tolower (*parm); + // expecting a comma here and char in range + if (*(p + 1) != ',' || *parm < *p || *parm > *(p + 2)) { + ret = NOT_ONE_OF; + goto msg_out; + } + } + } else if (*parm && (sv->flags & MULTI_SET)) { + // each char must be one of valid + if (strlen (parm) > PUNC_CHARS_SIZE) { + ret = STRING_TOO_LONG; + goto msg_out; + } + for (p = parm; *p; ++p) + if (!strchr (sv->valid, *p)) { + ret = NOT_ONE_OF; + goto msg_out; + } + } else if (*parm) { + // find_is_one_of + p = sv->valid; + // parm should be exactly 1 char + if (*(parm + 1)) { + ret = NOT_ONE_OF; + goto msg_out; + } + *parm = tolower (*parm); + for (; *p; ++p) + if (*parm == *p) + break; + if (!*p) { + // no match found + ret = NOT_ONE_OF; + goto msg_out; + } + } + // in range or doesn't matter + if (sv->flags & (HARD_DIRECT | SOFT_DIRECT) || !sv->flags) { + // replace string provided by user with formated string + if (*parm) { + // copy the format string up to the underscore + src = sv->build; + dest = formatted; + while (*src && *src != '_') + *dest++ = *src++; + // append parm + p = parm; + while (*p) + *dest++ = *p++; + // skip over the underscore + if (*src == '_') + ++src; + // append remainder of format + while (*src) + *dest++ = *src++; + // null terminate + *dest = '\0'; + } + } + // reset to default? + if (!*parm) { + // copy the format string up to the underscore + src = sv->build; + dest = formatted; + while (*src && *src != '_') + *dest++ = *src++; + // append default parameter + p = sv->param; + while (*p) + *dest++ = *p++; + // skip over the underscore + if (*src == '_') + ++src; + // append remainder of format + while (*src) + *dest++ = *src++; + // null terminate + *dest = '\0'; + ret = RESET_DEFAULT; + } + // store formatted value + if (*cfg_map & (0x01 << index)) + krealloc (*value, strlen (formatted) + 1); + else { + *cfg_map |= (0x01 << index); + *value = kmalloc (strlen (formatted) + 1, GFP_KERNEL); + } + strcpy (*value, formatted); + if (sv->flags & HARD_DIRECT) { + synth_write (formatted, strlen (formatted)); + synth_write ("\n", 1); + } + + /* set bell position */ + if (index == BELL_POS) + bell_pos = val; + + /* bleep settings need to be replicated through every console */ + if ((index == LINE_WRAP_BLEEP) || (index == ATTRIBUTE_BLEEP)) + for (i = 0; speakup_console[i] != NULL; ++i) { + if (index == LINE_WRAP_BLEEP) { + if (*parm == '1' || !*parm) + speakup_console[i]->sound |= + LineWrapBleep; + else + speakup_console[i]->sound &= + LineWrapMask; + } else { + // ATTRIBUTE_BLEEP + if (*parm == '1' || !*parm) + speakup_console[i]->sound |= + AttributeChangeBleep; + else + speakup_console[i]->sound &= + AttributeChangeMask; + } + } + if (ret == RESET_DEFAULT) + printk (KERN_ALERT "%s reset to default value\n", sv->id); + ret = count; + goto out; + +msg_out: + switch (ret) { + case NOT_IN_RANGE: + p = "value not in range"; + ret = count; + break; + case NOT_ONE_OF: + p = "value not one of"; + ret = count; + break; + case STRING_TOO_LONG: + p = "string longer than 33 chars"; + ret = count; + break; + } + printk (KERN_ALERT "setting %s (%s): %s (%s)\n", ent->name, parm, p, + sv->valid); + + out: + free_page ((unsigned long) parm); + return ret; +} + +// this is the read handler for /proc/speakup/synth +static int speakup_synth_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = sprintf (page, "%s\n", synth_name); + *start = 0; + *eof = 1; + return len; +} + +// this is the write handler for /proc/speakup/synth +static int speakup_synth_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int ret = count, i = 0; + char new_synth_name[10]; + struct spk_synth *new_synth = NULL; + + if (count < 1 || count > 9) + return -EINVAL; + if (copy_from_user (new_synth_name, buffer, count)) + return -EFAULT; + // NULL terminate + if (new_synth_name[count - 1] == '\n') + new_synth_name[count - 1] = '\0'; + else + new_synth_name[count] = '\0'; + strlwr (new_synth_name); + if (!strcmp (new_synth_name, synth->name)) { + printk (KERN_WARNING "already in use\n"); + return ret; + } + + for (i = 0; !new_synth && synths[i]; ++i) { + if (!strcmp (synths[i]->name, new_synth_name)) + new_synth = synths[i]; + } + + if (!new_synth && strcmp (new_synth_name, "none")) { + printk (KERN_WARNING + "there is no synth named \"%s\" built into this kernel\n", + new_synth_name); + return ret; + } + + /* At this point, we know that new_synth_name is valid, built into the + kernel, and not already in use. + Next, do the magic to select it as the new active synth */ + + // still working here. announce attempt and leave + printk (KERN_ALERT "attempt to change synth to %s\n", new_synth_name); + return ret; +} + +// called by proc_root_init() to initialize the /proc/speakup subtree +void __init proc_speakup_init (void) +{ + int i; + char path[40]; + mode_t mode; + struct proc_dir_entry *ent; +#define PROC_SPK_DIR "speakup" + + ent = create_proc_entry (PROC_SPK_DIR, S_IFDIR, 0); + if (!ent) { + printk (KERN_ALERT "Unable to create /proc/speakup entry.\n"); + return; + } + + ent = create_proc_entry (PROC_SPK_DIR "/version", S_IFREG | S_IRUGO, 0); + ent->read_proc = speakup_version_read_proc; + + ent = create_proc_entry (PROC_SPK_DIR "/silent", S_IFREG | S_IWUGO, 0); + ent->write_proc = speakup_silent_write_proc; + + ent = + create_proc_entry (PROC_SPK_DIR "/characters", + S_IFREG | S_IRUGO | S_IWUGO, 0); + ent->read_proc = speakup_characters_read_proc; + ent->write_proc = speakup_characters_write_proc; + + ent = + create_proc_entry (PROC_SPK_DIR "/synth", + S_IFREG | S_IRUGO | S_IWUGO, 0); + ent->read_proc = speakup_synth_read_proc; + ent->write_proc = speakup_synth_write_proc; + + if (synth != NULL) { + for (i = 0; synth->vars[i].id != NULL; i++) { + mode = S_IFREG | S_IRUGO; + if (~(synth->vars[i].flags) & NO_USER) + mode |= S_IWUGO; + sprintf (path, PROC_SPK_DIR "/%s", synth->vars[i].id); + ent = create_proc_entry (path, mode, 0); + ent->read_proc = speakup_settings_read_proc; + if (mode & S_IWUGO) + ent->write_proc = speakup_settings_write_proc; + ent->data = (void *) ent; + } + } + + for (i = 0; spk_vars[i].id != '\0'; ++i) { + if (!strcmp (spk_vars[i].id, "punc_none")) + continue; // no /proc file for this one -- it's empty + mode = S_IFREG | S_IRUGO; + if (~(spk_vars[i].flags) & NO_USER) + mode |= S_IWUGO; + sprintf (path, PROC_SPK_DIR "/%s", spk_vars[i].id); + ent = create_proc_entry (path, mode, 0); + ent->read_proc = speakup_settings_read_proc; + if (mode & S_IWUGO) + ent->write_proc = speakup_settings_write_proc; + ent->data = (void *) ent; + } + + // initialize the synth-specific subtree + if (synth != NULL) + proc_speakup_synth_init (); +} + +#endif // CONFIG_PROC_FS + +/* version 2.3.x */ +void __init +speakup_init (int currcons) +{ + unsigned char i; + + reset_default_chars (); + + speakup_console[currcons] = + (struct spk_t *) alloc_bootmem (sizeof (struct spk_t) + 1); + + for (i = 0; i < MIN_NR_CONSOLES; i++) { + spk_shut_up = 0; + spk_x = x; + spk_y = y; + spk_attr = spk_old_attr = attr; + spk_pos = pos; + spk_sound = 3; + spk_parked = 0; + spk_o_cp = spk_o_cy = spk_o_cx = 0; + } + for (; i < MAX_NR_CONSOLES; i++) + speakup_console[i] = NULL; + speakup_open (currcons); /* we'll try it here. */ + printk ("%s: initialized\n", SPEAKUP_VERSION); +} + +void speakup_allocate (int currcons) +{ + + speakup_console[currcons] = (struct spk_t *) kmalloc (sizeof (struct spk_t) + 1, GFP_KERNEL); + + spk_shut_up = 0; + spk_x = x; + spk_y = -1; + spk_old_attr = spk_attr = attr; + spk_pos = pos; + spk_sound = 3; + spk_parked = 0; + spk_o_cp = spk_o_cy = spk_o_cx = 0; +} + +void speakup_date (unsigned int currcons) +{ + spk_x = spk_cx = x; + spk_y = spk_cy = y; + spk_pos = spk_cp = pos; + spk_old_attr = spk_attr; + spk_attr = ((scr_readw ((unsigned short *) spk_pos) & 0xff00) >> 8); +} + +void speakup_check (unsigned int currcons) +{ + if (!spk_keydown) + return; + + if ((x == spk_o_cx + 1 || x == spk_o_cx - 1) && y == spk_o_cy) { + if (spk_keydown > 1 && x > spk_o_cx) + say_prev_char (currcons); + else + say_curr_char (currcons); + } else + if ((x == 0 && spk_o_cx == video_num_columns - 1 + && y == spk_o_cy + 1) + || (x == video_num_columns - 1 && spk_o_cx == 0 + && y == spk_o_cy - 1)) { + say_curr_char (currcons); + } else if (y == spk_o_cy && (y == bottom || y == top)) { + say_curr_line (currcons); + } else if ((y > spk_o_cy || y < spk_o_cy)) { + say_curr_line (currcons); + } else if (pos == spk_o_cp) { + say_curr_char (currcons); + } else + say_curr_word (currcons); + + spk_o_cp = pos; + spk_o_cx = x; + spk_o_cy = y; + spk_keydown = 0; + spk_parked &= 0xfe; + speakup_date (currcons); +} + +/* These functions are the interface to speakup from the actual kernel code. */ + +void speakup_bs (int currcons) +{ + if (!spk_parked) + speakup_date (currcons); + if ((!spk_shut_up || spk_shut_up & 0x02) && (currcons == fg_console) + && spk_keydown) { + spk_keydown = 0; + say_curr_char (currcons); + } +} + +void speakup_con_write (int currcons, const char *str, int len) +{ + if (!spk_shut_up && (currcons == fg_console)) { + if (bell_pos && spk_keydown && (x == bell_pos - 1)) + bleep(38); + spkup_write (str, len); + } +} + +void speakup_con_update (int currcons) +{ + if (speakup_console[currcons] == NULL) + return; + if (!spk_parked) + speakup_date (currcons); + if ((currcons == fg_console) && !spk_parked && spk_shut_up & 0x02) + speakup_check (currcons); +} + +void speakup_control(int currcons, struct kbd_struct * kbd, int value) +{ + /* let there be speech! */ + switch (value) { + case KVAL(K_CAPS): + if (vc_kbd_led(kbd , VC_CAPSLOCK)) + spk_control(fg_console, 10); + else + spk_control(fg_console, 11); + break; + case KVAL(K_NUM): + if (vc_kbd_led(kbd , VC_NUMLOCK)) + spk_control(fg_console, 12); + else + spk_control(fg_console, 13); + break; + case KVAL(K_HOLD): + if (vc_kbd_led(kbd , VC_SCROLLOCK)) + spk_control(fg_console, 14); + else + spk_control(fg_console, 15); + break; + default: + spk_control(currcons, value); + } +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_decext.c linux.20pre2-ac1/drivers/char/speakup/speakup_decext.c --- linux.20pre2/drivers/char/speakup/speakup_decext.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_decext.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,307 @@ +/* + * speakup_dectlk.c - Dectalk External driver for Linux kernel 2.3.x and speakup + * + * author: Kirk Reiser + + Copyright (C) 2000 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + + +/* These routines are written to control the Dectalk External speech + synthesizer by Digital Equipment Corp. They are not ment to be + thought of as a device driver in that they do not register + themselves as a chr device and there is no file_operations + structure. They are strictly to provide an interface to the + Dectalk External from the speakup screen review package. */ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants & + serial_uart_config */ +#include /* for more serial constants */ +#if (LINUX_VERSION_CODE >= 0x20300) /* v 2.3.x */ +#include /* for struct serial_state */ +#endif +#include +#include + +#define SYNTH_CLEAR 0x03 /* synth flush char */ +#define PROCSPEECH 0x0b /* start synth processing char */ +static int full_status = 0; +#define synth_full() (full_status = (inb_p(synth_port_tts) == 0x13)) +#define SPK_SERIAL_TIMEOUT 1000000 /* countdown values for serial timeouts */ +#define SPK_XMITR_TIMEOUT 1000000 /* countdown values transmitter/dsr timeouts */ +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 +#define NUM_DISABLE_TIMEOUTS 3 /* # of timeouts permitted before disable */ + +static int dectlk_alive = 0; + /* 160 ms delay and ctrl-x as flush */ + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] __initdata = { + SERIAL_PORT_DFNS +}; + +static int timeouts = 0; /* sequential number of timeouts */ + +static int wait_for_xmitr(void) +{ +int check, tmout = SPK_XMITR_TIMEOUT; + + if ((dectlk_alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { + dectlk_alive = 0; + timeouts = 0; + return 0; + } + + /* holding register empty? */ + do { + check = inb_p(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk("Dectalk External: timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + + tmout = SPK_XMITR_TIMEOUT; + /* CTS */ + do { + check = inb_p(synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int spk_serial_out(const char ch) +{ + if (dectlk_alive && synth_port_tts) { + if (wait_for_xmitr()) { + outb_p(ch, synth_port_tts); + return 1; + } + } + return 0; +} + +static unsigned char __init spk_serial_in(void) +{ +int lsr, tmout = SPK_SERIAL_TIMEOUT; +int c; + + do { + lsr = inb_p(synth_port_tts + UART_LSR); + if (--tmout == 0) return 0xff; + } while (!(lsr & UART_LSR_DR)); + c = inb_p(synth_port_tts + UART_RX); + return (unsigned char) c; +} + +static void do_catch_up(unsigned long data) +{ +unsigned long jiff_in = jiffies; + +synth_stop_timer(); +while ((synth_sent_bytes < synth_queued_bytes) && !synth_full()) + { + if (!spk_serial_out(*(synth_buffer+synth_sent_bytes))) { + synth_delay(synth_full_time); + return; + } + synth_sent_bytes++; + if (jiffies >= jiff_in+synth_jiffy_delta && *(synth_buffer+synth_sent_bytes-1) == ' ') { + spk_serial_out(PROCSPEECH); + synth_delay(synth_delay_time); + return; + } + } + + if (full_status) { + synth_delay(synth_full_time); + return; + } +synth_sent_bytes = synth_queued_bytes = 0; +spk_serial_out(PROCSPEECH); +synth_timer_active = 0; +if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static inline void synth_immediate_tts(const char *buf, size_t count) +{ + while (count--) spk_serial_out(*buf++); +return; +} + +static void synth_write_tts(char ch) +{ +static char last='['; + + if (!dectlk_alive) return; + if (ch < 0x00) return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = 0x0D; + if (ch == SYNTH_CLEAR) { /* clear all and wake sleeping */ + synth_immediate_tts("\x1bP;10z\x1b\\", 8); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +#if (LINUX_VERSION_CODE >= 0x20300) /* is it a 2.3.x kernel? */ + if (synth_timer.list.prev) synth_stop_timer(); +#else + if (synth_timer.prev) synth_stop_timer(); +#endif + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + +synth_buffer_add(ch); +if ((last != '[') && strchr(",.@!?/-:", ch)) synth_buffer_add(PROCSPEECH); +last = ch; +if (synth_buffering) return; +if (synth_timer_active == 0) synth_delay( synth_trigger_time ); +} + +static int __init serprobe(int index) +{ + struct serial_state *ser = NULL; + unsigned char test=0; + + if (synth_port_tts) { + for (test=0; test <= SPK_HI_TTY; test++) + if ( (rs_table+test)->port == synth_port_tts) { + ser = rs_table+test; + break; + } + } else ser = rs_table + index; + + if (synth_request_region(ser->port,8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb (ser->port + UART_LSR) == 0xff) { + synth_release_region(ser->port,8); + return -1; + } + mdelay(1); + + dectlk_alive = 1; + /* ignore any error results, if port was forced */ + if (synth_port_tts) + return 0; + + synth_port_tts = ser->port; + /* check for dectalk external now... */ + spk_serial_out(0x1b); + spk_serial_out('['); + spk_serial_out(';'); + spk_serial_out('5'); + spk_serial_out('n'); + spk_serial_out(0x1b); + spk_serial_out('\\'); + if ((test = spk_serial_in()) == 0x1b) + return 0; + /*printk("test = %x\n", test);*/ + + synth_release_region(ser->port,8); + timeouts = dectlk_alive = synth_port_tts = 0; /* not ignoring */ + return -1; +} + +static int __init synth_dev_probe(void) +{ +int i=0; + + printk("Probing for Dectalk External.\n"); + if (synth_port_tts) + printk("probe forced to 0x%x by kernel command line\n", synth_port_tts); + + /* check ttyS0-ttyS3 */ + for (i=SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe(i) == 0) break; /* found it */ + } + + if (dectlk_alive) { + /* found 'em */ + printk("Dectalk External: %03x-%03x, Driver Version %s,\n", + synth_port_tts, synth_port_tts+7, synth->version); + synth_immediate_tts(synth->init, strlen(synth->init)); + return 0; + } + + printk("Dectalk External: not found\n"); + return -ENODEV; +} + +static int synth_alive(void) +{ + if (dectlk_alive) + return 1; /* already on */ + else if ((!dectlk_alive) && (synth_port_tts)) { + if (wait_for_xmitr() > 0) { /* restart */ + dectlk_alive = 1; + synth_write(synth->reinit, strlen(synth->reinit)); + return 2; /* reenabled */ + } else printk("Dectalk External: can't restart synth\n"); + } + return 0; +} + +static const char init_string[] = "[:ra 300][:dv ap 100][:punc n][:pe -380]Dectalk External found\n"; +static const char reinit_string[] = "[:ra 300][:dv ap 100][:punc n][:pe -380]Dectalk restarted\n"; + +static struct spk_variable vars[] = +{{"flush", "\x03", "_", (BUILDER|HARD_DIRECT|USE_RANGE|NO_USER), "*"}, + {"pitch", "100", "[:dv ap _]", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,99"}, + {"caps_start", "[:dv ap 222]", "_", 0, "*"}, + {"caps_stop", "[:dv ap 100]", "_", 0, "*"}, + {"rate", "300", "[:ra _]", (NUMERIC|HARD_DIRECT|USE_RANGE), "75,650"}, + {"volume", "65", "[:dv gv _]", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,80"}, + {"voice", "p", "[:n_]", HARD_DIRECT, "phfdburwkv"}, + {"punct", "n", "[:pu _]", HARD_DIRECT, "nsa"}, + END_VARS}; + +static char *config[] = +{"\x03", "[:dv ap 100]", "[:dv ap 222]", "[:dv ap 100]", "[:ra 300]", "", + "[:np]", "[:pu n]"}; + +struct spk_synth synth_decext = {"decext", "Version-0.10", "dec_external", + init_string, reinit_string, 500, 50, 5, 1000, + vars, config, 0, synth_dev_probe, do_catch_up, + synth_write_tts, synth_alive}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_dectlk.c linux.20pre2-ac1/drivers/char/speakup/speakup_dectlk.c --- linux.20pre2/drivers/char/speakup/speakup_dectlk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_dectlk.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,337 @@ +/* + * speakup_dectlk.c - Dectalk Express driver for Linux kernel 2.3.x and speakup + * + * author: Kirk Reiser + + Copyright (C) 1998-99 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + +/* These routines are written to control the Dectalk Express speech + synthesizer by Digital Equipment Corp. They are not ment to be + thought of as a device driver in that they do not register + themselves as a chr device and there is no file_operations + structure. They are strictly to provide an interface to the + Dectalk Express from the speakup screen review package. */ + +#define KERNEL +#include +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include /* for rs_table, serial constants & + serial_uart_config */ +#include /* for more serial constants */ +#if LINUX_VERSION_CODE >= 0x020200 +#include /* for struct serial_state */ +#endif +#include +#include + +#define SYNTH_CLEAR 0x03 /* synth flush char */ +#define PROCSPEECH 0x0b /* start synth processing char */ +static int full_status = 0; +#define synth_full() (full_status = (inb_p(synth_port_tts) == 0x13)) +#define SPK_SERIAL_TIMEOUT 1000000 /* countdown values for serial timeouts */ +#define SPK_XMITR_TIMEOUT 1000000 /* countdown values transmitter/dsr timeouts */ +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 +#define NUM_DISABLE_TIMEOUTS 3 /* # of timeouts permitted before disable */ + +static int dectlk_alive = 0; + /* 160 ms delay and ctrl-x as flush */ +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] __initdata = { + SERIAL_PORT_DFNS +}; + +static int timeouts = 0; /* sequential number of timeouts */ + +static int +wait_for_xmitr (void) +{ + int check; + unsigned int tmout = SPK_XMITR_TIMEOUT; + + if ((dectlk_alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { + dectlk_alive = 0; + timeouts = 0; + return 0; + } + + /* holding register empty? */ + do { + check = inb_p(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk ("Dectalk Express: timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + + tmout = SPK_XMITR_TIMEOUT; + /* CTS */ + do { + check = inb_p (synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int +spk_serial_out (const char ch) +{ + if (dectlk_alive && synth_port_tts) { + if (wait_for_xmitr ()) { + outb_p (ch, synth_port_tts); + return 1; + } + } + return 0; +} + +static unsigned char __init +spk_serial_in (void) +{ + int lsr, tmout = SPK_SERIAL_TIMEOUT; + int c; + + do { + lsr = inb_p (synth_port_tts + UART_LSR); + if (--tmout == 0) + return 0xff; + } while (!(lsr & UART_LSR_DR)); + c = inb_p (synth_port_tts + UART_RX); + return (unsigned char) c; +} + +static void +do_catch_up (unsigned long data) +{ + unsigned long jiff_in = jiffies; + + synth_stop_timer (); + while ((synth_sent_bytes < synth_queued_bytes) && !synth_full ()) { + if (!spk_serial_out (*(synth_buffer + synth_sent_bytes))) { + synth_delay (synth_full_time); + return; + } + synth_sent_bytes++; + if (jiffies >= jiff_in + synth_jiffy_delta + && *(synth_buffer + synth_sent_bytes - 1) == ' ') { + spk_serial_out (PROCSPEECH); + synth_delay (synth_delay_time); + return; + } + } + + if (full_status) { + synth_delay (synth_full_time); + return; + } + synth_sent_bytes = synth_queued_bytes = 0; + synth_trigger_time = 50; + spk_serial_out (PROCSPEECH); + synth_timer_active = 0; + if (waitqueue_active (&synth_sleeping_list)) + wake_up_interruptible (&synth_sleeping_list); +} + +static inline void +synth_immediate_tts (const char *buf, size_t count) +{ + while (count--) + spk_serial_out (*buf++); + return; +} + +static void +synth_write_tts (char ch) +{ +/* int i = SPK_SERIAL_TIMEOUT; */ + static char last = '['; + + if (!dectlk_alive) + return; + if (ch < 0x00) + return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = 0x0D; + if (strchr ("-'", ch)) + ch = ' '; + if (ch == SYNTH_CLEAR) { /* clear all and wake sleeping */ + spk_serial_out (ch); + /*while(spk_serial_in() != 0x01 && i-- > 0); */ + synth_trigger_time = 100; + if (waitqueue_active (&synth_sleeping_list)) + wake_up_interruptible (&synth_sleeping_list); +#if LINUX_VERSION_CODE >= 0x020300 + if (synth_timer.list.prev) + synth_stop_timer (); +#else + if (synth_timer.prev) + synth_stop_timer (); +#endif + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + + synth_buffer_add (ch); + if ((last != '[') && strchr (",_.@!?/-:", ch)) + synth_buffer_add (PROCSPEECH); + last = ch; + if (synth_buffering) + return; + if (synth_timer_active == 0) + synth_delay (synth_trigger_time); + return; +} + +static int __init +serprobe (int index) +{ + struct serial_state *ser = NULL; + unsigned char test = 0; + + if (synth_port_tts) { + for (test = 0; test <= SPK_HI_TTY; test++) + if ((rs_table + test)->port == synth_port_tts) { + ser = rs_table + test; + break; + } + } else + ser = rs_table + index; + + /* don't do output yet... */ + if (synth_request_region (ser->port, 8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb (ser->port + UART_LSR) == 0xff) { + synth_release_region (ser->port, 8); + return -1; + } + mdelay (1); + outb (0x0d, ser->port); + + dectlk_alive = 1; + /* ignore any error results, if port was forced */ + if (synth_port_tts) + return 0; + + synth_port_tts = ser->port; + /* check for dectalk express now... */ + if (spk_serial_out (0x03)) { + while (spk_serial_in () != 0x01) ; + return 0; + } + + synth_release_region (ser->port, 8); + timeouts = dectlk_alive = synth_port_tts = 0; /* not ignoring */ + return -1; +} + +static int __init +synth_dev_probe (void) +{ + int i = 0; + + printk ("Probing for Dectalk Express.\n"); + if (synth_port_tts) + printk ("probe forced to 0x%x by kernel command line\n", + synth_port_tts); + + /* check ttyS0-ttyS3 */ + for (i = SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe (i) == 0) + break; /* found it */ + } + + if (dectlk_alive) { + /* found 'em */ + printk ("Dectalk Express: %03x-%03x, Driver Version %s,\n", + synth_port_tts, synth_port_tts + 7, synth->version); + synth_immediate_tts (synth->init, strlen (synth->init)); + return 0; + } + + printk ("Dectalk Express: not found\n"); + return -ENODEV; +} + +static int +synth_alive (void) +{ + if (dectlk_alive) + return 1; /* already on */ + else if ((!dectlk_alive) && (synth_port_tts)) { + if (wait_for_xmitr () > 0) { /* restart */ + dectlk_alive = 1; + synth_write (synth->reinit, strlen (synth->reinit)); + return 2; /* reenabled */ + } else + printk ("Dectalk Express: can't restart synth\n"); + } + return 0; +} + +static const char init_string[] = + "[:ra 300][:dv ap 100][:punc n][:pe -380]Dectalk Express found\n"; +static const char reinit_string[] = + "[:ra 300][:dv ap 100][:punc n][:pe -380]Dectalk restarted\n"; + +static struct spk_variable vars[] = + { {"flush", "\x03", "_", (BUILDER | HARD_DIRECT | USE_RANGE | NO_USER), + "*"}, +{"pitch", "100", "[:dv ap _]", (NUMERIC | HARD_DIRECT | USE_RANGE), "50,350"}, +{"caps_start", "[:dv ap 222]", "_", 0, "*"}, +{"caps_stop", "[:dv ap 100]", "_", 0, "*"}, +{"rate", "300", "[:ra _]", (NUMERIC | HARD_DIRECT | USE_RANGE), "75,650"}, +{"volume", "65", "[:dv gv _]", (NUMERIC | HARD_DIRECT | USE_RANGE), "0,80"}, +{"voice", "p", "[:n_]", HARD_DIRECT, "phfdburwkv"}, +{"punct", "n", "[:pu _]", HARD_DIRECT, "nsa"}, +END_VARS +}; + +static char *config[] = + { "\x03", "[:dv ap 100]", "[:dv ap 222]", "[:dv ap 100]", "[:ra 300]", + "[:dv gv 65]", "[:np]", "[:pu n]" +}; + +struct spk_synth synth_dectlk = { "dectlk", "Version-0.12", "dec_express", + init_string, reinit_string, 500, 50, 5, 1000, + vars, config, 0, synth_dev_probe, do_catch_up, + synth_write_tts, synth_alive +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_drvcommon.c linux.20pre2-ac1/drivers/char/speakup/speakup_drvcommon.c --- linux.20pre2/drivers/char/speakup/speakup_drvcommon.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_drvcommon.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,399 @@ +#define KERNEL +#include +#include +#include /* for isdigit() and friends */ +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants & + serial_uart_config */ +#include /* for more serial constants */ +#include /* for struct serial_state */ +#include +#include + +#define synthBufferSize 8192 /* currently 8K bytes */ +struct spk_synth *synth = NULL; +unsigned char synth_jiffy_delta = HZ/20; +int synth_port_tts = 0; +volatile int synth_timer_active = 0; /* indicates when a timer is set */ +DECLARE_WAIT_QUEUE_HEAD (synth_sleeping_list); +struct timer_list synth_timer; +unsigned short synth_delay_time = 500; /* time to schedule handler */ +unsigned short synth_trigger_time = 50; +unsigned short synth_full_time = 1000; /* time before coming back when synth is full */ +char synth_buffering = 1; /* flag to indicate we're buffering */ +unsigned char synth_buffer[synthBufferSize]; /* guess what this is for! */ +unsigned short synth_end_of_buffer = synthBufferSize; +volatile unsigned short synth_queued_bytes = 0, synth_sent_bytes = 0; +/* synth_queued_bytes points to top of chars queued, + * synth_sent_bytes points at top of bytes sent by synth->catch_up() */ + +void +initialize_uart(struct serial_state *ser) +{ + int baud = 9600; + int quot = 0; + unsigned cval = 0; + int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8; + + /* + * Divisor, bytesize and parity + */ + quot = ser->baud_base / baud; + cval = cflag & (CSIZE | CSTOPB); +#if defined(__powerpc__) || defined(__alpha__) + cval >>= 8; +#else /* !__powerpc__ && !__alpha__ */ + cval >>= 4; +#endif /* !__powerpc__ && !__alpha__ */ + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + outb(cval | UART_LCR_DLAB, ser->port + UART_LCR); /* set DLAB */ + outb(quot & 0xff, ser->port + UART_DLL); /* LS of divisor */ + outb(quot >> 8, ser->port + UART_DLM); /* MS of divisor */ + outb(cval, ser->port + UART_LCR); /* reset DLAB */ + outb(0, ser->port + UART_IER); + outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR); +} + +/* sleep for ms milliseconds */ +void +synth_delay (int ms) +{ + synth_timer.expires = jiffies + (ms * HZ + 1000 - HZ) / 1000; +# if (LINUX_VERSION_CODE >= 0x20300) /* is it a 2.3.x kernel? */ + if (!synth_timer.list.prev) + add_timer (&synth_timer); +# else + if (!synth_timer.prev) + add_timer (&synth_timer); +# endif + synth_timer_active++; +} + +void +synth_stop_timer (void) +{ + if (synth_timer_active) + del_timer (&synth_timer); +} + +void +synth_buffer_add (char ch) +{ + /* someone needs to take a nap for a while. */ + if (synth_queued_bytes + 1 == synth_end_of_buffer - 100 + && (!waitqueue_active (&synth_sleeping_list))) { + interruptible_sleep_on (&synth_sleeping_list); + } + *(synth_buffer + synth_queued_bytes++) = ch; +} + +void +synth_write (const char *buf, size_t count) +{ + while (count--) + synth->write (*buf++); +} + +#if LINUX_VERSION_CODE >= 0x20300 +static struct resource synth_res; +#endif + +int __init +synth_request_region (unsigned long start, unsigned long n) +{ +#if (LINUX_VERSION_CODE >= 0x20300) /* is it a 2.3.x kernel? */ + struct resource *parent = &ioport_resource; + + memset (&synth_res, 0, sizeof (synth_res)); + synth_res.name = synth->name; + synth_res.start = start; + synth_res.end = start + n - 1; + synth_res.flags = IORESOURCE_BUSY; + + return request_resource (parent, &synth_res); +#else + if (check_region (start, n)) + return -EBUSY; + request_region (start, n, synth->name); + return 0; +#endif +} + +int __init +synth_release_region (unsigned long start, unsigned long n) +{ +#if (LINUX_VERSION_CODE >= 0x20300) + return release_resource (&synth_res); +#else + release_region (start, n); + return 0; +#endif +} + +#ifdef CONFIG_PROC_FS + +// /proc/synth-specific code + +#include +#include + +static struct proc_dir_entry *proc_speakup_synth; + +// this is the read handler for /proc/speakup/synth-specific vars +static int +speakup_vars_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct proc_dir_entry *ent = data; + + *start = 0; + *eof = 1; + + if (!strcmp (ent->name, "jiffy_delta")) + return sprintf (page, "%d\n", synth_jiffy_delta); + if (!strcmp (ent->name, "delay_time")) + return sprintf (page, "%d\n", synth_delay_time); + if (!strcmp (ent->name, "queued_bytes")) + return sprintf (page, "%d\n", synth_queued_bytes); + if (!strcmp (ent->name, "sent_bytes")) + return sprintf (page, "%d\n", synth_sent_bytes); + if (!strcmp (ent->name, "trigger_time")) + return sprintf (page, "%d\n", synth_trigger_time); + if (!strcmp (ent->name, "full_time")) + return sprintf (page, "%d\n", synth_full_time); + if (!strcmp (ent->name, "version")) + return sprintf (page, "%s\n", synth->version); + + return sprintf (page, "%s slipped through the cracks!\n", ent->name); +} + +#define RESET_DEFAULT -4 + +// this is the write handler for /proc/speakup/synth-specific vars +static int +speakup_vars_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct proc_dir_entry *ent = data; + int i, len = count, val = 0, ret = -ERANGE; + long min = 0, max = 0; + char *page; + + if (!(page = (char *) __get_free_page (GFP_KERNEL))) + return -ENOMEM; + if (copy_from_user (page, buffer, count)) { + ret = -EFAULT; + goto out; + } + // lose the newline + if (page[len - 1] == '\n') + --len; + + // trigger_time is an unsigned short 0 <= val <= 65535 + if (!strcmp (ent->name, "trigger_time")) { + if (!len) { + synth_trigger_time = synth->trigger_time; + ret = RESET_DEFAULT; + goto out; + } + max = 65535; + // 1 to 5 digits + if (len < 1 || len > 5) + goto out; + for (i = 0; i < len; ++i) { + if (!isdigit (page[i])) + goto out; + val *= 10; + val += page[i] - '0'; + } + if (val < min || val > max) + goto out; + synth_trigger_time = val; + ret = count; + } + // full_time is an unsigned short 0 <= val <= 65535 + else if (!strcmp (ent->name, "full_time")) { + if (!len) { + synth_full_time = synth->full_time; + ret = RESET_DEFAULT; + goto out; + } + max = 65535; + // 1 to 5 digits + if (len < 1 || len > 5) + goto out; + for (i = 0; i < len; ++i) { + if (!isdigit (page[i])) + goto out; + val *= 10; + val += page[i] - '0'; + } + if (val < min || val > max) + goto out; + synth_full_time = val; + ret = count; + } + // jiffy_delta is an unsigned char 0 <= val <= 255 + else if (!strcmp (ent->name, "jiffy_delta")) { + if (!len) { + synth_jiffy_delta = synth->jiffy_delta; + ret = RESET_DEFAULT; + goto out; + } + max = 255; + // 1 to 3 digits + if (len < 1 || len > 3) + goto out; + for (i = 0; i < len; ++i) { + if (!isdigit (page[i])) + goto out; + val *= 10; + val += page[i] - '0'; + } + if (val < min || val > max) + goto out; + synth_jiffy_delta = val; + ret = count; + } + // delay_time is an unsigned short 0 <= val <= 65535 + else if (!strcmp (ent->name, "delay_time")) { + if (!len) { + synth_delay_time = synth->delay_time; + ret = RESET_DEFAULT; + goto out; + } + max = 65535; + // 1 to 5 digits + if (len < 1 || len > 5) + goto out; + for (i = 0; i < len; ++i) { + if (!isdigit (page[i])) + goto out; + val *= 10; + val += page[i] - '0'; + } + if (val < min || val > max) + goto out; + synth_delay_time = val; + ret = count; + } + + out: + if (ret == -ERANGE) { + printk (KERN_ALERT + "setting %s (%.*s): value out of range (%ld-%ld)\n", + ent->name, len, page, min, max); + ret = count; + } else if (ret == RESET_DEFAULT) { + printk (KERN_ALERT "%s reset to default value\n", ent->name); + ret = count; + } + free_page ((unsigned long) page); + return ret; +} + +#define MIN(a,b) ( ((a) < (b))?(a):(b) ) + +// this is the write handler for /proc/speakup/synth-specific/direct +static int +speakup_direct_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + static const int max_buf_len = 100; + unsigned char buf[max_buf_len + 1]; + int ret = count; + extern char *xlate (char *); + + if (copy_from_user (buf, buffer, count = (MIN (count, max_buf_len)))) + return -EFAULT; + buf[count] = '\0'; + xlate (buf); + synth_write (buf, strlen (buf)); + return ret; +} + +char *read_only[] = { + "queued_bytes", "sent_bytes", "version", NULL +}; + +char *root_writable[] = { + "delay_time", "full_time", "jiffy_delta", "trigger_time", NULL +}; + +// called by proc_speakup_init() to initialize the /proc/speakup/synth-specific subtree +void +proc_speakup_synth_init (void) +{ + struct proc_dir_entry *ent; + char *dir = "speakup/"; + char path[80]; + int i; + + sprintf (path, "%s%s", dir, synth->proc_name); + proc_speakup_synth = create_proc_entry (path, S_IFDIR, 0); + if (!proc_speakup_synth) { + printk (KERN_WARNING "Unable to create /proc/%s entry.\n", + path); + return; + } + + for (i = 0; read_only[i]; ++i) { + sprintf (path, "%s%s/%s", dir, synth->proc_name, read_only[i]); + ent = create_proc_entry (path, S_IFREG | S_IRUGO, 0); + ent->read_proc = speakup_vars_read_proc; + ent->data = (void *) ent; + } + + for (i = 0; root_writable[i]; ++i) { + sprintf (path, "%s%s/%s", dir, synth->proc_name, root_writable[i]); + ent = create_proc_entry (path, S_IFREG | S_IRUGO | S_IWUSR, 0); + ent->read_proc = speakup_vars_read_proc; + ent->write_proc = speakup_vars_write_proc; + ent->data = (void *) ent; + } + + sprintf (path, "%s%s/direct", dir, synth->proc_name); + ent = create_proc_entry (path, S_IFREG | S_IWUGO, 0); + ent->write_proc = speakup_direct_write_proc; +} + +#endif + +int __init +synth_init (void) +{ + if (synth->probe () < 0) { + printk ("%s: device probe failed\n", synth->name); + return -ENODEV; + } + init_timer (&synth_timer); + synth_timer.function = synth->catch_up; +#if (LINUX_VERSION_CODE >= 0x20300) /* it's a 2.3.x kernel */ + init_waitqueue_head (&synth_sleeping_list); +#else /* it's a 2.2.x kernel */ + init_waitqueue (&synth_sleeping_list); +#endif + synth_delay_time = synth->delay_time; + synth_trigger_time = synth->trigger_time; + synth_jiffy_delta = synth->jiffy_delta; + synth_full_time = synth->full_time; + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_dtlk.c linux.20pre2-ac1/drivers/char/speakup/speakup_dtlk.c --- linux.20pre2/drivers/char/speakup/speakup_dtlk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_dtlk.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,259 @@ +/* + * speakup_dtlk.c - DoubleTalk PC driver for Linux kernel 2.3.x and speakup + * + * author: Kirk Reiser + + Copyright (C) 1998-99 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + + +/* These routines are written to control the Double Talk PC speech + synthesizer. They are not ment to be thought of as a device driver + in that they do not register themselves as a chr device and there + is no file_operations structure. They are strictly to provide an + interface to the DoubleTalk from the speakup screen review package. +*/ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include /* need to know if 2.2.x or 2.3.x */ + +#include +#include "speakup_dtlk.h" /* local header file for DoubleTalk values */ + +#define synth_readable() ((synth_status = inb_p(synth_port_tts)) & TTS_READABLE) +#define synth_full() ((synth_status = inb_p(synth_port_tts)) & TTS_ALMOST_FULL) +static int synth_port_lpc; +static unsigned int synth_portlist[] = + { 0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0 }; +/* 200ms delay */ +static unsigned char synth_status = 0; /* speed up some checks which are done regularly */ + +static inline void spk_out(const char ch) +{ +int tmout = 100000; + + while (((synth_status = inb_p(synth_port_tts)) & TTS_WRITABLE) == 0); +outb_p(ch, synth_port_tts); + while ((((synth_status = inb_p(synth_port_tts)) & TTS_WRITABLE) != 0) + && (--tmout != 0) ); +} + +static void do_catch_up(unsigned long data) +{ +unsigned long jiff_in = jiffies; + +synth_stop_timer(); +synth_status = inb_p(synth_port_tts); +while ((synth_sent_bytes < synth_queued_bytes) && !(synth_status & TTS_ALMOST_FULL)) + { + spk_out(*(synth_buffer+synth_sent_bytes++)); + if (jiffies >= jiff_in+synth_jiffy_delta && *(synth_buffer+synth_sent_bytes-1) == ' ') { + spk_out(0x00); + synth_delay(synth_delay_time); + return; + } + } +if (synth_status & TTS_ALMOST_FULL) + { + synth_delay(synth_full_time); + return; + } +spk_out(0x00); +synth_sent_bytes = synth_queued_bytes = 0; +synth_timer_active = 0; +if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static void synth_write_tts(char ch) +{ + + if (ch < 0x00) return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into NULL to force talking. */ + ch = 0x00; + if (ch == SYNTH_CLEAR) { /* clear all and wake sleeping */ + outb_p(ch, synth_port_tts); /* output to TTS port */ + while (((synth_status = inb_p(synth_port_tts)) & TTS_WRITABLE) != 0); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_queued_bytes = synth_sent_bytes = 0; + return; + } + + synth_buffer_add(ch); + if (synth_buffering) return; + if (synth_timer_active == 0) synth_delay( synth_trigger_time ); +} + +static inline void synth_immediate_tts(const char *buf, short count) +{ +char ch; + + while (count--) { + ch = *buf++; + if (ch != SYNTH_CLEAR) + spk_out(ch); /* output to TTS port */ + } +} + +static char __init synth_read_tts(void) +{ +unsigned char ch; + + while (((synth_status = inb_p(synth_port_tts)) & TTS_READABLE) == 0); + ch = synth_status & 0x7f; + outb_p(ch, synth_port_tts); + while ((inb_p(synth_port_tts) & TTS_READABLE) != 0); +return (char) ch; +} + +/* interrogate the DoubleTalk PC and return its settings */ +static struct synth_settings * __init synth_interrogate(void) +{ +unsigned char *t; +static char buf[sizeof(struct synth_settings) + 1]; +int total, i; +static struct synth_settings status; + + synth_immediate_tts("\x18\x01?", 3); + + for (total = 0, i = 0; i < 50; i++) + { + buf[total] = synth_read_tts(); + if (total > 2 && buf[total] == 0x7f) break; + if (total < sizeof(struct synth_settings)) total++; + } + + t = buf; + status.serial_number = t[0] + t[1]*256; /* serial number is little endian */ + t += 2; + + i = 0; + while (*t != '\r') + { + status.rom_version[i] = *t; + if (i < sizeof(status.rom_version)-1) i++; + t++; + } + status.rom_version[i] = 0; + t++; + + status.mode = *t++; + status.punc_level = *t++; + status.formant_freq = *t++; + status.pitch = *t++; + status.speed = *t++; + status.volume = *t++; + status.tone = *t++; + status.expression = *t++; + status.ext_dict_loaded = *t++; + status.ext_dict_status = *t++; + status.free_ram = *t++; + status.articulation = *t++; + status.reverb = *t++; + status.eob = *t++; + return &status; +} + +static int __init synth_dev_probe(void) +{ +unsigned int port_val = 0; +int i = 0; +struct synth_settings *sp; + + printk("Probing for DoubleTalk.\n"); + if (synth_port_tts) { + printk("probe forced to %x by kernel command line\n", synth_port_tts); + if (synth_request_region(synth_port_tts-1, SYNTH_IO_EXTENT)) { + printk("sorry, port already reserved\n"); + return -EBUSY; + } + port_val = inw(synth_port_tts-1); + synth_port_lpc = synth_port_tts-1; + } + else { + for(i=0; synth_portlist[i]; i++) { + if (synth_request_region(synth_portlist[i], SYNTH_IO_EXTENT)) + continue; + port_val = inw(synth_portlist[i]); + if ((port_val &= 0xfbff) == 0x107f) { + synth_port_lpc = synth_portlist[i]; + synth_port_tts = synth_port_lpc+1; + break; + } + synth_release_region(synth_portlist[i], SYNTH_IO_EXTENT); + } + } + + if ((port_val &= 0xfbff) != 0x107f) { + printk("DoubleTalk PC: not found\n"); + return -ENODEV; + } + + while (inw_p(synth_port_lpc) != 0x147f ); /* wait until it's ready */ + sp = synth_interrogate(); + printk("DoubleTalk PC: %03x-%03x, ROM version %s,\n" + "DoubleTalk PC: serial number %u, driver: %s\n", + synth_port_lpc, synth_port_lpc+SYNTH_IO_EXTENT - 1, + sp->rom_version, sp->serial_number, synth->version); + synth_immediate_tts(synth->init, strlen(synth->init)); + return 0; +} + +static int synth_alive(void) { + return 1; /* I'm *INVINCIBLE* */ +} + +static const char init_string[] = "\x01@doubletalk found\n\x01\x31y\n"; +static const char reinit_string[] = "\x01@doubletalk found\n\x01\x31y\n"; + +static struct spk_variable vars[] = +{{"flush", "\x18", "_", (BUILDER|HARD_DIRECT|USE_RANGE|NO_USER), "*"}, + {"pitch", "50", "\x01_p", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,99"}, + {"caps_start", "\x01+35p", "_", 0, "*"}, + {"caps_stop", "\x01-35p", "_", 0, "*"}, + {"rate", "5", "\x01_s", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + {"tone", "1", "\x01_x", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,2"}, + {"volume", "5", "\x01_v", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + {"voice", "0", "\x01_o", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,7"}, + {"ffreq", "5", "\x01_f", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + {"punct", "7", "\x01_b", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,15"}, + END_VARS}; + +static char *config[] = +{"\x18", "\x01\x35\x30p", "\x01\x38\x35p", "\x01\x35\x30p", "\x01\x35s", + "\x01\x31x", "\x01\x35v", "\x01\x30o", "\x01\x35\x66", "\x01\x37\x62"}; + +struct spk_synth synth_dtlk = {"dtlk", "Version-0.13", "doubletalk_pc", + init_string, reinit_string, 500, 50, 5, 1000, + vars, config, 0, synth_dev_probe, do_catch_up, + synth_write_tts, synth_alive}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_dtlk.h linux.20pre2-ac1/drivers/char/speakup/speakup_dtlk.h --- linux.20pre2/drivers/char/speakup/speakup_dtlk.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_dtlk.h 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,57 @@ +/* speakup_dtlk.h - header file for speakups DoubleTalk driver. */ + +#define SYNTH_IO_EXTENT 0x02 + +#define SYNTH_CLEAR 0x18 /* stops speech */ + + /* TTS Port Status Flags */ +#define TTS_READABLE 0x80 /* mask for bit which is nonzero if a + byte can be read from the TTS port */ +#define TTS_SPEAKING 0x40 /* mask for SYNC bit, which is nonzero + while DoubleTalk is producing + output with TTS, PCM or CVSD + synthesizers or tone generators + (that is, all but LPC) */ +#define TTS_SPEAKING2 0x20 /* mask for SYNC2 bit, + which falls to zero up to 0.4 sec + before speech stops */ +#define TTS_WRITABLE 0x10 /* mask for RDY bit, which when set to + 1, indicates the TTS port is ready + to accept a byte of data. The RDY + bit goes zero 2-3 usec after + writing, and goes 1 again 180-190 + usec later. */ +#define TTS_ALMOST_FULL 0x08 /* mask for AF bit: When set to 1, + indicates that less than 300 bytes + are available in the TTS input + buffer. AF is always 0 in the PCM, + TGN and CVSD modes. */ +#define TTS_ALMOST_EMPTY 0x04 /* mask for AE bit: When set to 1, + indicates that less than 300 bytes + are remaining in DoubleTalk's input + (TTS or PCM) buffer. AE is always 1 + in the TGN and CVSD modes. */ + + /* data returned by Interrogate command */ +struct synth_settings +{ + unsigned short serial_number; /* 0-7Fh:0-7Fh */ + unsigned char rom_version[24]; /* null terminated string */ + unsigned char mode; /* 0=Character; 1=Phoneme; 2=Text */ + unsigned char punc_level; /* nB; 0-7 */ + unsigned char formant_freq; /* nF; 0-9 */ + unsigned char pitch; /* nP; 0-99 */ + unsigned char speed; /* nS; 0-9 */ + unsigned char volume; /* nV; 0-9 */ + unsigned char tone; /* nX; 0-2 */ + unsigned char expression; /* nE; 0-9 */ + unsigned char ext_dict_loaded; /* 1=exception dictionary loaded */ + unsigned char ext_dict_status; /* 1=exception dictionary enabled */ + unsigned char free_ram; /* # pages (truncated) remaining for + text buffer */ + unsigned char articulation; /* nA; 0-9 */ + unsigned char reverb; /* nR; 0-9 */ + unsigned char eob; /* 7Fh value indicating end of + parameter block */ + unsigned char has_indexing; /* nonzero if indexing is implemented */ +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_ltlk.c linux.20pre2-ac1/drivers/char/speakup/speakup_ltlk.c --- linux.20pre2/drivers/char/speakup/speakup_ltlk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_ltlk.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,342 @@ +/* + * speakup_ltlk.c - LiteTalk driver for Linux kernel 2.3.x and speakup + * + * author: Kirk Reiser and Andy Berdan + + Copyright (C) 1998-99 Kirk Reiser, and Andy Berdan + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + + Andy Berdan + 3-337 Wharncliffe Rd. N London, Ontario, Canada N6G 1E4 + */ + + +/* These routines are written to control the Lite Talk speech + synthesizer. They are not ment to be thought of as a device driver + in that they do not register themselves as a chr device and there + is no file_operations structure. They are strictly to provide an + interface to the LiteTalk from the speakup screen review package. +*/ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants & + serial_uart_config */ +#include /* for more serial constants */ +#if (LINUX_VERSION_CODE >= 0x20300) /* v 2.3.x */ +#include /* for struct serial_state */ +#endif +#include +#include + +#include "speakup_dtlk.h" /* local header file for LiteTalk values */ + +#define synth_full() ( !(inb(synth_port_tts + UART_MSR) & UART_MSR_CTS) ) +#define PROCSPEECH 0x00 /* synth process speech char */ +#define SPK_SERIAL_TIMEOUT 1000000 /* countdown values for serial timeouts */ +#define SPK_XMITR_TIMEOUT 3000000 /* countdown values transmitter/dsr timeouts */ +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 +#define NUM_DISABLE_TIMEOUTS 3 /* # of timeouts permitted before disable */ + +static int ltlk_alive = 0; + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] __initdata = { + SERIAL_PORT_DFNS +}; + +static inline int wait_for_xmitr(void) +{ + static int timeouts = 0; /* sequential number of timeouts */ + int check, tmout = SPK_XMITR_TIMEOUT; + + if ((ltlk_alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { + ltlk_alive = 0; + timeouts = 0; + return 0; + } + + /* holding register empty? */ + + do { + check = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk("LiteTalk: register timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + tmout = SPK_XMITR_TIMEOUT; + + /* CTS */ + do { + check = inb(synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int spk_serial_out(const char ch) +{ + if (ltlk_alive && synth_port_tts) { + if (wait_for_xmitr()) { + outb(ch, synth_port_tts); + return 1; + } + } + return 0; +} + +static unsigned char __init spk_serial_in(void) +{ + int c, lsr, tmout = SPK_SERIAL_TIMEOUT; + + do { + lsr = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk("time out while waiting for input.\n"); + return 0xff; + } + } while ((lsr & UART_LSR_DR) != UART_LSR_DR); + c = inb(synth_port_tts + UART_RX); + return (unsigned char) c; +} + +static void do_catch_up(unsigned long data) +{ + unsigned long jiff_in = jiffies; + + synth_stop_timer(); + while (synth_sent_bytes < synth_queued_bytes) + { + if (!spk_serial_out(*(synth_buffer+synth_sent_bytes))) { + synth_delay(synth_full_time); + return; + } + synth_sent_bytes++; + if (jiffies >= jiff_in+synth_jiffy_delta + && *(synth_buffer+synth_sent_bytes-1) == ' ') { + spk_serial_out(PROCSPEECH); + synth_delay(synth_delay_time); + return; + } + } + + synth_sent_bytes = synth_queued_bytes = 0; + spk_serial_out(PROCSPEECH); + synth_timer_active = 0; + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static void synth_write_tts(char ch) +{ + if (!ltlk_alive) return; + if (ch < 0x00) return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = PROCSPEECH; + + /* clear all and wake sleeping */ + if (ch == SYNTH_CLEAR) { + spk_serial_out(ch); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + + synth_buffer_add(ch); + if (synth_buffering) return; + if (synth_timer_active == 0) synth_delay( synth_trigger_time ); +} + +static inline void synth_immediate_tts(const char *buf, short count) +{ + while (count--) spk_serial_out(*buf++); + return; +} + +/* interrogate the LiteTalk and print its settings */ +static void __init synth_interrogate(void) +{ + unsigned char *t, i; + unsigned char buf[50], rom_v[20]; + + synth_immediate_tts("\x18\x01?", 3); + + for (i = 0; i < 50; i++) + { + buf[i] = spk_serial_in(); + if (i > 2 && buf[i] == 0x7f) break; + } + + t = buf+2; + i = 0; + while (*t != '\r') + { + rom_v[i] = *t; + t++; i++; + } + rom_v[i] = 0; + + printk("LiteTalk: ROM version: %s\n", rom_v); + return; +} + +static int __init serprobe(int index) +{ + struct serial_state *ser = NULL; + unsigned char test=0; + + if (synth_port_tts) { + for (test=0; test <= SPK_HI_TTY; test++) + if ( (rs_table+test)->port == synth_port_tts) { + ser = rs_table+test; + break; + } + } else ser = rs_table + index; + + /* don't do output yet... */ + if (synth_request_region(ser->port,8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb (ser->port + UART_LSR) == 0xff) { + // printk("initial test = %x\n", test); + synth_release_region(ser->port,8); + return -1; + } + outb(0, ser->port); + mdelay(1); + outb('\r', ser->port); + + ltlk_alive = 1; + /* ignore any error results, if port was forced */ + if (synth_port_tts) { + return 0; + } + + synth_port_tts = ser->port; + + /* check for device... */ + if (spk_serial_out(SYNTH_CLEAR)) return 0; + /*spk_serial_out('@'); + mdelay(100); + + spk_serial_out(0); + + if ((spk_serial_in() == ('C'+ 0x80)) + && ((test = spk_serial_in()) > ('A' + 0x80)) + && (test < ('Z' + 0x80)) + && (spk_serial_in() == 0x8d) ) + return 0; */ + + synth_release_region(ser->port,8); + ltlk_alive = synth_port_tts = 0; /* try next port */ + return -1; +} + +static int __init synth_dev_probe(void) +{ + int i; + + printk("Probing for LiteTalk.\n"); + if (synth_port_tts) + printk("Probe forced to 0x%x by kernel command line\n", synth_port_tts); + + for (i=SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe(i) == 0) break; /* found it */ + } + + if (ltlk_alive) { + /* found 'em */ + synth_interrogate(); + printk("LiteTalk: at %03x-%03x, driver %s\n", + synth_port_tts, synth_port_tts + 7, synth->version); + synth_write(synth->init, strlen(synth->init)); + return 0; + } + + printk("LiteTalk: not found\n"); + return -ENODEV; +} + +static int synth_alive(void) { + + if (ltlk_alive) { + return 1; /* already on */ + } else { + if ((!ltlk_alive) && (synth_port_tts)) { + if (wait_for_xmitr() > 0) { /* restart */ + ltlk_alive = 1; + synth_write(synth->reinit, strlen(synth->reinit)); + return 2; /* reenabled */ + } else printk("LiteTalk: can't restart synth\n"); + } + } + return 0; +} + +static const char init_string[] = "\01@light talk found\n\x01\x31y\n\0"; +static const char reinit_string[] = "\01@light talk restarted\n\x01\x31y\n\0"; +/* 200ms delay */ + +static struct spk_variable vars[] = +{ + { "flush", "\x18\x20", "_", (BUILDER|HARD_DIRECT|USE_RANGE|NO_USER), "*" }, + { "pitch", "50", "\x01_p", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,99" }, + { "caps_start", "\x01+35p", "_", 0, "*" }, + { "caps_stop", "\x01-35p", "_", 0, "*" }, + { "rate", "5", "\x01_s", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9" }, + { "tone", "1", "\x01_x", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,2" }, + { "volume", "5", "\x01_v", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9" }, + { "voice", "0", "\x01_o", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,7" }, + { "ffreq", "5", "\x01_f", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9" }, + { "punct", "7", "\x01_b", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,15" }, + END_VARS +}; + +static char *config[] = +{ "\x18\x20", "\x01\x35\x30p", "\x01\x38\x35p", "\x01\x35\x30p", "\x01\x35s", + "\x01\x31x", "\x01\x35v", "\x01\x30o", "\x01\x35\x66", "\x01\x37\x62" }; + +struct spk_synth synth_ltlk = { "ltlk", "Version-0.13", "litetalk", + init_string, reinit_string, 500, 50, 5, 5000, + vars, config, 0, synth_dev_probe, do_catch_up, + synth_write_tts, synth_alive }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakupmap.c linux.20pre2-ac1/drivers/char/speakup/speakupmap.c --- linux.20pre2/drivers/char/speakup/speakupmap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakupmap.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,298 @@ + +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable defkeymap.map > defkeymap.c */ + +#include +#include +#include + +u_short plain_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, + 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, + 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, + 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xfd26, + 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xfd0b, + 0xfd0a, 0xfd0c, 0xfd1e, 0xfd08, 0xfd07, 0xfd09, 0xfd14, 0xfd05, + 0xfd04, 0xfd06, 0xf701, 0xfd1b, 0xf206, 0xf200, 0xf03c, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xfd25, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short shift_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, + 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009, + 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, + 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53, + 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, + 0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, + 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xfd26, + 0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, + 0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf208, 0xf203, 0xfd0b, + 0xfd0a, 0xfd0c, 0xfd1e, 0xfd08, 0xfd07, 0xfd09, 0xfd14, 0xfd05, + 0xfd04, 0xfd06, 0xf701, 0xfd1b, 0xf206, 0xf200, 0xf03e, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xfd25, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short altgr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xfb61, 0xfb73, + 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf406, + 0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, + 0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xfd0f, + 0xfd20, 0xfd0d, 0xfd24, 0xfd22, 0xfd12, 0xfd23, 0xfd21, 0xfd10, + 0xfd11, 0xfd0e, 0xf701, 0xfd1d, 0xf206, 0xf200, 0xf07c, 0xf516, + 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd1c, 0xf702, 0xfd28, 0xfd25, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, + 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xfd26, + 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xfd0b, + 0xfd0a, 0xfd0c, 0xfd1e, 0xfd08, 0xfd07, 0xfd09, 0xfd14, 0xfd05, + 0xfd04, 0xfd06, 0xf701, 0xfd1b, 0xf206, 0xf200, 0xf200, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xf01c, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short shift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xfd26, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xfd0b, + 0xfd0a, 0xfd0c, 0xfd1e, 0xfd08, 0xfd07, 0xfd09, 0xfd14, 0xfd05, + 0xfd04, 0xfd06, 0xf701, 0xfd1b, 0xf206, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xfd25, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short altgr_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xfd26, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xfd0b, + 0xfd0a, 0xfd0c, 0xfd1e, 0xfd08, 0xfd07, 0xfd09, 0xfd14, 0xfd05, + 0xfd04, 0xfd06, 0xf701, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xfd25, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short alt_map[NR_KEYS] = { + 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, + 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809, + 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, + 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873, + 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, + 0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876, + 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xfd26, + 0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907, + 0xf908, 0xf909, 0xfd1e, 0xf904, 0xf905, 0xf906, 0xfd14, 0xf901, + 0xf902, 0xf903, 0xf900, 0xfd1b, 0xf206, 0xf200, 0xf83c, 0xf50a, + 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xf01c, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short shift_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf821, 0xf840, 0xf823, 0xf824, 0xf825, 0xf85e, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf851, 0xf857, 0xf845, 0xf852, 0xf854, 0xf859, 0xf855, 0xf849, + 0xf84f, 0xf850, 0xf87b, 0xf87d, 0xf201, 0xf702, 0xf841, 0xf853, + 0xf844, 0xf846, 0xf847, 0xf848, 0xf84a, 0xf84b, 0xf84c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf87c, 0xf85a, 0xf858, 0xf843, 0xf856, + 0xf842, 0xf84e, 0xf84d, 0xf83c, 0xf83e, 0xf200, 0xf700, 0xfd26, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xfd0b, + 0xfd0a, 0xfd0c, 0xfd1e, 0xfd08, 0xfd07, 0xfd09, 0xfd14, 0xfd05, + 0xfd04, 0xfd06, 0xf701, 0xfd1b, 0xf206, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xfd25, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, + 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813, + 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816, + 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xfd26, + 0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xfd0b, + 0xfd0a, 0xfd0c, 0xfd1e, 0xfd08, 0xfd07, 0xfd09, 0xfd14, 0xfd05, + 0xfd04, 0xfd06, 0xf701, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a, + 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xfd25, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short shift_ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, + 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813, + 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816, + 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xfd26, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xfd0b, + 0xfd0a, 0xfd0c, 0xfd1e, 0xfd08, 0xfd07, 0xfd09, 0xfd14, 0xfd05, + 0xfd04, 0xfd06, 0xf701, 0xfd1b, 0xf206, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xfd03, 0xf702, 0xfd27, 0xfd25, 0xf703, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, altgr_ctrl_map, 0, + alt_map, shift_alt_map, 0, 0, + ctrl_alt_map, shift_ctrl_alt_map, 0 +}; + +unsigned int keymap_count = 10; + + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + 0, + 0, + 0, + 0, + func_buf + 145, + func_buf + 146, + func_buf + 147, + func_buf + 148, + func_buf + 149, + func_buf + 150, + 0, +}; + +struct kbdiacr accent_table[MAX_DIACR] = { +}; + +unsigned int accent_table_size = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakupmap.map linux.20pre2-ac1/drivers/char/speakup/speakupmap.map --- linux.20pre2/drivers/char/speakup/speakupmap.map 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakupmap.map 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,308 @@ +# us.map +# with some additions from quinlan@spectrum.cs.bucknell.edu (Daniel Quinlan) +# 14 Mar 1994 +keymaps 0-2,4-6,8,9,12,13 +keycode 1 = Escape Escape + alt keycode 1 = Meta_Escape +keycode 2 = one exclam + alt keycode 2 = Meta_one + alt shift keycode 2 = Meta_exclam +keycode 3 = two at at + control keycode 3 = nul + control shift keycode 3 = nul + alt keycode 3 = Meta_two + alt shift keycode 3 = Meta_at +keycode 4 = three numbersign + control keycode 4 = Escape + alt keycode 4 = Meta_three + alt shift keycode 4 = Meta_numbersign +keycode 5 = four dollar dollar + control keycode 5 = Control_backslash + alt keycode 5 = Meta_four + alt shift keycode 5 = Meta_dollar +keycode 6 = five percent + control keycode 6 = Control_bracketright + alt keycode 6 = Meta_five + alt shift keycode 6 = Meta_percent +keycode 7 = six asciicircum + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six + alt shift keycode 7 = Meta_asciicircum +keycode 8 = seven ampersand braceleft + control keycode 8 = Control_underscore + alt keycode 8 = Meta_seven +keycode 9 = eight asterisk bracketleft + control keycode 9 = Delete + alt keycode 9 = Meta_eight +keycode 10 = nine parenleft bracketright + alt keycode 10 = Meta_nine +keycode 11 = zero parenright braceright + alt keycode 11 = Meta_zero +keycode 12 = minus underscore backslash + control keycode 12 = Control_underscore + control shift keycode 12 = Control_underscore + alt keycode 12 = Meta_minus +keycode 13 = equal plus + alt keycode 13 = Meta_equal +keycode 14 = Delete Delete + alt keycode 14 = Meta_Delete +keycode 15 = Tab Tab + alt keycode 15 = Meta_Tab +keycode 16 = q +keycode 17 = w +keycode 18 = e +keycode 19 = r +keycode 20 = t +keycode 21 = y +keycode 22 = u +keycode 23 = i +keycode 24 = o +keycode 25 = p +keycode 26 = bracketleft braceleft + control keycode 26 = Escape + alt keycode 26 = Meta_bracketleft + alt shift keycode 26 = Meta_braceleft +keycode 27 = bracketright braceright asciitilde + control keycode 27 = Control_bracketright + alt keycode 27 = Meta_bracketright + alt shift keycode 27 = Meta_braceright +keycode 28 = Return + alt keycode 28 = 0x080d +keycode 29 = Control +keycode 30 = a +keycode 31 = s +keycode 32 = d +keycode 33 = f +keycode 34 = g +keycode 35 = h +keycode 36 = j +keycode 37 = k +keycode 38 = l +keycode 39 = semicolon colon + alt keycode 39 = Meta_semicolon +keycode 40 = apostrophe quotedbl + control keycode 40 = Control_g + alt keycode 40 = Meta_apostrophe +keycode 41 = grave asciitilde + control keycode 41 = nul + alt keycode 41 = Meta_grave +keycode 42 = Shift +keycode 43 = backslash bar + control keycode 43 = Control_backslash + alt keycode 43 = Meta_backslash + alt shift keycode 43 = Meta_bar +keycode 44 = z +keycode 45 = x +keycode 46 = c +keycode 47 = v +keycode 48 = b +keycode 49 = n +keycode 50 = m +keycode 51 = comma less + alt keycode 51 = Meta_comma + alt shift keycode 51 = Meta_less +keycode 52 = period greater + alt keycode 52 = Meta_period + alt shift keycode 52 = Meta_greater +keycode 53 = slash question + control keycode 53 = Delete + alt keycode 53 = Meta_slash +keycode 54 = Shift +keycode 55 = 0x0d26 +#keycode 55 = KP_Multiply + altgr keycode 55 = 0x0406 +keycode 56 = Alt +keycode 57 = space space + control keycode 57 = nul + alt keycode 57 = Meta_space +keycode 58 = Caps_Lock +keycode 59 = F1 F11 Console_13 + control keycode 59 = F1 + alt keycode 59 = Console_1 + control alt keycode 59 = Console_1 +keycode 60 = F2 F12 Console_14 + control keycode 60 = F2 + alt keycode 60 = Console_2 + control alt keycode 60 = Console_2 +keycode 61 = F3 F13 Console_15 + control keycode 61 = F3 + alt keycode 61 = Console_3 + control alt keycode 61 = Console_3 +keycode 62 = F4 F14 Console_16 + control keycode 62 = F4 + alt keycode 62 = Console_4 + control alt keycode 62 = Console_4 +keycode 63 = F5 F15 Console_17 + control keycode 63 = F5 + alt keycode 63 = Console_5 + control alt keycode 63 = Console_5 +keycode 64 = F6 F16 Console_18 + control keycode 64 = F6 + alt keycode 64 = Console_6 + control alt keycode 64 = Console_6 +keycode 65 = F7 F17 Console_19 + control keycode 65 = F7 + alt keycode 65 = Console_7 + control alt keycode 65 = Console_7 +keycode 66 = F8 F18 Console_20 + control keycode 66 = F8 + alt keycode 66 = Console_8 + control alt keycode 66 = Console_8 +keycode 67 = F9 F19 Console_21 + control keycode 67 = F9 + alt keycode 67 = Console_9 + control alt keycode 67 = Console_9 +keycode 68 = F10 F20 Console_22 + control keycode 68 = F10 + alt keycode 68 = Console_10 + control alt keycode 68 = Console_10 +keycode 69 = Num_Lock +keycode 70 = Scroll_Lock Show_Memory Show_Registers + control keycode 70 = Show_State + alt keycode 70 = Scroll_Lock +keycode 71 = 0x0d0b + altgr keycode 71 = 0x0d0f +#keycode 71 = KP_7 + alt keycode 71 = Ascii_7 +keycode 72 = 0x0d0a + altgr keycode 72 = 0x0d20 +#keycode 72 = KP_8 + alt keycode 72 = Ascii_8 +keycode 73 = 0x0d0c + altgr keycode 73 = 0x0d0d +#keycode 73 = KP_9 + alt keycode 73 = Ascii_9 +keycode 74 = 0x0d1e + altgr keycode 74 = 0x0d24 +keycode 75 = 0x0d08 + altgr keycode 75 = 0x0d22 +#keycode 75 = KP_4 + alt keycode 75 = Ascii_4 +keycode 76 = 0x0d07 +#keycode 76 = KP_5 + altgr keycode 76 = 0x0d12 + alt keycode 76 = Ascii_5 +keycode 77 = 0x0d09 + altgr keycode 77 = 0x0d23 +#keycode 77 = KP_6 + alt keycode 77 = Ascii_6 +#keycode 78 = KP_Add +keycode 78 = 0x0d14 + altgr keycode 78 = 0x0d21 +keycode 79 = 0x0d05 +#keycode 79 = KP_1 + altgr keycode 79 = 0x0d10 + alt keycode 79 = Ascii_1 +keycode 80 = 0x0d04 +#keycode 80 = KP_2 + altgr keycode 80 = 0x0d11 + alt keycode 80 = Ascii_2 +keycode 81 = 0x0d06 + altgr keycode 81 = 0x0d0e +#keycode 81 = KP_3 + alt keycode 81 = Ascii_3 +#keycode 82 = 0x0d14 +keycode 82 = AltGr +#keycode 82 = KP_0 + alt keycode 82 = Ascii_0 +#keycode 83 = KP_Period +keycode 83 = 0x0d1b + altgr keycode 83 = 0x0d1d + altgr control keycode 83 = Boot + control alt keycode 83 = Boot +keycode 84 = Last_Console +keycode 85 = +keycode 86 = less greater bar + alt keycode 86 = Meta_less +keycode 87 = F11 F11 Console_23 + control keycode 87 = F11 + alt keycode 87 = Console_11 + control alt keycode 87 = Console_11 +keycode 88 = F12 F12 Console_24 + control keycode 88 = F12 + alt keycode 88 = Console_12 + control alt keycode 88 = Console_12 +keycode 89 = +keycode 90 = +keycode 91 = +keycode 92 = +keycode 93 = +keycode 94 = +keycode 95 = +keycode 96 = 0x0d03 + altgr keycode 96 = 0x0d1c +#keycode 96 = KP_Enter +keycode 97 = Control +keycode 98 = 0x0d27 +#keycode 98 = KP_Divide + altgr keycode 98 = 0x0d28 +#keycode 99 = Control_backslash +keycode 99 = 0x0d25 + control keycode 99 = Control_backslash + alt keycode 99 = Control_backslash +keycode 100 = Alt +keycode 101 = Break +keycode 102 = Find +keycode 103 = Up +keycode 104 = Prior + shift keycode 104 = Scroll_Backward +keycode 105 = Left + alt keycode 105 = Decr_Console +keycode 106 = Right + alt keycode 106 = Incr_Console +keycode 107 = Select +keycode 108 = Down +keycode 109 = Next + shift keycode 109 = Scroll_Forward +keycode 110 = Insert +keycode 111 = Remove + altgr control keycode 111 = Boot + control alt keycode 111 = Boot +keycode 112 = +keycode 113 = +keycode 114 = +keycode 115 = +keycode 116 = +keycode 117 = +keycode 118 = +keycode 119 = +keycode 120 = +keycode 121 = +keycode 122 = +keycode 123 = +keycode 124 = +keycode 125 = +keycode 126 = +keycode 127 = +string F1 = "\033[[A" +string F2 = "\033[[B" +string F3 = "\033[[C" +string F4 = "\033[[D" +string F5 = "\033[[E" +string F6 = "\033[17~" +string F7 = "\033[18~" +string F8 = "\033[19~" +string F9 = "\033[20~" +string F10 = "\033[21~" +string F11 = "\033[23~" +string F12 = "\033[24~" +string F13 = "\033[25~" +string F14 = "\033[26~" +string F15 = "\033[28~" +string F16 = "\033[29~" +string F17 = "\033[31~" +string F18 = "\033[32~" +string F19 = "\033[33~" +string F20 = "\033[34~" +string Find = "\033[1~" +string Insert = "\033[2~" +string Remove = "\033[3~" +string Select = "\033[4~" +string Prior = "\033[5~" +string Next = "\033[6~" +string F21 = "" +string F22 = "" +string F23 = "" +string F24 = "" +string F25 = "" +string F26 = "" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_spkout.c linux.20pre2-ac1/drivers/char/speakup/speakup_spkout.c --- linux.20pre2/drivers/char/speakup/speakup_spkout.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_spkout.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,301 @@ +/* + * speakup_speakout.c for linux kernels 2.2.x and speakup + * + * author: Kirk Reiser and John Covici + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + + +/* These routines are written to control the speakout serial speech + synthesizer. They are not ment to be thought of as a device driver + in that they do not register themselves as a chr device and there + is no file_operations structure. They are strictly to provide an + interface to the speakout from the speakup screen review package. +*/ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants and + serial_uart_config */ +#include /* for more serial constants */ +#if (LINUX_VERSION_CODE >= 0x20300) /* v 2.3.x */ +#include /* for struct serial_state */ +#endif +#include +#include + +#define SYNTH_CLEAR 0x18 +#define SPK_TIMEOUT 100 /* buffer timeout in ms */ +#define NUM_DISABLE_TIMEOUTS 3 /* disable synth if n timeouts */ +#define SPK_SERIAL_TIMEOUT 1000000 /* countdown values for serial timeouts */ +#define SPK_XMITR_TIMEOUT 1000000 /* countdown values transmitter/dsr timeouts */ +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 + +static int spkout_alive = 0; +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +static int wait_for_xmitr(void) +{ +static int timeouts = 0; /* sequential number of timeouts */ +int check, tmout = SPK_XMITR_TIMEOUT; + + if ((spkout_alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { + spkout_alive = 0; + timeouts = 0; + return 0; + } + + /* holding register empty? */ + do { + check = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk("SpeakOut: timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + + tmout = SPK_XMITR_TIMEOUT; + /* CTS */ + do { + check = inb(synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int spk_serial_out(const char ch) +{ + if (spkout_alive && synth_port_tts) { + if (wait_for_xmitr()) { + outb(ch, synth_port_tts); + return 1; + } + } + return 0; +} + +static unsigned char __init spk_serial_in(void) +{ +int c, lsr, tmout = SPK_SERIAL_TIMEOUT; + + do { + lsr = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) return 0xff; + } while (!(lsr & UART_LSR_DR)); + c = inb(synth_port_tts + UART_RX); + return (unsigned char) c; +} + +static void do_catch_up(unsigned long data) +{ + unsigned long jiff_in = jiffies; + +synth_stop_timer(); + while (synth_sent_bytes < synth_queued_bytes) + { + if (!spk_serial_out(*(synth_buffer+synth_sent_bytes))) { + synth_delay(synth_full_time); + return; + } + synth_sent_bytes++; + if (jiffies >= jiff_in+synth_jiffy_delta && *(synth_buffer+synth_sent_bytes-1) == ' ') { + spk_serial_out('\r'); + synth_delay(synth_delay_time); + return; + } + } + +synth_sent_bytes = synth_queued_bytes = 0; +synth_timer_active = 0; +spk_serial_out('\r'); +if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + +static inline void clear_it(char ch) +{ + while ((inb(synth_port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY); + outb(ch, synth_port_tts); +} + +void synth_write_tts(char ch) +{ + if (!spkout_alive) return; + if (ch < 0x00) return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = '\r'; + if (ch == SYNTH_CLEAR) /* clear all and wake sleeping */ + { + clear_it(ch); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + +synth_buffer_add(ch); +if (synth_buffering) return; +if (synth_timer_active == 0) synth_delay( synth_trigger_time ); +return; +} + +static inline void synth_immediate_tts(const char *buf, short count) +{ + while (count--) synth_write_tts(*buf++); +return; +} + +/* + * Setup initial baud/bits/parity. Swiped from serial.c (console section) + * Return non-zero if we didn't find a serial port. + */ +static int __init serprobe(int index) +{ + struct serial_state *ser = NULL; + unsigned char test=0; + + if (synth_port_tts) { + for (test=0; test <= SPK_HI_TTY; test++) + if ( (rs_table+test)->port == synth_port_tts) { + ser = rs_table+test; + break; + } + } else ser = rs_table + index; + + if (synth_request_region(ser->port,8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb (ser->port + UART_LSR) == 0xff) { + synth_release_region(ser->port,8); + return -1; + } + mdelay(1); + + spkout_alive = 1; + /* ignore any error results, if port was forced */ + if (synth_port_tts) + return 0; + + synth_port_tts = ser->port; + + /* check for speak out now... */ + spk_serial_out(0x05); + spk_serial_out('['); /* set index cmd */ + spk_serial_out(0x0a); /* index mark */ + spk_serial_out('\r'); /* flush buffer for safety */ + mdelay(10); + if (spk_serial_in() == 0x0a) return 0; + + synth_release_region(ser->port,8); + spkout_alive = synth_port_tts = 0; /* not ignoring */ + return -1; +} + +static int __init synth_dev_probe(void) +{ +int i=0; + + printk("Probing for Speak Out.\n"); + if (synth_port_tts != 0) /* set from commandline */ + printk("Probe forced to 0x%x by kernel command line.\n",synth_port_tts); + + for (i=SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe(i) == 0) break; /* found it */ + } + + if (spkout_alive) { + /* found 'em */ + printk("Speak Out: %03x-%03x, Driver version %s,\n", + synth_port_tts, synth_port_tts + 7, synth->version); + synth_immediate_tts(synth->init, strlen(synth->init)); + return 0; + } + + printk("Speak Out: not found\n"); + return -ENODEV; +} + + /* this is a new function required by speakup: + * if synth is not active, make it active and return 2 + * if synth is already active, return 1 + * otherwise (if it can't be made active), return 0 + */ +static int synth_alive(void) +{ + if (spkout_alive) + return 1; /* already on */ + else if ((!spkout_alive) && (synth_port_tts)) { + if (wait_for_xmitr() > 0) { /* restart */ + spkout_alive = 1; + synth_write(synth->reinit, strlen(synth->reinit)); + return 2; /* reenabled */ + } else printk("Speak Out: can't restart synth\n"); + } + return 0; +} + +static const char init_string[] = "\x05R7\x05P3\x05Ti\x05W1\x05I2\x05\x43\x33\x05MnSpeakout found\r"; +static const char reinit_string[] = "\x05R7\x05P3\x05Ti\x05W1\x05I2\x05\x43\x33\x05MnSpeakout found\r"; + +static struct spk_variable vars[] = +{{"flush", "\x18", "_", (BUILDER|HARD_DIRECT|NO_USER), "*"}, + {"pitch", "3", "\x05P_", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + {"caps_start", "\x05P+", "_", 0, "*"}, + {"caps_stop", "\x05P-", "_", 0, "*"}, + {"rate", "7", "\x05R_", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + {"tone", "i", "\x05T_", (HARD_DIRECT|USE_RANGE), "a,z"}, + {"volume", "9", "\x05V_", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + {"punct", "n", "\x05M_", HARD_DIRECT, "nmsa"}, + END_VARS}; + +static char *config[] = +{"\x18", "\x05P3", "\x05P+", "\x05P-", "\x05R7", "\x05Ti", "\x05V9", + "\x05Mn"}; + +struct spk_synth synth_spkout = {"spkout", "Version-0.12", "speakout", + init_string, reinit_string, 500, 50, 5, 5000, + vars, config, 0, synth_dev_probe, do_catch_up, + synth_write_tts, synth_alive}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/speakup_txprt.c linux.20pre2-ac1/drivers/char/speakup/speakup_txprt.c --- linux.20pre2/drivers/char/speakup/speakup_txprt.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/speakup_txprt.c 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,287 @@ +/* + * speakup_txprt.c for linux kernels 2.2.x and speakup + * + * author: Kirk Reiser + + Copyright (C) 1998-99 Kirk Reiser. + + 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 + + Kirk Reiser + 261 Trott dr. London, Ontario, Canada. N6G 1B6 + */ + + +/* These routines are written to control the Transport serial speech + synthesizer. They are not ment to be thought of as a device driver + in that they do not register themselves as a chr device and there + is no file_operations structure. They are strictly to provide an + interface to the txprt from the speakup screen review package. */ + +#define KERNEL +#include +#include +#include +#include /* for verify_area */ +#include /* for -EBUSY */ +#include /* for check_region, request_region */ +#include /* for loops_per_sec */ +#include /* for put_user_byte */ +#include /* for inb_p, outb_p, inb, outb, etc... */ +#include /* for wait_queue */ +#include /* kd_mksound */ +#include /* for __init */ +#include +#include /* for rs_table, serial constants and + serial_uart_config */ +#include /* for more serial constants */ +#if (LINUX_VERSION_CODE >= 0x20300) /* v 2.3.x */ +#include /* for struct serial_state */ +#endif +#include +#include + +#define SYNTH_CLEAR 0x18 +#define SPK_TIMEOUT 100 /* buffer timeout in ms */ +#define NUM_DISABLE_TIMEOUTS 3 /* disable synth if n timeouts */ +#define SPK_SERIAL_TIMEOUT 1000000 /* countdown values for serial timeouts */ +#define SPK_XMITR_TIMEOUT 1000000 /* countdown values transmitter/dsr timeouts */ +#define SPK_LO_TTY 0 /* check ttyS0 ... ttyS3 */ +#define SPK_HI_TTY 3 +#define PROCSPEECH '\r' /* process speech char */ + +static int txprt_alive = 0; +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct serial_state rs_table[] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +static int timeouts = 0; /* sequential number of timeouts */ + +static int wait_for_xmitr(void) +{ +int check, tmout = SPK_XMITR_TIMEOUT; + + if ((txprt_alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { + txprt_alive = 0; + timeouts = 0; + return 0; + } + + /* holding register empty? */ + do { + check = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) { + printk("TXPRT: timed out\n"); + timeouts++; + return 0; + } + } while ((check & BOTH_EMPTY) != BOTH_EMPTY); + + tmout = SPK_XMITR_TIMEOUT; + /* CTS */ + do { + check = inb(synth_port_tts + UART_MSR); + if (--tmout == 0) { + timeouts++; + return 0; + } + } while ((check & UART_MSR_CTS) != UART_MSR_CTS); + + timeouts = 0; + return 1; +} + +static inline int spk_serial_out(const char ch) +{ + if (txprt_alive && synth_port_tts) { + if (wait_for_xmitr()) { + outb(ch, synth_port_tts); + return 1; + } + } + return 0; +} + +static unsigned char __init spk_serial_in(void) +{ +int c, lsr, tmout = SPK_SERIAL_TIMEOUT; + + do { + lsr = inb(synth_port_tts + UART_LSR); + if (--tmout == 0) return 0xff; + } while (!(lsr & UART_LSR_DR)); + c = inb(synth_port_tts + UART_RX); + return (unsigned char) c; +} + +static void do_catch_up(unsigned long data) +{ + unsigned long jiff_in = jiffies; + +synth_stop_timer(); + while (synth_sent_bytes < synth_queued_bytes) + { + if (!spk_serial_out(*(synth_buffer+synth_sent_bytes))) { + synth_delay(synth_full_time); + return; + } + synth_sent_bytes++; + if (jiffies >= jiff_in+synth_jiffy_delta && *(synth_buffer+synth_sent_bytes-1) == ' ') + { + spk_serial_out(PROCSPEECH); + synth_delay(synth_delay_time); + return; + } + } + +synth_sent_bytes = synth_queued_bytes = 0; +spk_serial_out(PROCSPEECH); +synth_timer_active = 0; +if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); +} + + +static void synth_write_tts(char ch) +{ + if (!txprt_alive) return; + if (ch < 0x00) return; /* don't want unprintable chars */ + if (ch == 0x0a) /* turn lf into to force talking. */ + ch = PROCSPEECH; + if (ch == SYNTH_CLEAR) /* clear all and wake sleeping */ + { + spk_serial_out(ch); + if (waitqueue_active(&synth_sleeping_list)) + wake_up_interruptible(&synth_sleeping_list); + synth_timer_active = synth_queued_bytes = synth_sent_bytes = 0; + return; + } + +synth_buffer_add(ch); +if (synth_buffering) return; +if (synth_timer_active == 0) synth_delay( synth_trigger_time ); +return; +} + +static inline void synth_immediate_tts(const char *buf, short count) +{ + while (count--) spk_serial_out(*buf++); +return; +} + +static int __init serprobe(int index) +{ + struct serial_state *ser = NULL; + unsigned char test=0; + + if (synth_port_tts) { + for (test=0; test <= SPK_HI_TTY; test++) + if ( (rs_table+test)->port == synth_port_tts) { + ser = rs_table+test; + break; + } + } else ser = rs_table + index; + + if (synth_request_region(ser->port,8)) + return -1; + + initialize_uart(ser); + /* If we read 0xff from the LSR, there is no UART here. */ + if (inb (ser->port + UART_LSR) == 0xff) { + synth_release_region(ser->port,8); + return -1; + } + + txprt_alive = 1; + if (synth_port_tts) return 0; + synth_port_tts = ser->port; + + /* check for txprt now... */ + spk_serial_out(0x18); + spk_serial_out('\r'); + mdelay(1); + spk_serial_out(0x05); + spk_serial_out('I'); + spk_serial_out('k'); + mdelay(10); + spk_serial_out(0x05); + spk_serial_out('Q'); + if ((test = spk_serial_in()) == 'k') return 0; + else printk("synth returned %x\n", test); + + synth_release_region(ser->port,8); + timeouts = txprt_alive = synth_port_tts = 0; + return -1; +} + +static int __init synth_dev_probe(void) +{ +int i; + + printk("Probing for Transport.\n"); + if (synth_port_tts) + printk("Probe forced to 0x%x by kernel command line\n", synth_port_tts); + for (i=SPK_LO_TTY; i <= SPK_HI_TTY; i++) { + if (serprobe(i) == 0) break; /* found it */ + } + + if (txprt_alive) { + /* found 'em */ + printk("Transport: %03x-%03x, Driver version %s,\n", + synth_port_tts, synth_port_tts + 7, synth->version); + synth_immediate_tts(synth->init, strlen(synth->init)); + return 0; + } + + printk("Transport: not found\n"); + return -ENODEV; +} + +static int synth_alive(void) +{ + if (txprt_alive) + return 1; /* already on */ + else if ((!txprt_alive) && (synth_port_tts)) { + if (wait_for_xmitr() > 0) { /* restart */ + txprt_alive = 1; + synth_write(synth->reinit, strlen(synth->reinit)); + return 2; /* reenabled */ + } else printk("Transport: can't restart synth\n"); + } + return 0; +} + + +static const char init_string[] = "\x05$\x05P5\x05R5\x05N1Transport found\r"; +static const char reinit_string[] = "\x05$\x05P5\x05R5\x05N1Transport initialized\r"; +static struct spk_variable vars[] = +{{"flush", "\x18\r", "_", (BUILDER|HARD_DIRECT|NO_USER), "*"}, + {"pitch", "5", "\x05P_", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + {"caps_start", "\x05P8", "_", 0, "*"}, + {"caps_stop", "\x05P5", "_", 0, "*"}, + {"rate", "5", "\x05R_", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + {"tone", "I", "\x05T_", (HARD_DIRECT|USE_RANGE), "a,z"}, + {"volume", "5", "\x05V_", (NUMERIC|HARD_DIRECT|USE_RANGE), "0,9"}, + END_VARS}; + +static char *config[] = +{"\x18\r", "\x05P5", "\x05P8", "\x05P5", "\x05R5", "\x05TI", "\x05V5", NULL}; + +struct spk_synth synth_txprt = {"txprt", "Version-0.13", "transport", + init_string, reinit_string, 500, 50, 5, 5000, + vars, config, 0, synth_dev_probe, do_catch_up, + synth_write_tts, synth_alive}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/symbols.h linux.20pre2-ac1/drivers/char/speakup/symbols.h --- linux.20pre2/drivers/char/speakup/symbols.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/symbols.h 2002-08-13 22:28:55.000000000 +0100 @@ -0,0 +1,62 @@ +#ifndef _SPEAKUP_SYMBOLS_H +#define _SPEAKUP_SYMBOLS_H + +#include + +#define PUNC_CHARS_SIZE 33 +#define PUNC_CHARS "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" + +#define DEFAULT_SPKUP_VARS \ +/* line_wrap_bleep */ "1", \ +/* attribute_bleep */ "1", \ +/* bleep_time (ms) */ "3", \ +/* spell_delay */ "1", \ +/* punc_level */ "1", \ +/* say_control */ "0", \ +/* no_interrupt */ "0", \ +/* punc_none */ "", \ +/* punc_some */ "/$%&@", \ +/* punc_most */ "($%&#@=+*^<>|\\)", \ +/* punc_all */ PUNC_CHARS, \ +/* key_echo */ "1", \ +/* bell_pos */ "0" + +// alias the necessary hardware constants off to generalized constants +#define FLUSH 0 +#define PITCH 1 +#define CAPS_START 2 +#define CAPS_STOP 3 + +#define LINE_WRAP_BLEEP 0 +#define ATTRIBUTE_BLEEP 1 +#define BLEEP_TIME 2 +#define SPELL_DELAY 3 +#define PUNCT_LEVEL 4 +#define SAY_CONTROL 5 +#define NO_INTERRUPT 6 +#define PUNC_NONE 7 +#define PUNC_SOME 8 +#define PUNC_MOST 9 +#define PUNC_ALL 10 +#define KEY_ECHO 11 +#define BELL_POS 12 + +// beginning of the 4 punc levels +#define PUNC_OFFSET PUNC_NONE + +#define SPKUP_VARS \ +{"line_wrap_bleep", "1", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), TOGGLE}, \ +{"attribute_bleep", "1", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), TOGGLE}, \ +{"bleep_time", "3", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), "1,9"}, \ +{"spell_delay", "1", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), "1,5"}, \ +{"punc_level", "1", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), "0,3"}, \ +{"say_control", "0", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), TOGGLE}, \ +{"no_interrupt", "0", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), TOGGLE}, \ +{"punc_none", "", "_", (SOFT_DIRECT|NO_USER), ""}, \ +{"punc_some", "/$%&", "_", (MULTI_SET|SOFT_DIRECT), PUNC_CHARS}, \ +{"punc_most", "($%&#@=+*^<>|\\)", "_", (MULTI_SET|SOFT_DIRECT), PUNC_CHARS}, \ +{"punc_all", PUNC_CHARS, "_", (SOFT_DIRECT|NO_USER), ""}, \ +{"key_echo", "1", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), TOGGLE}, \ +{"bell_pos", "0", "_", (NUMERIC|SOFT_DIRECT|USE_RANGE), "0,200"}, \ +END_VARS +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/speakup/TODO linux.20pre2-ac1/drivers/char/speakup/TODO --- linux.20pre2/drivers/char/speakup/TODO 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/speakup/TODO 2002-08-06 15:42:07.000000000 +0100 @@ -0,0 +1,66 @@ +The format of this file is getting organized to help me keep track of +where we are going. I am organizing it into three sections. +Immediate things which need to be done I.E. code re-organization. New +features we are currently working on or at least in the near future. +Long term features which will move to the new features list as the new +features list empties. + +Immediate: + +Screen cursoring needs to become more reliable and consistant. + +New-Features: + +convert the individual synth drivers into modules (involves moving buffering + into speakup proper). + +synth_file fops need to be filled in and expanded such as some type of +ioctl function and a real synth_file_read() function. + + +Long-Term-Features: + +keyboard macros (ala ASAP/qedit) + +finding calling process, so per-program configurations can be loaded + +Check park status and store it before doing a console switch. (non-trivial) + +make numlock turn review pad to number pad. + +user defined scroll-back ala shift-pgup. + +insert as 'capslock-style'/'next-style' key -- have internalized speakup + variable, which tracks state of the insert key; each speakup bare-key + function checks the variable, and possibly calls the alternate + function and returns + +Expand phonetic spelling to toggle on and off and work with previous + and next and spell_word functions. Also shift pitch on phonetic words + for capitalized letters. [partially complete] + +Chuck wants a bleep if the shift key is hit and the capslock is on. +Here is his suggested test sequence: +1. check if the caps lock is set; if it is, +2. check if the char is alphabetic; if it is, +3. check if the shift key is pressed; if it is, +4. send a bell char to the console. + +Frank would like a fast way to go to the end of the word in addition +to moving to the beginning. + +I'd like a function to move the reading cursor to the last char on a +line in addition to the right edge of the screen. + +Gene thinks we should have a /proc function to store and show the rom +version of any synth currently operating. + +The items in each list have no connection with the order of +implementation. I just jotted them down as I thought of them. + +Bill Acker WB2FLW: When the final result is "none", then, no trace of +Speakup. and use default keymap otherwise business as usual plus use +"built-in" speakupmap.map + +Look at lilo routines which init the serial device and compare to speakup drivers. + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/synclinkmp.c linux.20pre2-ac1/drivers/char/synclinkmp.c --- linux.20pre2/drivers/char/synclinkmp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/synclinkmp.c 2002-08-12 10:45:28.000000000 +0100 @@ -0,0 +1,5615 @@ +/* + * $Id: synclinkmp.c,v 3.17 2002/04/22 16:05:39 paulkf Exp $ + * + * Device driver for Microgate SyncLink Multiport + * high speed multiprotocol serial adapter. + * + * written by Paul Fulghum for Microgate Corporation + * paulkf@microgate.com + * + * Microgate and SyncLink are trademarks of Microgate Corporation + * + * Derived from serial.c written by Theodore Ts'o and Linus Torvalds + * This code is released under the GNU General Public License (GPL) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) +#if defined(__i386__) +# define BREAKPOINT() asm(" int $3"); +#else +# define BREAKPOINT() { } +#endif + +#define MAX_DEVICES 12 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE +#define CONFIG_SYNCLINK_SYNCPPP 1 +#endif + +#ifdef CONFIG_SYNCLINK_SYNCPPP +#if LINUX_VERSION_CODE < VERSION(2,4,3) +#include "../net/wan/syncppp.h" +#else +#include +#endif +#endif + +#include +#define GET_USER(error,value,addr) error = get_user(value,addr) +#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 +#define PUT_USER(error,value,addr) error = put_user(value,addr) +#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 + +#include + +#include "linux/synclink.h" + +static MGSL_PARAMS default_params = { + MGSL_MODE_HDLC, /* unsigned long mode */ + 0, /* unsigned char loopback; */ + HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ + HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ + 0, /* unsigned long clock_speed; */ + 0xff, /* unsigned char addr_filter; */ + HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ + HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ + HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ + 9600, /* unsigned long data_rate; */ + 8, /* unsigned char data_bits; */ + 1, /* unsigned char stop_bits; */ + ASYNC_PARITY_NONE /* unsigned char parity; */ +}; + +/* size in bytes of DMA data buffers */ +#define SCABUFSIZE 1024 +#define SCA_MEM_SIZE 0x40000 +#define SCA_BASE_SIZE 512 +#define SCA_REG_SIZE 16 +#define SCA_MAX_PORTS 4 +#define SCAMAXDESC 128 + +#define BUFFERLISTSIZE 4096 + +/* SCA-I style DMA buffer descriptor */ +typedef struct _SCADESC +{ + u16 next; /* lower l6 bits of next descriptor addr */ + u16 buf_ptr; /* lower 16 bits of buffer addr */ + u8 buf_base; /* upper 8 bits of buffer addr */ + u8 pad1; + u16 length; /* length of buffer */ + u8 status; /* status of buffer */ + u8 pad2; +} SCADESC, *PSCADESC; + +typedef struct _SCADESC_EX +{ + /* device driver bookkeeping section */ + char *virt_addr; /* virtual address of data buffer */ + u16 phys_entry; /* lower 16-bits of physical address of this descriptor */ +} SCADESC_EX, *PSCADESC_EX; + +/* The queue of BH actions to be performed */ + +#define BH_RECEIVE 1 +#define BH_TRANSMIT 2 +#define BH_STATUS 4 + +#define IO_PIN_SHUTDOWN_LIMIT 100 + +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +struct _input_signal_events { + int ri_up; + int ri_down; + int dsr_up; + int dsr_down; + int dcd_up; + int dcd_down; + int cts_up; + int cts_down; +}; + +/* + * Device instance data structure + */ +typedef struct _synclinkmp_info { + void *if_ptr; /* General purpose pointer (used by SPPP) */ + int magic; + int flags; + int count; /* count of opens */ + int line; + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + + struct mgsl_icount icount; + + struct termios normal_termios; + struct termios callout_termios; + + struct tty_struct *tty; + int timeout; + int x_char; /* xon/xoff character */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + u16 read_status_mask1; /* break detection (SR1 indications) */ + u16 read_status_mask2; /* parity/framing/overun (SR2 indications) */ + unsigned char ignore_status_mask1; /* break detection (SR1 indications) */ + unsigned char ignore_status_mask2; /* parity/framing/overun (SR2 indications) */ + unsigned char *tx_buf; + int tx_put; + int tx_get; + int tx_count; + + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + + wait_queue_head_t status_event_wait_q; + wait_queue_head_t event_wait_q; + struct timer_list tx_timer; /* HDLC transmit timeout timer */ + struct _synclinkmp_info *next_device; /* device list link */ + struct timer_list status_timer; /* input signal status check timer */ + + spinlock_t lock; /* spinlock for synchronizing with ISR */ + struct tq_struct task; /* task structure for scheduling bh */ + + u32 max_frame_size; /* as set by device config */ + + u32 pending_bh; + + int bh_running; /* Protection from multiple */ + int isr_overflow; + int bh_requested; + + int dcd_chkcount; /* check counts to prevent */ + int cts_chkcount; /* too many IRQs if a signal */ + int dsr_chkcount; /* is floating */ + int ri_chkcount; + + char *buffer_list; /* virtual address of Rx & Tx buffer lists */ + unsigned long buffer_list_phys; + + unsigned int rx_buf_count; /* count of total allocated Rx buffers */ + SCADESC *rx_buf_list; /* list of receive buffer entries */ + SCADESC_EX rx_buf_list_ex[SCAMAXDESC]; /* list of receive buffer entries */ + unsigned int current_rx_buf; + + unsigned int tx_buf_count; /* count of total allocated Tx buffers */ + SCADESC *tx_buf_list; /* list of transmit buffer entries */ + SCADESC_EX tx_buf_list_ex[SCAMAXDESC]; /* list of transmit buffer entries */ + unsigned int last_tx_buf; + + unsigned char *tmp_rx_buf; + unsigned int tmp_rx_buf_count; + + int rx_enabled; + int rx_overflow; + + int tx_enabled; + int tx_active; + u32 idle_mode; + + unsigned char ie0_value; + unsigned char ie1_value; + unsigned char ie2_value; + unsigned char ctrlreg_value; + unsigned char old_signals; + + char device_name[25]; /* device instance name */ + + int port_count; + int adapter_num; + int port_num; + + struct _synclinkmp_info *port_array[SCA_MAX_PORTS]; + + unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */ + + unsigned int irq_level; /* interrupt level */ + unsigned long irq_flags; + int irq_requested; /* nonzero if IRQ requested */ + + MGSL_PARAMS params; /* communications parameters */ + + unsigned char serial_signals; /* current serial signal states */ + + int irq_occurred; /* for diagnostics use */ + unsigned int init_error; /* Initialization startup error */ + + u32 last_mem_alloc; + unsigned char* memory_base; /* shared memory address (PCI only) */ + u32 phys_memory_base; + int shared_mem_requested; + + unsigned char* sca_base; /* HD64570 SCA Memory address */ + u32 phys_sca_base; + u32 sca_offset; + int sca_base_requested; + + unsigned char* lcr_base; /* local config registers (PCI only) */ + u32 phys_lcr_base; + u32 lcr_offset; + int lcr_mem_requested; + + unsigned char* statctrl_base; /* status/control register memory */ + u32 phys_statctrl_base; + u32 statctrl_offset; + int sca_statctrl_requested; + + u32 misc_ctrl_value; + char flag_buf[MAX_ASYNC_BUFFER_SIZE]; + char char_buf[MAX_ASYNC_BUFFER_SIZE]; + BOOLEAN drop_rts_on_tx_done; + + struct _input_signal_events input_signal_events; + + /* SPPP/Cisco HDLC device parts */ + int netcount; + int dosyncppp; + spinlock_t netlock; +#ifdef CONFIG_SYNCLINK_SYNCPPP + struct ppp_device pppdev; + char netname[10]; + struct net_device *netdev; + struct net_device_stats netstats; + struct net_device netdevice; +#endif +} SLMP_INFO; + +#define MGSL_MAGIC 0x5401 + +/* + * define serial signal status change macros + */ +#define MISCSTATUS_DCD_LATCHED (SerialSignal_DCD<<8) /* indicates change in DCD */ +#define MISCSTATUS_RI_LATCHED (SerialSignal_RI<<8) /* indicates change in RI */ +#define MISCSTATUS_CTS_LATCHED (SerialSignal_CTS<<8) /* indicates change in CTS */ +#define MISCSTATUS_DSR_LATCHED (SerialSignal_DSR<<8) /* change in DSR */ + +/* Common Register macros */ +#define LPR 0x00 +#define PABR0 0x02 +#define PABR1 0x03 +#define WCRL 0x04 +#define WCRM 0x05 +#define WCRH 0x06 +#define DPCR 0x08 +#define DMER 0x09 +#define ISR0 0x10 +#define ISR1 0x11 +#define ISR2 0x12 +#define IER0 0x14 +#define IER1 0x15 +#define IER2 0x16 +#define ITCR 0x18 +#define INTVR 0x1a +#define IMVR 0x1c + +/* MSCI Register macros */ +#define TRB 0x20 +#define TRBL 0x20 +#define TRBH 0x21 +#define SR0 0x22 +#define SR1 0x23 +#define SR2 0x24 +#define SR3 0x25 +#define FST 0x26 +#define IE0 0x28 +#define IE1 0x29 +#define IE2 0x2a +#define FIE 0x2b +#define CMD 0x2c +#define MD0 0x2e +#define MD1 0x2f +#define MD2 0x30 +#define CTL 0x31 +#define SA0 0x32 +#define SA1 0x33 +#define IDL 0x34 +#define TMC 0x35 +#define RXS 0x36 +#define TXS 0x37 +#define TRC0 0x38 +#define TRC1 0x39 +#define RRC 0x3a +#define CST0 0x3c +#define CST1 0x3d + +/* Timer Register Macros */ +#define TCNT 0x60 +#define TCNTL 0x60 +#define TCNTH 0x61 +#define TCONR 0x62 +#define TCONRL 0x62 +#define TCONRH 0x63 +#define TMCS 0x64 +#define TEPR 0x65 + +/* DMA Controller Register macros */ +#define DAR 0x80 +#define DARL 0x80 +#define DARH 0x81 +#define DARB 0x82 +#define BAR 0x80 +#define BARL 0x80 +#define BARH 0x81 +#define BARB 0x82 +#define SAR 0x84 +#define SARL 0x84 +#define SARH 0x85 +#define SARB 0x86 +#define CPB 0x86 +#define CDA 0x88 +#define CDAL 0x88 +#define CDAH 0x89 +#define EDA 0x8a +#define EDAL 0x8a +#define EDAH 0x8b +#define BFL 0x8c +#define BFLL 0x8c +#define BFLH 0x8d +#define BCR 0x8e +#define BCRL 0x8e +#define BCRH 0x8f +#define DSR 0x90 +#define DMR 0x91 +#define FCT 0x93 +#define DIR 0x94 +#define DCMD 0x95 + +/* combine with timer or DMA register address */ +#define TIMER0 0x00 +#define TIMER1 0x08 +#define TIMER2 0x10 +#define TIMER3 0x18 +#define RXDMA 0x00 +#define TXDMA 0x20 + +/* SCA Command Codes */ +#define NOOP 0x00 +#define TXRESET 0x01 +#define TXENABLE 0x02 +#define TXDISABLE 0x03 +#define TXCRCINIT 0x04 +#define TXCRCEXCL 0x05 +#define TXEOM 0x06 +#define TXABORT 0x07 +#define MPON 0x08 +#define TXBUFCLR 0x09 +#define RXRESET 0x11 +#define RXENABLE 0x12 +#define RXDISABLE 0x13 +#define RXCRCINIT 0x14 +#define RXREJECT 0x15 +#define SEARCHMP 0x16 +#define RXCRCEXCL 0x17 +#define RXCRCCALC 0x18 +#define CHRESET 0x21 +#define HUNT 0x31 + +/* DMA command codes */ +#define SWABORT 0x01 +#define FEICLEAR 0x02 + +/* IE0 */ +#define TXINTE BIT7 +#define RXINTE BIT6 +#define TXRDYE BIT1 +#define RXRDYE BIT0 + +/* IE1 & SR1 */ +#define UDRN BIT7 +#define IDLE BIT6 +#define SYNCD BIT4 +#define FLGD BIT4 +#define CCTS BIT3 +#define CDCD BIT2 +#define BRKD BIT1 +#define ABTD BIT1 +#define GAPD BIT1 +#define BRKE BIT0 +#define IDLD BIT0 + +/* IE2 & SR2 */ +#define EOM BIT7 +#define PMP BIT6 +#define SHRT BIT6 +#define PE BIT5 +#define ABT BIT5 +#define FRME BIT4 +#define RBIT BIT4 +#define OVRN BIT3 +#define CRCE BIT2 + + +#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) + +/* + * Global linked list of SyncLink devices + */ +static SLMP_INFO *synclinkmp_device_list = NULL; +static int synclinkmp_adapter_count = -1; +static int synclinkmp_device_count = 0; + +/* + * Set this param to non-zero to load eax with the + * .text section address and breakpoint on module load. + * This is useful for use with gdb and add-symbol-file command. + */ +static int break_on_load=0; + +/* + * Driver major number, defaults to zero to get auto + * assigned major number. May be forced as module parameter. + */ +static int ttymajor=0; +int cuamajor=0; + +/* + * Array of user specified options for ISA adapters. + */ +static int debug_level = 0; +static int maxframe[MAX_DEVICES] = {0,}; +static int dosyncppp[MAX_DEVICES] = {0,}; + +MODULE_PARM(break_on_load,"i"); +MODULE_PARM(ttymajor,"i"); +MODULE_PARM(cuamajor,"i"); +MODULE_PARM(debug_level,"i"); +MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i"); +MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i"); + +static char *driver_name = "SyncLink MultiPort driver"; +static char *driver_version = "$Revision: 3.17 $"; + +static int __init synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); +static void __exit synclinkmp_remove_one(struct pci_dev *dev); + +static struct pci_device_id synclinkmp_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, synclinkmp_pci_tbl); + +static struct pci_driver synclinkmp_pci_driver = { + name: "synclinkmp", + id_table: synclinkmp_pci_tbl, + probe: synclinkmp_init_one, + remove: synclinkmp_remove_one, +}; + + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +static struct tty_struct *serial_table[MAX_DEVICES]; +static struct termios *serial_termios[MAX_DEVICES]; +static struct termios *serial_termios_locked[MAX_DEVICES]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +/* tty callbacks */ + +static int open(struct tty_struct *tty, struct file * filp); +static void close(struct tty_struct *tty, struct file * filp); +static void hangup(struct tty_struct *tty); +static void set_termios(struct tty_struct *tty, struct termios *old_termios); + +static int write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static void put_char(struct tty_struct *tty, unsigned char ch); +static void send_xchar(struct tty_struct *tty, char ch); +static void wait_until_sent(struct tty_struct *tty, int timeout); +static int write_room(struct tty_struct *tty); +static void flush_chars(struct tty_struct *tty); +static void flush_buffer(struct tty_struct *tty); +static void tx_hold(struct tty_struct *tty); +static void tx_release(struct tty_struct *tty); + +static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); +static int read_proc(char *page, char **start, off_t off, int count,int *eof, void *data); +static int chars_in_buffer(struct tty_struct *tty); +static void throttle(struct tty_struct * tty); +static void unthrottle(struct tty_struct * tty); +static void set_break(struct tty_struct *tty, int break_state); + +/* sppp support and callbacks */ + +#ifdef CONFIG_SYNCLINK_SYNCPPP +static void sppp_init(SLMP_INFO *info); +static void sppp_delete(SLMP_INFO *info); +static void sppp_rx_done(SLMP_INFO *info, char *buf, int size); +static void sppp_tx_done(SLMP_INFO *info); + +static int sppp_cb_open(struct net_device *d); +static int sppp_cb_close(struct net_device *d); +static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int sppp_cb_tx(struct sk_buff *skb, struct net_device *dev); +static void sppp_cb_tx_timeout(struct net_device *dev); +static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev); +#endif + +/* ioctl handlers */ + +static int get_stats(SLMP_INFO *info, struct mgsl_icount *user_icount); +static int get_params(SLMP_INFO *info, MGSL_PARAMS *params); +static int set_params(SLMP_INFO *info, MGSL_PARAMS *params); +static int get_txidle(SLMP_INFO *info, int*idle_mode); +static int set_txidle(SLMP_INFO *info, int idle_mode); +static int tx_enable(SLMP_INFO *info, int enable); +static int tx_abort(SLMP_INFO *info); +static int rx_enable(SLMP_INFO *info, int enable); +static int map_status(int signals); +static int modem_input_wait(SLMP_INFO *info,int arg); +static int wait_mgsl_event(SLMP_INFO *info, int *mask_ptr); +static int get_modem_info(SLMP_INFO *info, unsigned int *value); +static int set_modem_info(SLMP_INFO *info, unsigned int cmd,unsigned int *value); +static void set_break(struct tty_struct *tty, int break_state); + +static void add_device(SLMP_INFO *info); +static void device_init(int adapter_num, struct pci_dev *pdev); +static int claim_resources(SLMP_INFO *info); +static void release_resources(SLMP_INFO *info); + +static int startup(SLMP_INFO *info); +static int block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info); +static void shutdown(SLMP_INFO *info); +static void program_hw(SLMP_INFO *info); +static void change_params(SLMP_INFO *info); + +static int init_adapter(SLMP_INFO *info); +static int register_test(SLMP_INFO *info); +static int irq_test(SLMP_INFO *info); +static int loopback_test(SLMP_INFO *info); +static int adapter_test(SLMP_INFO *info); +static int memory_test(SLMP_INFO *info); + +static void reset_adapter(SLMP_INFO *info); +static void reset_port(SLMP_INFO *info); +static void async_mode(SLMP_INFO *info); +static void hdlc_mode(SLMP_INFO *info); + +static void rx_stop(SLMP_INFO *info); +static void rx_start(SLMP_INFO *info); +static void rx_reset_buffers(SLMP_INFO *info); +static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last); +static int rx_get_frame(SLMP_INFO *info); + +static void tx_start(SLMP_INFO *info); +static void tx_stop(SLMP_INFO *info); +static void tx_load_fifo(SLMP_INFO *info); +static void tx_set_idle(SLMP_INFO *info); +static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count); + +static void get_signals(SLMP_INFO *info); +static void set_signals(SLMP_INFO *info); +static void enable_loopback(SLMP_INFO *info, int enable); +static void set_rate(SLMP_INFO *info, u32 data_rate); + +static int bh_action(SLMP_INFO *info); +static void bh_handler(void* Context); +static void bh_receive(SLMP_INFO *info); +static void bh_transmit(SLMP_INFO *info); +static void bh_status(SLMP_INFO *info); +static void isr_timer(SLMP_INFO *info); +static void isr_rxint(SLMP_INFO *info); +static void isr_rxrdy(SLMP_INFO *info); +static void isr_txint(SLMP_INFO *info); +static void isr_txrdy(SLMP_INFO *info); +static void isr_rxdmaok(SLMP_INFO *info); +static void isr_rxdmaerror(SLMP_INFO *info); +static void isr_txdmaok(SLMP_INFO *info); +static void isr_txdmaerror(SLMP_INFO *info); +static void isr_io_pin(SLMP_INFO *info, u16 status); +static void synclinkmp_interrupt(int irq, void *dev_id, struct pt_regs * regs); + +static int alloc_dma_bufs(SLMP_INFO *info); +static void free_dma_bufs(SLMP_INFO *info); +static int alloc_buf_list(SLMP_INFO *info); +static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *list, SCADESC_EX *list_ex,int count); +static int alloc_tmp_rx_buf(SLMP_INFO *info); +static void free_tmp_rx_buf(SLMP_INFO *info); + +static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count); +static void trace_block(SLMP_INFO *info, const char* data, int count, int xmit); +static void tx_timeout(unsigned long context); +static void status_timeout(unsigned long context); + +static unsigned char read_reg(SLMP_INFO *info, unsigned char addr); +static void write_reg(SLMP_INFO *info, unsigned char addr, unsigned char val); +static u16 read_reg16(SLMP_INFO *info, unsigned char addr); +static void write_reg16(SLMP_INFO *info, unsigned char addr, u16 val); +static unsigned char read_status_reg(SLMP_INFO * info); +static void write_control_reg(SLMP_INFO * info); + + +static unsigned char rx_active_fifo_level = 16; // rx request FIFO activation level in bytes +static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation level in bytes +static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes + +static u32 misc_ctrl_value = 0x007e4040; +static u32 lcr1_brdr_value = 0x0080002d; + +static u32 read_ahead_count = 8; + +/* DPCR, DMA Priority Control + * + * 07..05 Not used, must be 0 + * 04 BRC, bus release condition: 0=all transfers complete + * 1=release after 1 xfer on all channels + * 03 CCC, channel change condition: 0=every cycle + * 1=after each channel completes all xfers + * 02..00 PR<2..0>, priority 100=round robin + * + * 00000100 = 0x00 + */ +static unsigned char dma_priority = 0x04; + +// Number of bytes that can be written to shared RAM +// in a single write operation +static u32 sca_pci_load_interval = 64; + +/* + * 1st function defined in .text section. Calling this function in + * init_module() followed by a breakpoint allows a remote debugger + * (gdb) to get the .text address for the add-symbol-file command. + * This allows remote debugging of dynamically loadable modules. + */ +static void* synclinkmp_get_text_ptr(void); +static void* synclinkmp_get_text_ptr() {return synclinkmp_get_text_ptr;} + +static inline int sanity_check(SLMP_INFO *info, + kdev_t device, const char *routine) +{ +#ifdef SANITY_CHECK + static const char *badmagic = + "Warning: bad magic number for synclinkmp_struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null synclinkmp_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != MGSL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +/* tty callbacks */ + +/* Called when a port is opened. Init and enable port. + */ +static int open(struct tty_struct *tty, struct file *filp) +{ + SLMP_INFO *info; + int retval, line; + unsigned long flags; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= synclinkmp_device_count)) { + printk("%s(%d): open with illegal line #%d.\n", + __FILE__,__LINE__,line); + return -ENODEV; + } + + info = synclinkmp_device_list; + while(info && info->line != line) + info = info->next_device; + if ( !info ){ + printk("%s(%d):%s Can't find specified device on open (line=%d)\n", + __FILE__,__LINE__,info->device_name,line); + return -ENODEV; + } + + if ( info->init_error ) { + printk("%s(%d):%s device is not allocated, init error=%d\n", + __FILE__,__LINE__,info->device_name,info->init_error); + return -ENODEV; + } + + tty->driver_data = info; + info->tty = tty; + if (sanity_check(info, tty->device, "open")) + return -ENODEV; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s open(), old ref count = %d\n", + __FILE__,__LINE__,tty->driver.name, info->count); + + MOD_INC_USE_COUNT; + + /* If port is closing, signal caller to try again */ + if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + retval = ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); + goto cleanup; + } + + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + spin_lock_irqsave(&info->netlock, flags); + if (info->netcount) { + retval = -EBUSY; + spin_unlock_irqrestore(&info->netlock, flags); + goto cleanup; + } + info->count++; + spin_unlock_irqrestore(&info->netlock, flags); + + if (info->count == 1) { + /* 1st open on this device, init hardware */ + retval = startup(info); + if (retval < 0) + goto cleanup; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s block_til_ready() returned %d\n", + __FILE__,__LINE__, info->device_name, retval); + goto cleanup; + } + + if ((info->count == 1) && + info->flags & ASYNC_SPLIT_TERMIOS) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + change_params(info); + } + + info->session = current->session; + info->pgrp = current->pgrp; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s open() success\n", + __FILE__,__LINE__, info->device_name); + retval = 0; + +cleanup: + if (retval) { + if(MOD_IN_USE) + MOD_DEC_USE_COUNT; + if(info->count) + info->count--; + } + + return retval; +} + +/* Called when port is closed. Wait for remaining data to be + * sent. Disable port and free resources. + */ +static void close(struct tty_struct *tty, struct file *filp) +{ + SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; + + if (!info || sanity_check(info, tty->device, "close")) + return; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s close() entry, count=%d\n", + __FILE__,__LINE__, info->device_name, info->count); + + if (!info->count || tty_hung_up_p(filp)) + goto cleanup; + + if ((tty->count == 1) && (info->count != 1)) { + /* + * tty->count is 1 and the tty structure will be freed. + * info->count should be one in this case. + * if it's not, correct it so that the port is shutdown. + */ + printk("%s(%d):%s close: bad refcount; tty->count is 1, " + "info->count is %d\n", + __FILE__,__LINE__, info->device_name, info->count); + info->count = 1; + } + + info->count--; + + /* if at least one open remaining, leave hardware active */ + if (info->count) + goto cleanup; + + info->flags |= ASYNC_CLOSING; + + /* Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + + /* set tty->closing to notify line discipline to + * only process XON/XOFF characters. Only the N_TTY + * discipline appears to use this (ppp does not). + */ + tty->closing = 1; + + /* wait for transmit data to clear all layers */ + + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s close() calling tty_wait_until_sent\n", + __FILE__,__LINE__, info->device_name ); + tty_wait_until_sent(tty, info->closing_wait); + } + + if (info->flags & ASYNC_INITIALIZED) + wait_until_sent(tty, info->timeout); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + shutdown(info); + + tty->closing = 0; + info->tty = 0; + + if (info->blocked_open) { + if (info->close_delay) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + + wake_up_interruptible(&info->close_wait); + +cleanup: + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__, + tty->driver.name, info->count); + if(MOD_IN_USE) + MOD_DEC_USE_COUNT; +} + +/* Called by tty_hangup() when a hangup is signaled. + * This is the same as closing all open descriptors for the port. + */ +static void hangup(struct tty_struct *tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s hangup()\n", + __FILE__,__LINE__, info->device_name ); + + if (sanity_check(info, tty->device, "hangup")) + return; + + flush_buffer(tty); + shutdown(info); + + info->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + + wake_up_interruptible(&info->open_wait); +} + +/* Set new termios settings + */ +static void set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__, + tty->driver.name ); + + /* just return if nothing has changed */ + if ((tty->termios->c_cflag == old_termios->c_cflag) + && (RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_params(info); + + /* Handle transition to B0 status */ + if (old_termios->c_cflag & CBAUD && + !(tty->termios->c_cflag & CBAUD)) { + info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + tty->termios->c_cflag & CBAUD) { + info->serial_signals |= SerialSignal_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->serial_signals |= SerialSignal_RTS; + } + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + /* Handle turning off CRTSCTS */ + if (old_termios->c_cflag & CRTSCTS && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + tx_release(tty); + } +} + +/* Send a block of data + * + * Arguments: + * + * tty pointer to tty information structure + * from_user flag: 1 = from user process + * buf pointer to buffer containing send data + * count size of send data in bytes + * + * Return Value: number of characters written + */ +static int write(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0, err; + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s write() count=%d\n", + __FILE__,__LINE__,info->device_name,count); + + if (sanity_check(info, tty->device, "write")) + goto cleanup; + + if (!tty || !info->tx_buf) + goto cleanup; + + if (info->params.mode == MGSL_MODE_HDLC) { + if (count > info->max_frame_size) { + ret = -EIO; + goto cleanup; + } + if (info->tx_active) + goto cleanup; + if (info->tx_count) { + /* send accumulated data from send_char() calls */ + /* as frame and wait before accepting more data. */ + tx_load_dma_buffer(info, info->tx_buf, info->tx_count); + goto start; + } + if (!from_user) { + ret = info->tx_count = count; + tx_load_dma_buffer(info, buf, count); + goto start; + } + } + + for (;;) { + c = MIN(count, + MIN(info->max_frame_size - info->tx_count - 1, + info->max_frame_size - info->tx_put)); + if (c <= 0) + break; + + if (from_user) { + COPY_FROM_USER(err, info->tx_buf + info->tx_put, buf, c); + if (err) { + if (!ret) + ret = -EFAULT; + break; + } + } else + memcpy(info->tx_buf + info->tx_put, buf, c); + + spin_lock_irqsave(&info->lock,flags); + info->tx_put += c; + if (info->tx_put >= info->max_frame_size) + info->tx_put -= info->max_frame_size; + info->tx_count += c; + spin_unlock_irqrestore(&info->lock,flags); + + buf += c; + count -= c; + ret += c; + } + + if (info->params.mode == MGSL_MODE_HDLC) { + if (count) { + ret = info->tx_count = 0; + goto cleanup; + } + tx_load_dma_buffer(info, info->tx_buf, info->tx_count); + } +start: + if (info->tx_count && !tty->stopped && !tty->hw_stopped) { + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } + +cleanup: + if (debug_level >= DEBUG_LEVEL_INFO) + printk( "%s(%d):%s write() returning=%d\n", + __FILE__,__LINE__,info->device_name,ret); + return ret; +} + +/* Add a character to the transmit buffer. + */ +static void put_char(struct tty_struct *tty, unsigned char ch) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if ( debug_level >= DEBUG_LEVEL_INFO ) { + printk( "%s(%d):%s put_char(%d)\n", + __FILE__,__LINE__,info->device_name,ch); + } + + if (sanity_check(info, tty->device, "put_char")) + return; + + if (!tty || !info->tx_buf) + return; + + spin_lock_irqsave(&info->lock,flags); + + if ( (info->params.mode != MGSL_MODE_HDLC) || + !info->tx_active ) { + + if (info->tx_count < info->max_frame_size - 1) { + info->tx_buf[info->tx_put++] = ch; + if (info->tx_put >= info->max_frame_size) + info->tx_put -= info->max_frame_size; + info->tx_count++; + } + } + + spin_unlock_irqrestore(&info->lock,flags); +} + +/* Send a high-priority XON/XOFF character + */ +static void send_xchar(struct tty_struct *tty, char ch) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s send_xchar(%d)\n", + __FILE__,__LINE__, info->device_name, ch ); + + if (sanity_check(info, tty->device, "send_xchar")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_enabled) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +/* Wait until the transmitter is empty. + */ +static void wait_until_sent(struct tty_struct *tty, int timeout) +{ + SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; + unsigned long orig_jiffies, char_time; + + if (!info ) + return; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s wait_until_sent() entry\n", + __FILE__,__LINE__, info->device_name ); + + if (sanity_check(info, tty->device, "wait_until_sent")) + return; + + if (!(info->flags & ASYNC_INITIALIZED)) + goto exit; + + orig_jiffies = jiffies; + + /* Set check interval to 1/5 of estimated time to + * send a character, and make it at least 1. The check + * interval should also be less than the timeout. + * Note: use tight timings here to satisfy the NIST-PCTS. + */ + + if ( info->params.data_rate ) { + char_time = info->timeout/(32 * 5); + if (!char_time) + char_time++; + } else + char_time = 1; + + if (timeout) + char_time = MIN(char_time, timeout); + + if ( info->params.mode == MGSL_MODE_HDLC ) { + while (info->tx_active) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && ((orig_jiffies + timeout) < jiffies)) + break; + } + } else { + //TODO: determine if there is something similar to USC16C32 + // TXSTATUS_ALL_SENT status + while ( info->tx_active && info->tx_enabled) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && ((orig_jiffies + timeout) < jiffies)) + break; + } + } + +exit: + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s wait_until_sent() exit\n", + __FILE__,__LINE__, info->device_name ); +} + +/* Return the count of free bytes in transmit buffer + */ +static int write_room(struct tty_struct *tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + int ret; + + if (sanity_check(info, tty->device, "write_room")) + return 0; + + if (info->params.mode == MGSL_MODE_HDLC) { + ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; + } else { + ret = info->max_frame_size - info->tx_count - 1; + if (ret < 0) + ret = 0; + } + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s write_room()=%d\n", + __FILE__, __LINE__, info->device_name, ret); + + return ret; +} + +/* enable transmitter and send remaining buffered characters + */ +static void flush_chars(struct tty_struct *tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s flush_chars() entry tx_count=%d\n", + __FILE__,__LINE__,info->device_name,info->tx_count); + + if (sanity_check(info, tty->device, "flush_chars")) + return; + + if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped || + !info->tx_buf) + return; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s flush_chars() entry, starting transmitter\n", + __FILE__,__LINE__,info->device_name ); + + spin_lock_irqsave(&info->lock,flags); + + if (!info->tx_active) { + if ( (info->params.mode == MGSL_MODE_HDLC) && + info->tx_count ) { + /* operating in synchronous (frame oriented) mode */ + /* copy data from circular tx_buf to */ + /* transmit DMA buffer. */ + tx_load_dma_buffer(info, + info->tx_buf,info->tx_count); + } + tx_start(info); + } + + spin_unlock_irqrestore(&info->lock,flags); +} + +/* Discard all data in the send buffer + */ +static void flush_buffer(struct tty_struct *tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s flush_buffer() entry\n", + __FILE__,__LINE__, info->device_name ); + + if (sanity_check(info, tty->device, "flush_buffer")) + return; + + spin_lock_irqsave(&info->lock,flags); + info->tx_count = info->tx_put = info->tx_get = 0; + del_timer(&info->tx_timer); + spin_unlock_irqrestore(&info->lock,flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* throttle (stop) transmitter + */ +static void tx_hold(struct tty_struct *tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->device, "tx_hold")) + return; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s(%d):%s tx_hold()\n", + __FILE__,__LINE__,info->device_name); + + spin_lock_irqsave(&info->lock,flags); + if (info->tx_enabled) + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); +} + +/* release (start) transmitter + */ +static void tx_release(struct tty_struct *tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (sanity_check(info, tty->device, "tx_release")) + return; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s(%d):%s tx_release()\n", + __FILE__,__LINE__,info->device_name); + + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_enabled) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); +} + +/* Service an IOCTL request + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to associated file object for device + * cmd IOCTL command code + * arg command argument/context + * + * Return Value: 0 if success, otherwise error code + */ +static int ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + int error; + struct mgsl_icount cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s ioctl() cmd=%08X\n", __FILE__,__LINE__, + info->device_name, cmd ); + + if (sanity_check(info, tty->device, "ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case MGSL_IOCGPARAMS: + return get_params(info,(MGSL_PARAMS *)arg); + case MGSL_IOCSPARAMS: + return set_params(info,(MGSL_PARAMS *)arg); + case MGSL_IOCGTXIDLE: + return get_txidle(info,(int*)arg); + case MGSL_IOCSTXIDLE: + return set_txidle(info,(int)arg); + case MGSL_IOCTXENABLE: + return tx_enable(info,(int)arg); + case MGSL_IOCRXENABLE: + return rx_enable(info,(int)arg); + case MGSL_IOCTXABORT: + return tx_abort(info); + case MGSL_IOCGSTATS: + return get_stats(info,(struct mgsl_icount*)arg); + case MGSL_IOCWAITEVENT: + return wait_mgsl_event(info,(int*)arg); + case MGSL_IOCLOOPTXDONE: + return 0; // TODO: Not supported, need to document + case MGSL_IOCCLRMODCOUNT: + while(MOD_IN_USE) + MOD_DEC_USE_COUNT; + return 0; + /* Wait for modem input (DCD,RI,DSR,CTS) change + * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) + */ + case TIOCMIWAIT: + return modem_input_wait(info,(int)arg); + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + spin_unlock_irqrestore(&info->lock,flags); + p_cuser = (struct serial_icounter_struct *) arg; + PUT_USER(error,cnow.cts, &p_cuser->cts); + if (error) return error; + PUT_USER(error,cnow.dsr, &p_cuser->dsr); + if (error) return error; + PUT_USER(error,cnow.rng, &p_cuser->rng); + if (error) return error; + PUT_USER(error,cnow.dcd, &p_cuser->dcd); + if (error) return error; + PUT_USER(error,cnow.rx, &p_cuser->rx); + if (error) return error; + PUT_USER(error,cnow.tx, &p_cuser->tx); + if (error) return error; + PUT_USER(error,cnow.frame, &p_cuser->frame); + if (error) return error; + PUT_USER(error,cnow.overrun, &p_cuser->overrun); + if (error) return error; + PUT_USER(error,cnow.parity, &p_cuser->parity); + if (error) return error; + PUT_USER(error,cnow.brk, &p_cuser->brk); + if (error) return error; + PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun); + if (error) return error; + return 0; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, SLMP_INFO *info) +{ + char stat_buf[30]; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n" + "\tIRQ=%d MaxFrameSize=%u\n", + info->device_name, + info->phys_sca_base, + info->phys_memory_base, + info->phys_statctrl_base, + info->phys_lcr_base, + info->irq_level, + info->max_frame_size ); + + /* output current serial signal states */ + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (info->serial_signals & SerialSignal_RTS) + strcat(stat_buf, "|RTS"); + if (info->serial_signals & SerialSignal_CTS) + strcat(stat_buf, "|CTS"); + if (info->serial_signals & SerialSignal_DTR) + strcat(stat_buf, "|DTR"); + if (info->serial_signals & SerialSignal_DSR) + strcat(stat_buf, "|DSR"); + if (info->serial_signals & SerialSignal_DCD) + strcat(stat_buf, "|CD"); + if (info->serial_signals & SerialSignal_RI) + strcat(stat_buf, "|RI"); + + if (info->params.mode == MGSL_MODE_HDLC) { + ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d", + info->icount.txok, info->icount.rxok); + if (info->icount.txunder) + ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); + if (info->icount.txabort) + ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); + if (info->icount.rxshort) + ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); + if (info->icount.rxlong) + ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); + if (info->icount.rxover) + ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); + if (info->icount.rxcrc) + ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc); + } else { + ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d", + info->icount.tx, info->icount.rx); + if (info->icount.frame) + ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + if (info->icount.parity) + ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + if (info->icount.brk) + ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + if (info->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + } + + /* Append serial signal status to end */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + + ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", + info->tx_active,info->bh_requested,info->bh_running, + info->pending_bh); + + return ret; +} + +/* Called to print information about devices + */ +int read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0, l; + off_t begin = 0; + SLMP_INFO *info; + + len += sprintf(page, "synclinkmp driver:%s\n", driver_version); + + info = synclinkmp_device_list; + while( info ) { + l = line_info(page + len, info); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + info = info->next_device; + } + + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* Return the count of bytes in transmit buffer + */ +static int chars_in_buffer(struct tty_struct *tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + + if (sanity_check(info, tty->device, "chars_in_buffer")) + return 0; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s chars_in_buffer()=%d\n", + __FILE__, __LINE__, info->device_name, info->tx_count); + + return info->tx_count; +} + +/* Signal remote device to throttle send data (our receive data) + */ +static void throttle(struct tty_struct * tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s throttle() entry\n", + __FILE__,__LINE__, info->device_name ); + + if (sanity_check(info, tty->device, "throttle")) + return; + + if (I_IXOFF(tty)) + send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) { + spin_lock_irqsave(&info->lock,flags); + info->serial_signals &= ~SerialSignal_RTS; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +/* Signal remote device to stop throttling send data (our receive data) + */ +static void unthrottle(struct tty_struct * tty) +{ + SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s unthrottle() entry\n", + __FILE__,__LINE__, info->device_name ); + + if (sanity_check(info, tty->device, "unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + send_xchar(tty, START_CHAR(tty)); + } + + if (tty->termios->c_cflag & CRTSCTS) { + spin_lock_irqsave(&info->lock,flags); + info->serial_signals |= SerialSignal_RTS; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } +} + +/* set or clear transmit break condition + * break_state -1=set break condition, 0=clear + */ +static void set_break(struct tty_struct *tty, int break_state) +{ + unsigned char RegValue; + SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s set_break(%d)\n", + __FILE__,__LINE__, info->device_name, break_state); + + if (sanity_check(info, tty->device, "set_break")) + return; + + spin_lock_irqsave(&info->lock,flags); + RegValue = read_reg(info, CTL); + if (break_state == -1) + RegValue |= BIT3; + else + RegValue &= ~BIT3; + write_reg(info, CTL, RegValue); + spin_unlock_irqrestore(&info->lock,flags); +} + +#ifdef CONFIG_SYNCLINK_SYNCPPP + +/* syncppp support and callbacks */ + +static void sppp_init(SLMP_INFO *info) +{ + struct net_device *d; + + sprintf(info->netname,"mgslm%dp%d",info->adapter_num,info->port_num); + + info->if_ptr = &info->pppdev; + info->netdev = info->pppdev.dev = &info->netdevice; + + sppp_attach(&info->pppdev); + + d = info->netdev; + strcpy(d->name,info->netname); + d->base_addr = 0; + d->irq = info->irq_level; + d->dma = 0; + d->priv = info; + d->init = NULL; + d->open = sppp_cb_open; + d->stop = sppp_cb_close; + d->hard_start_xmit = sppp_cb_tx; + d->do_ioctl = sppp_cb_ioctl; + d->get_stats = sppp_cb_net_stats; + d->tx_timeout = sppp_cb_tx_timeout; + d->watchdog_timeo = 10*HZ; + +#if LINUX_VERSION_CODE < VERSION(2,4,4) + dev_init_buffers(d); +#endif + + if (register_netdev(d) == -1) { + printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); + sppp_detach(info->netdev); + return; + } + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("sppp_init(%s)\n",info->netname); +} + +static void sppp_delete(SLMP_INFO *info) +{ + if (debug_level >= DEBUG_LEVEL_INFO) + printk("sppp_delete(%s)\n",info->netname); + sppp_detach(info->netdev); + unregister_netdev(info->netdev); +} + +static int sppp_cb_open(struct net_device *d) +{ + SLMP_INFO *info = d->priv; + int err, flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("sppp_cb_open(%s)\n",info->netname); + + spin_lock_irqsave(&info->netlock, flags); + if (info->count != 0 || info->netcount != 0) { + printk(KERN_WARNING "%s: sppp_cb_open returning busy\n", info->netname); + spin_unlock_irqrestore(&info->netlock, flags); + return -EBUSY; + } + info->netcount=1; + MOD_INC_USE_COUNT; + spin_unlock_irqrestore(&info->netlock, flags); + + /* claim resources and init adapter */ + if ((err = startup(info)) != 0) + goto open_fail; + + /* allow syncppp module to do open processing */ + if ((err = sppp_open(d)) != 0) { + shutdown(info); + goto open_fail; + } + + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + program_hw(info); + + d->trans_start = jiffies; + netif_start_queue(d); + return 0; + +open_fail: + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + MOD_DEC_USE_COUNT; + spin_unlock_irqrestore(&info->netlock, flags); + return err; +} + +static void sppp_cb_tx_timeout(struct net_device *dev) +{ + SLMP_INFO *info = dev->priv; + int flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("sppp_tx_timeout(%s)\n",info->netname); + + info->netstats.tx_errors++; + info->netstats.tx_aborted_errors++; + + spin_lock_irqsave(&info->lock,flags); + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); + + netif_wake_queue(dev); +} + +static int sppp_cb_tx(struct sk_buff *skb, struct net_device *dev) +{ + SLMP_INFO *info = dev->priv; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("sppp_tx(%s)\n",info->netname); + + netif_stop_queue(dev); + + info->tx_count = skb->len; + tx_load_dma_buffer(info, skb->data, skb->len); + info->netstats.tx_packets++; + info->netstats.tx_bytes += skb->len; + dev_kfree_skb(skb); + + dev->trans_start = jiffies; + + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + + return 0; +} + +static int sppp_cb_close(struct net_device *d) +{ + SLMP_INFO *info = d->priv; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("sppp_cb_close(%s)\n",info->netname); + + /* shutdown adapter and release resources */ + shutdown(info); + + /* allow syncppp to do close processing */ + sppp_close(d); + netif_stop_queue(d); + + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + MOD_DEC_USE_COUNT; + spin_unlock_irqrestore(&info->netlock, flags); + return 0; +} + +static void sppp_rx_done(SLMP_INFO *info, char *buf, int size) +{ + struct sk_buff *skb = dev_alloc_skb(size); + if (debug_level >= DEBUG_LEVEL_INFO) + printk("sppp_rx_done(%s)\n",info->netname); + if (skb == NULL) { + printk(KERN_NOTICE "%s: cant alloc skb, dropping packet\n", + info->netname); + info->netstats.rx_dropped++; + return; + } + + memcpy(skb_put(skb, size),buf,size); + + skb->protocol = htons(ETH_P_WAN_PPP); + skb->dev = info->netdev; + skb->mac.raw = skb->data; + info->netstats.rx_packets++; + info->netstats.rx_bytes += size; + netif_rx(skb); + info->netdev->trans_start = jiffies; +} + +static void sppp_tx_done(SLMP_INFO *info) +{ + if (netif_queue_stopped(info->netdev)) + netif_wake_queue(info->netdev); +} + +static struct net_device_stats *sppp_cb_net_stats(struct net_device *dev) +{ + SLMP_INFO *info = dev->priv; + if (debug_level >= DEBUG_LEVEL_INFO) + printk("net_stats(%s)\n",info->netname); + return &info->netstats; +} + +static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + SLMP_INFO *info = (SLMP_INFO *)dev->priv; + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):ioctl %s cmd=%08X\n", __FILE__,__LINE__, + info->netname, cmd ); + return sppp_do_ioctl(dev, ifr, cmd); +} + +#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */ + + +/* Return next bottom half action to perform. + * Return Value: BH action code or 0 if nothing to do. + */ +int bh_action(SLMP_INFO *info) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&info->lock,flags); + + if (info->pending_bh & BH_RECEIVE) { + info->pending_bh &= ~BH_RECEIVE; + rc = BH_RECEIVE; + } else if (info->pending_bh & BH_TRANSMIT) { + info->pending_bh &= ~BH_TRANSMIT; + rc = BH_TRANSMIT; + } else if (info->pending_bh & BH_STATUS) { + info->pending_bh &= ~BH_STATUS; + rc = BH_STATUS; + } + + if (!rc) { + /* Mark BH routine as complete */ + info->bh_running = 0; + info->bh_requested = 0; + } + + spin_unlock_irqrestore(&info->lock,flags); + + return rc; +} + +/* Perform bottom half processing of work items queued by ISR. + */ +void bh_handler(void* Context) +{ + SLMP_INFO *info = (SLMP_INFO*)Context; + int action; + + if (!info) + return; + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):%s bh_handler() entry\n", + __FILE__,__LINE__,info->device_name); + + info->bh_running = 1; + + while((action = bh_action(info)) != 0) { + + /* Process work item */ + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):%s bh_handler() work item action=%d\n", + __FILE__,__LINE__,info->device_name, action); + + switch (action) { + + case BH_RECEIVE: + bh_receive(info); + break; + case BH_TRANSMIT: + bh_transmit(info); + break; + case BH_STATUS: + bh_status(info); + break; + default: + /* unknown work item ID */ + printk("%s(%d):%s Unknown work item ID=%08X!\n", + __FILE__,__LINE__,info->device_name,action); + break; + } + } + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):%s bh_handler() exit\n", + __FILE__,__LINE__,info->device_name); +} + +void bh_receive(SLMP_INFO *info) +{ + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):%s bh_receive()\n", + __FILE__,__LINE__,info->device_name); + + while( rx_get_frame(info) ); +} + +void bh_transmit(SLMP_INFO *info) +{ + struct tty_struct *tty = info->tty; + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):%s bh_transmit() entry\n", + __FILE__,__LINE__,info->device_name); + + if (tty) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) { + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):%s calling ldisc.write_wakeup\n", + __FILE__,__LINE__,info->device_name); + (tty->ldisc.write_wakeup)(tty); + } + wake_up_interruptible(&tty->write_wait); + } +} + +void bh_status(SLMP_INFO *info) +{ + if ( debug_level >= DEBUG_LEVEL_BH ) + printk( "%s(%d):%s bh_status() entry\n", + __FILE__,__LINE__,info->device_name); + + info->ri_chkcount = 0; + info->dsr_chkcount = 0; + info->dcd_chkcount = 0; + info->cts_chkcount = 0; +} + +void isr_timer(SLMP_INFO * info) +{ + unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; + + /* IER2<7..4> = timer<3..0> interrupt enables (0=disabled) */ + write_reg(info, IER2, 0); + + /* TMCS, Timer Control/Status Register + * + * 07 CMF, Compare match flag (read only) 1=match + * 06 ECMI, CMF Interrupt Enable: 0=disabled + * 05 Reserved, must be 0 + * 04 TME, Timer Enable + * 03..00 Reserved, must be 0 + * + * 0000 0000 + */ + write_reg(info, (unsigned char)(timer + TMCS), 0); + + info->irq_occurred = TRUE; + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_timer()\n", + __FILE__,__LINE__,info->device_name); +} + +void isr_rxint(SLMP_INFO * info) +{ + struct tty_struct *tty = info->tty; + struct mgsl_icount *icount = &info->icount; + unsigned char status = read_reg(info, SR1); + unsigned char status2 = read_reg(info, SR2); + + /* clear status bits */ + if ( status & (FLGD + IDLD + CDCD + BRKD) ) + write_reg(info, SR1, + (unsigned char)(status & (FLGD + IDLD + CDCD + BRKD))); + + if ( status2 & OVRN ) + write_reg(info, SR2, (unsigned char)(status2 & OVRN)); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_rxint status=%02X %02x\n", + __FILE__,__LINE__,info->device_name,status,status2); + + if (info->params.mode == MGSL_MODE_ASYNC) { + if (status & BRKD) { + icount->brk++; + + /* process break detection if tty control + * is not set to ignore it + */ + if ( tty ) { + if (!(status & info->ignore_status_mask1)) { + if (info->read_status_mask1 & BRKD) { + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } + } + } + } + } + else { + if (status & (FLGD|IDLD)) { + if (status & FLGD) + info->icount.exithunt++; + else if (status & IDLD) + info->icount.rxidle++; + wake_up_interruptible(&info->event_wait_q); + } + } + + if (status & CDCD) { + /* simulate a common modem status change interrupt + * for our handler + */ + get_signals( info ); + isr_io_pin(info, + MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD)); + } +} + +/* + * handle async rx data interrupts + */ +void isr_rxrdy(SLMP_INFO * info) +{ + u16 status; + unsigned char DataByte; + struct tty_struct *tty = info->tty; + struct mgsl_icount *icount = &info->icount; + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_rxrdy\n", + __FILE__,__LINE__,info->device_name); + + while((status = read_reg(info,CST0)) & BIT0) + { + DataByte = read_reg(info,TRB); + + if ( tty ) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + continue; + + *tty->flip.char_buf_ptr = DataByte; + *tty->flip.flag_buf_ptr = 0; + } + + icount->rx++; + + if ( status & (PE + FRME + OVRN) ) { + printk("%s(%d):%s rxerr=%04X\n", + __FILE__,__LINE__,info->device_name,status); + + /* update error statistics */ + if (status & PE) + icount->parity++; + else if (status & FRME) + icount->frame++; + else if (status & OVRN) + icount->overrun++; + + /* discard char if tty control flags say so */ + if (status & info->ignore_status_mask2) + continue; + + status &= info->read_status_mask2; + + if ( tty ) { + if (status & PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (status & FRME) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (status & OVRN) { + /* Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + } /* end of if (error) */ + + if ( tty ) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + } + + if ( debug_level >= DEBUG_LEVEL_ISR ) { + printk("%s(%d):%s isr_rxrdy() flip count=%d\n", + __FILE__,__LINE__,info->device_name, + tty ? tty->flip.count : 0); + printk("%s(%d):%s rx=%d brk=%d parity=%d frame=%d overrun=%d\n", + __FILE__,__LINE__,info->device_name, + icount->rx,icount->brk,icount->parity, + icount->frame,icount->overrun); + } + + if ( tty && tty->flip.count ) + tty_flip_buffer_push(tty); +} + +void isr_txeom(SLMP_INFO * info, unsigned char status) +{ + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_txeom status=%02x\n", + __FILE__,__LINE__,info->device_name,status); + + /* disable and clear MSCI interrupts */ + info->ie1_value &= ~(IDLE + UDRN); + write_reg(info, IE1, info->ie1_value); + write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); + + write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ + write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ + write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ + + if ( info->tx_active ) { + if (info->params.mode != MGSL_MODE_ASYNC) { + if (status & UDRN) + info->icount.txunder++; + else if (status & IDLE) + info->icount.txok++; + } + + info->tx_active = 0; + info->tx_count = info->tx_put = info->tx_get = 0; + + del_timer(&info->tx_timer); + + if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) { + info->serial_signals &= ~SerialSignal_RTS; + info->drop_rts_on_tx_done = 0; + set_signals(info); + } + +#ifdef CONFIG_SYNCLINK_SYNCPPP + if (info->netcount) + sppp_tx_done(info); + else +#endif + { + if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { + tx_stop(info); + return; + } + info->pending_bh |= BH_TRANSMIT; + } + } +} + + +/* + * handle tx status interrupts + */ +void isr_txint(SLMP_INFO * info) +{ + unsigned char status = read_reg(info, SR1); + + /* clear status bits */ + write_reg(info, SR1, (unsigned char)(status & (UDRN + IDLE + CCTS))); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_txint status=%02x\n", + __FILE__,__LINE__,info->device_name,status); + + if (status & (UDRN + IDLE)) + isr_txeom(info, status); + + if (status & CCTS) { + /* simulate a common modem status change interrupt + * for our handler + */ + get_signals( info ); + isr_io_pin(info, + MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS)); + + } +} + +/* + * handle async tx data interrupts + */ +void isr_txrdy(SLMP_INFO * info) +{ + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_txrdy() tx_count=%d\n", + __FILE__,__LINE__,info->device_name,info->tx_count); + + if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) { + tx_stop(info); + return; + } + + if ( info->tx_count ) + tx_load_fifo( info ); + else { + info->tx_active = 0; + info->ie0_value &= ~TXRDYE; + write_reg(info, IE0, info->ie0_value); + } + + if (info->tx_count < WAKEUP_CHARS) + info->pending_bh |= BH_TRANSMIT; +} + +void isr_rxdmaok(SLMP_INFO * info) +{ + /* BIT7 = EOT (end of transfer) + * BIT6 = EOM (end of message/frame) + */ + unsigned char status = read_reg(info,RXDMA + DSR) & 0xc0; + + /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ + write_reg(info, RXDMA + DSR, (unsigned char)(status | 1)); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_rxdmaok(), status=%02x\n", + __FILE__,__LINE__,info->device_name,status); + + info->pending_bh |= BH_RECEIVE; +} + +void isr_rxdmaerror(SLMP_INFO * info) +{ + /* BIT5 = BOF (buffer overflow) + * BIT4 = COF (counter overflow) + */ + unsigned char status = read_reg(info,RXDMA + DSR) & 0x30; + + /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ + write_reg(info, RXDMA + DSR, (unsigned char)(status | 1)); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_rxdmaerror(), status=%02x\n", + __FILE__,__LINE__,info->device_name,status); + + info->rx_overflow = TRUE; + info->pending_bh |= BH_RECEIVE; +} + +void isr_txdmaok(SLMP_INFO * info) +{ + /* BIT7 = EOT (end of transfer, used for async mode) + * BIT6 = EOM (end of message/frame, used for sync mode) + * + * We don't look at DMA status because only EOT is enabled + * and we always clear and disable all tx DMA IRQs. + */ +// unsigned char dma_status = read_reg(info,TXDMA + DSR) & 0xc0; + unsigned char status_reg1 = read_reg(info, SR1); + + write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ + write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ + write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_txdmaok(), status=%02x\n", + __FILE__,__LINE__,info->device_name,status_reg1); + + /* If transmitter already idle, do end of frame processing, + * otherwise enable interrupt for tx IDLE. + */ + if (status_reg1 & IDLE) + isr_txeom(info, IDLE); + else { + /* disable and clear underrun IRQ, enable IDLE interrupt */ + info->ie1_value |= IDLE; + info->ie1_value &= ~UDRN; + write_reg(info, IE1, info->ie1_value); + + write_reg(info, SR1, UDRN); + } +} + +void isr_txdmaerror(SLMP_INFO * info) +{ + /* BIT5 = BOF (buffer overflow) + * BIT4 = COF (counter overflow) + */ + unsigned char status = read_reg(info,TXDMA + DSR) & 0x30; + + /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ + write_reg(info, TXDMA + DSR, (unsigned char)(status | 1)); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s isr_txdmaerror(), status=%02x\n", + __FILE__,__LINE__,info->device_name,status); +} + +/* handle input serial signal changes + */ +void isr_io_pin( SLMP_INFO *info, u16 status ) +{ + struct mgsl_icount *icount; + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):isr_io_pin status=%04X\n", + __FILE__,__LINE__,status); + + if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED | + MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) { + icount = &info->icount; + /* update input line counters */ + if (status & MISCSTATUS_RI_LATCHED) { + icount->rng++; + if ( status & SerialSignal_RI ) + info->input_signal_events.ri_up++; + else + info->input_signal_events.ri_down++; + } + if (status & MISCSTATUS_DSR_LATCHED) { + icount->dsr++; + if ( status & SerialSignal_DSR ) + info->input_signal_events.dsr_up++; + else + info->input_signal_events.dsr_down++; + } + if (status & MISCSTATUS_DCD_LATCHED) { + if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) { + info->ie1_value &= ~CDCD; + write_reg(info, IE1, info->ie1_value); + } + icount->dcd++; + if (status & SerialSignal_DCD) { + info->input_signal_events.dcd_up++; +#ifdef CONFIG_SYNCLINK_SYNCPPP + if (info->netcount) + sppp_reopen(info->netdev); +#endif + } else + info->input_signal_events.dcd_down++; + } + if (status & MISCSTATUS_CTS_LATCHED) + { + if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) { + info->ie1_value &= ~CCTS; + write_reg(info, IE1, info->ie1_value); + } + icount->cts++; + if ( status & SerialSignal_CTS ) + info->input_signal_events.cts_up++; + else + info->input_signal_events.cts_down++; + } + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + + if ( (info->flags & ASYNC_CHECK_CD) && + (status & MISCSTATUS_DCD_LATCHED) ) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s CD now %s...", info->device_name, + (status & SerialSignal_DCD) ? "on" : "off"); + if (status & SerialSignal_DCD) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("doing serial hangup..."); + if (info->tty) + tty_hangup(info->tty); + } + } + + if ( (info->flags & ASYNC_CTS_FLOW) && + (status & MISCSTATUS_CTS_LATCHED) ) { + if ( info->tty ) { + if (info->tty->hw_stopped) { + if (status & SerialSignal_CTS) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("CTS tx start..."); + info->tty->hw_stopped = 0; + tx_start(info); + info->pending_bh |= BH_TRANSMIT; + return; + } + } else { + if (!(status & SerialSignal_CTS)) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("CTS tx stop..."); + info->tty->hw_stopped = 1; + tx_stop(info); + } + } + } + } + } + + info->pending_bh |= BH_STATUS; +} + +/* Interrupt service routine entry point. + * + * Arguments: + * irq interrupt number that caused interrupt + * dev_id device ID supplied during interrupt registration + * regs interrupted processor context + */ +static void synclinkmp_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + SLMP_INFO * info; + unsigned char status, status0, status1=0; + unsigned char dmastatus, dmastatus0, dmastatus1=0; + unsigned char timerstatus0, timerstatus1=0; + unsigned char shift; + unsigned int i; + unsigned short tmp; + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d): synclinkmp_interrupt(%d)entry.\n", + __FILE__,__LINE__,irq); + + info = (SLMP_INFO *)dev_id; + if (!info) + return; + + spin_lock(&info->lock); + + for(;;) { + + /* get status for SCA0 (ports 0-1) */ + tmp = read_reg16(info, ISR0); /* get ISR0 and ISR1 in one read */ + status0 = (unsigned char)tmp; + dmastatus0 = (unsigned char)(tmp>>8); + timerstatus0 = read_reg(info, ISR2); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s status0=%02x, dmastatus0=%02x, timerstatus0=%02x\n", + __FILE__,__LINE__,info->device_name, + status0,dmastatus0,timerstatus0); + + if (info->port_count == 4) { + /* get status for SCA1 (ports 2-3) */ + tmp = read_reg16(info->port_array[2], ISR0); + status1 = (unsigned char)tmp; + dmastatus1 = (unsigned char)(tmp>>8); + timerstatus1 = read_reg(info->port_array[2], ISR2); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s status1=%02x, dmastatus1=%02x, timerstatus1=%02x\n", + __FILE__,__LINE__,info->device_name, + status1,dmastatus1,timerstatus1); + } + + if (!status0 && !dmastatus0 && !timerstatus0 && + !status1 && !dmastatus1 && !timerstatus1) + break; + + for(i=0; i < info->port_count ; i++) { + if (info->port_array[i] == NULL) + continue; + if (i < 2) { + status = status0; + dmastatus = dmastatus0; + } else { + status = status1; + dmastatus = dmastatus1; + } + + shift = i & 1 ? 4 :0; + + if (status & BIT0 << shift) + isr_rxrdy(info->port_array[i]); + if (status & BIT1 << shift) + isr_txrdy(info->port_array[i]); + if (status & BIT2 << shift) + isr_rxint(info->port_array[i]); + if (status & BIT3 << shift) + isr_txint(info->port_array[i]); + + if (dmastatus & BIT0 << shift) + isr_rxdmaerror(info->port_array[i]); + if (dmastatus & BIT1 << shift) + isr_rxdmaok(info->port_array[i]); + if (dmastatus & BIT2 << shift) + isr_txdmaerror(info->port_array[i]); + if (dmastatus & BIT3 << shift) + isr_txdmaok(info->port_array[i]); + } + + if (timerstatus0 & (BIT5 | BIT4)) + isr_timer(info->port_array[0]); + if (timerstatus0 & (BIT7 | BIT6)) + isr_timer(info->port_array[1]); + if (timerstatus1 & (BIT5 | BIT4)) + isr_timer(info->port_array[2]); + if (timerstatus1 & (BIT7 | BIT6)) + isr_timer(info->port_array[3]); + } + + for(i=0; i < info->port_count ; i++) { + SLMP_INFO * port = info->port_array[i]; + + /* Request bottom half processing if there's something + * for it to do and the bh is not already running. + * + * Note: startup adapter diags require interrupts. + * do not request bottom half processing if the + * device is not open in a normal mode. + */ + if ( port && (port->count || port->netcount) && + port->pending_bh && !port->bh_running && + !port->bh_requested ) { + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):%s queueing bh task.\n", + __FILE__,__LINE__,port->device_name); + queue_task(&port->task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + port->bh_requested = 1; + } + } + + spin_unlock(&info->lock); + + if ( debug_level >= DEBUG_LEVEL_ISR ) + printk("%s(%d):synclinkmp_interrupt(%d)exit.\n", + __FILE__,__LINE__,irq); +} + +/* Initialize and start device. + */ +static int startup(SLMP_INFO * info) +{ + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name); + + if (info->flags & ASYNC_INITIALIZED) + return 0; + + if (!info->tx_buf) { + info->tx_buf = (unsigned char *)kmalloc(info->max_frame_size, GFP_KERNEL); + if (!info->tx_buf) { + printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", + __FILE__,__LINE__,info->device_name); + return -ENOMEM; + } + } + + info->pending_bh = 0; + + init_timer(&info->tx_timer); + info->tx_timer.data = (unsigned long)info; + info->tx_timer.function = tx_timeout; + + /* program hardware for current parameters */ + reset_port(info); + + change_params(info); + + init_timer(&info->status_timer); + info->status_timer.data = (unsigned long)info; + info->status_timer.function = status_timeout; + info->status_timer.expires = jiffies + jiffies_from_ms(10); + add_timer(&info->status_timer); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags |= ASYNC_INITIALIZED; + + return 0; +} + +/* Called by close() and hangup() to shutdown hardware + */ +static void shutdown(SLMP_INFO * info) +{ + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s synclinkmp_shutdown()\n", + __FILE__,__LINE__, info->device_name ); + + /* clear status wait queue because status changes */ + /* can't happen after shutting down the hardware */ + wake_up_interruptible(&info->status_event_wait_q); + wake_up_interruptible(&info->event_wait_q); + + del_timer(&info->tx_timer); + del_timer(&info->status_timer); + + if (info->tx_buf) { + free_page((unsigned long) info->tx_buf); + info->tx_buf = 0; + } + + spin_lock_irqsave(&info->lock,flags); + + reset_port(info); + + if (!info->tty || info->tty->termios->c_cflag & HUPCL) { + info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); + set_signals(info); + } + + spin_unlock_irqrestore(&info->lock,flags); + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; +} + +static void program_hw(SLMP_INFO *info) +{ + unsigned long flags; + + spin_lock_irqsave(&info->lock,flags); + + rx_stop(info); + tx_stop(info); + + info->tx_count = info->tx_put = info->tx_get = 0; + + if (info->params.mode == MGSL_MODE_HDLC || info->netcount) + hdlc_mode(info); + else + async_mode(info); + + set_signals(info); + + info->dcd_chkcount = 0; + info->cts_chkcount = 0; + info->ri_chkcount = 0; + info->dsr_chkcount = 0; + + info->ie1_value |= (CDCD|CCTS); + write_reg(info, IE1, info->ie1_value); + + get_signals(info); + + if (info->netcount || (info->tty && info->tty->termios->c_cflag & CREAD) ) + rx_start(info); + + spin_unlock_irqrestore(&info->lock,flags); +} + +/* Reconfigure adapter based on new parameters + */ +static void change_params(SLMP_INFO *info) +{ + unsigned cflag; + int bits_per_char; + + if (!info->tty || !info->tty->termios) + return; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s change_params()\n", + __FILE__,__LINE__, info->device_name ); + + cflag = info->tty->termios->c_cflag; + + /* if B0 rate (hangup) specified then negate DTR and RTS */ + /* otherwise assert DTR and RTS */ + if (cflag & CBAUD) + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + else + info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); + + /* byte size and parity */ + + switch (cflag & CSIZE) { + case CS5: info->params.data_bits = 5; break; + case CS6: info->params.data_bits = 6; break; + case CS7: info->params.data_bits = 7; break; + case CS8: info->params.data_bits = 8; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: info->params.data_bits = 7; break; + } + + if (cflag & CSTOPB) + info->params.stop_bits = 2; + else + info->params.stop_bits = 1; + + info->params.parity = ASYNC_PARITY_NONE; + if (cflag & PARENB) { + if (cflag & PARODD) + info->params.parity = ASYNC_PARITY_ODD; + else + info->params.parity = ASYNC_PARITY_EVEN; +#ifdef CMSPAR + if (cflag & CMSPAR) + info->params.parity = ASYNC_PARITY_SPACE; +#endif + } + + /* calculate number of jiffies to transmit a full + * FIFO (32 bytes) at specified data rate + */ + bits_per_char = info->params.data_bits + + info->params.stop_bits + 1; + + /* if port data rate is set to 460800 or less then + * allow tty settings to override, otherwise keep the + * current data rate. + */ + if (info->params.data_rate <= 460800) { + info->params.data_rate = tty_get_baud_rate(info->tty); + } + + if ( info->params.data_rate ) { + info->timeout = (32*HZ*bits_per_char) / + info->params.data_rate; + } + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + /* process tty input control flags */ + + info->read_status_mask2 = OVRN; + if (I_INPCK(info->tty)) + info->read_status_mask2 |= PE | FRME; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask1 |= BRKD; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask2 |= PE | FRME; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask1 |= BRKD; + /* If ignoring parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask2 |= OVRN; + } + + program_hw(info); +} + +static int get_stats(SLMP_INFO * info, struct mgsl_icount *user_icount) +{ + int err; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s get_params()\n", + __FILE__,__LINE__, info->device_name); + + COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s get_stats() user buffer copy failed\n", + __FILE__,__LINE__,info->device_name); + return -EFAULT; + } + + return 0; +} + +static int get_params(SLMP_INFO * info, MGSL_PARAMS *user_params) +{ + int err; + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s get_params()\n", + __FILE__,__LINE__, info->device_name); + + COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s get_params() user buffer copy failed\n", + __FILE__,__LINE__,info->device_name); + return -EFAULT; + } + + return 0; +} + +static int set_params(SLMP_INFO * info, MGSL_PARAMS *new_params) +{ + unsigned long flags; + MGSL_PARAMS tmp_params; + int err; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s set_params\n", + __FILE__,__LINE__,info->device_name ); + COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s set_params() user buffer copy failed\n", + __FILE__,__LINE__,info->device_name); + return -EFAULT; + } + + spin_lock_irqsave(&info->lock,flags); + memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); + spin_unlock_irqrestore(&info->lock,flags); + + change_params(info); + + return 0; +} + +static int get_txidle(SLMP_INFO * info, int*idle_mode) +{ + int err; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s get_txidle()=%d\n", + __FILE__,__LINE__, info->device_name, info->idle_mode); + + COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); + if (err) { + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s get_txidle() user buffer copy failed\n", + __FILE__,__LINE__,info->device_name); + return -EFAULT; + } + + return 0; +} + +static int set_txidle(SLMP_INFO * info, int idle_mode) +{ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s set_txidle(%d)\n", + __FILE__,__LINE__,info->device_name, idle_mode ); + + spin_lock_irqsave(&info->lock,flags); + info->idle_mode = idle_mode; + tx_set_idle( info ); + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int tx_enable(SLMP_INFO * info, int enable) +{ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s tx_enable(%d)\n", + __FILE__,__LINE__,info->device_name, enable); + + spin_lock_irqsave(&info->lock,flags); + if ( enable ) { + if ( !info->tx_enabled ) { + tx_start(info); + } + } else { + if ( info->tx_enabled ) + tx_stop(info); + } + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +/* abort send HDLC frame + */ +static int tx_abort(SLMP_INFO * info) +{ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s tx_abort()\n", + __FILE__,__LINE__,info->device_name); + + spin_lock_irqsave(&info->lock,flags); + if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC ) { + info->ie1_value &= ~UDRN; + info->ie1_value |= IDLE; + write_reg(info, IE1, info->ie1_value); /* disable tx status interrupts */ + write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); /* clear pending */ + + write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ + write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ + + write_reg(info, CMD, TXABORT); + } + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int rx_enable(SLMP_INFO * info, int enable) +{ + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s rx_enable(%d)\n", + __FILE__,__LINE__,info->device_name,enable); + + spin_lock_irqsave(&info->lock,flags); + if ( enable ) { + if ( !info->rx_enabled ) + rx_start(info); + } else { + if ( info->rx_enabled ) + rx_stop(info); + } + spin_unlock_irqrestore(&info->lock,flags); + return 0; +} + +static int map_status(int signals) +{ + /* Map status bits to API event bits */ + + return ((signals & SerialSignal_DSR) ? MgslEvent_DsrActive : MgslEvent_DsrInactive) + + ((signals & SerialSignal_CTS) ? MgslEvent_CtsActive : MgslEvent_CtsInactive) + + ((signals & SerialSignal_DCD) ? MgslEvent_DcdActive : MgslEvent_DcdInactive) + + ((signals & SerialSignal_RI) ? MgslEvent_RiActive : MgslEvent_RiInactive); +} + +/* wait for specified event to occur + */ +static int wait_mgsl_event(SLMP_INFO * info, int * mask_ptr) +{ + unsigned long flags; + int s; + int rc=0; + struct mgsl_icount cprev, cnow; + int events; + int mask; + struct _input_signal_events oldsigs, newsigs; + DECLARE_WAITQUEUE(wait, current); + + COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); + if (rc) { + return -EFAULT; + } + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s wait_mgsl_event(%d)\n", + __FILE__,__LINE__,info->device_name,mask); + + spin_lock_irqsave(&info->lock,flags); + + /* return immediately if state matches requested events */ + get_signals(info); + s = map_status(info->serial_signals); + + events = mask & + ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + + ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + + ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + + ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); + if (events) { + spin_unlock_irqrestore(&info->lock,flags); + goto exit; + } + + /* save current irq counts */ + cprev = info->icount; + oldsigs = info->input_signal_events; + + /* enable hunt and idle irqs if needed */ + if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) { + unsigned char oldval = info->ie1_value; + unsigned char newval = oldval + + (mask & MgslEvent_ExitHuntMode ? FLGD:0) + + (mask & MgslEvent_IdleReceived ? IDLE:0); + if ( oldval != newval ) { + info->ie1_value = newval; + write_reg(info, IE1, info->ie1_value); + } + } + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&info->event_wait_q, &wait); + + spin_unlock_irqrestore(&info->lock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get current irq counts */ + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + newsigs = info->input_signal_events; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + /* if no change, wait aborted for some reason */ + if (newsigs.dsr_up == oldsigs.dsr_up && + newsigs.dsr_down == oldsigs.dsr_down && + newsigs.dcd_up == oldsigs.dcd_up && + newsigs.dcd_down == oldsigs.dcd_down && + newsigs.cts_up == oldsigs.cts_up && + newsigs.cts_down == oldsigs.cts_down && + newsigs.ri_up == oldsigs.ri_up && + newsigs.ri_down == oldsigs.ri_down && + cnow.exithunt == cprev.exithunt && + cnow.rxidle == cprev.rxidle) { + rc = -EIO; + break; + } + + events = mask & + ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + + (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + + (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + + (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + + (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + + (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + + (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + + (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + + (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + + (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); + if (events) + break; + + cprev = cnow; + oldsigs = newsigs; + } + + remove_wait_queue(&info->event_wait_q, &wait); + set_current_state(TASK_RUNNING); + + + if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { + spin_lock_irqsave(&info->lock,flags); + if (!waitqueue_active(&info->event_wait_q)) { + /* disable enable exit hunt mode/idle rcvd IRQs */ + info->ie1_value &= ~(FLGD|IDLE); + write_reg(info, IE1, info->ie1_value); + } + spin_unlock_irqrestore(&info->lock,flags); + } +exit: + if ( rc == 0 ) + PUT_USER(rc, events, mask_ptr); + + return rc; +} + +static int modem_input_wait(SLMP_INFO *info,int arg) +{ + unsigned long flags; + int rc; + struct mgsl_icount cprev, cnow; + DECLARE_WAITQUEUE(wait, current); + + /* save current irq counts */ + spin_lock_irqsave(&info->lock,flags); + cprev = info->icount; + add_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + for(;;) { + schedule(); + if (signal_pending(current)) { + rc = -ERESTARTSYS; + break; + } + + /* get new irq counts */ + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&info->lock,flags); + + /* if no change, wait aborted for some reason */ + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { + rc = -EIO; + break; + } + + /* check for change in caller specified modem input */ + if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || + (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || + (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || + (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { + rc = 0; + break; + } + + cprev = cnow; + } + remove_wait_queue(&info->status_event_wait_q, &wait); + set_current_state(TASK_RUNNING); + return rc; +} + +/* return the state of the serial control and status signals + */ +static int get_modem_info(SLMP_INFO * info, unsigned int *value) +{ + unsigned int result; + unsigned long flags; + int err; + + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) + + ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) + + ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) + + ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG:0) + + ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) + + ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0); + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s synclinkmp_get_modem_info() value=%08X\n", + __FILE__,__LINE__, info->device_name, result ); + + PUT_USER(err,result,value); + return err; +} + +/* set modem control signals (DTR/RTS) + * + * cmd signal command: TIOCMBIS = set bit TIOCMBIC = clear bit + * TIOCMSET = set/clear signal values + * value bit mask for command + */ +static int set_modem_info(SLMP_INFO * info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s synclinkmp_set_modem_info()\n", + __FILE__,__LINE__,info->device_name ); + + GET_USER(error,arg,value); + if (error) + return error; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->serial_signals |= SerialSignal_RTS; + if (arg & TIOCM_DTR) + info->serial_signals |= SerialSignal_DTR; + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->serial_signals &= ~SerialSignal_RTS; + if (arg & TIOCM_DTR) + info->serial_signals &= ~SerialSignal_DTR; + break; + case TIOCMSET: + if (arg & TIOCM_RTS) + info->serial_signals |= SerialSignal_RTS; + else + info->serial_signals &= ~SerialSignal_RTS; + + if (arg & TIOCM_DTR) + info->serial_signals |= SerialSignal_DTR; + else + info->serial_signals &= ~SerialSignal_DTR; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&info->lock,flags); + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + return 0; +} + + + +/* Block the current process until the specified port is ready to open. + */ +static int block_til_ready(struct tty_struct *tty, struct file *filp, + SLMP_INFO *info) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s block_til_ready()\n", + __FILE__,__LINE__, tty->driver.name ); + + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + /* this is a callout device */ + /* just verify that normal device is not in use */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ + /* nonblock mode is set or port is not enabled */ + /* just verify that callout device is not active */ + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* Wait for carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + + retval = 0; + add_wait_queue(&info->open_wait, &wait); + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s block_til_ready() before block, count=%d\n", + __FILE__,__LINE__, tty->driver.name, info->count ); + + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + info->count--; + } + restore_flags(flags); + info->blocked_open++; + + while (1) { + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) { + spin_lock_irqsave(&info->lock,flags); + info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; + set_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + } + + set_current_state(TASK_INTERRUPTIBLE); + + if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){ + retval = (info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + break; + } + + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { + break; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s block_til_ready() count=%d\n", + __FILE__,__LINE__, tty->driver.name, info->count ); + + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + + if (extra_count) + info->count++; + info->blocked_open--; + + if (debug_level >= DEBUG_LEVEL_INFO) + printk("%s(%d):%s block_til_ready() after, count=%d\n", + __FILE__,__LINE__, tty->driver.name, info->count ); + + if (!retval) + info->flags |= ASYNC_NORMAL_ACTIVE; + + return retval; +} + +int alloc_dma_bufs(SLMP_INFO *info) +{ + unsigned short BuffersPerFrame; + unsigned short BufferCount; + + // Force allocation to start at 64K boundary for each port. + // This is necessary because *all* buffer descriptors for a port + // *must* be in the same 64K block. All descriptors on a port + // share a common 'base' address (upper 8 bits of 24 bits) programmed + // into the CBP register. + info->port_array[0]->last_mem_alloc = (SCA_MEM_SIZE/4) * info->port_num; + + /* Calculate the number of DMA buffers necessary to hold the */ + /* largest allowable frame size. Note: If the max frame size is */ + /* not an even multiple of the DMA buffer size then we need to */ + /* round the buffer count per frame up one. */ + + BuffersPerFrame = (unsigned short)(info->max_frame_size/SCABUFSIZE); + if ( info->max_frame_size % SCABUFSIZE ) + BuffersPerFrame++; + + /* calculate total number of data buffers (SCABUFSIZE) possible + * in one ports memory (SCA_MEM_SIZE/4) after allocating memory + * for the descriptor list (BUFFERLISTSIZE). + */ + BufferCount = (SCA_MEM_SIZE/4 - BUFFERLISTSIZE)/SCABUFSIZE; + + /* limit number of buffers to maximum amount of descriptors */ + if (BufferCount > BUFFERLISTSIZE/sizeof(SCADESC)) + BufferCount = BUFFERLISTSIZE/sizeof(SCADESC); + + /* use enough buffers to transmit one max size frame */ + info->tx_buf_count = BuffersPerFrame + 1; + + /* never use more than half the available buffers for transmit */ + if (info->tx_buf_count > (BufferCount/2)) + info->tx_buf_count = BufferCount/2; + + if (info->tx_buf_count > SCAMAXDESC) + info->tx_buf_count = SCAMAXDESC; + + /* use remaining buffers for receive */ + info->rx_buf_count = BufferCount - info->tx_buf_count; + + if (info->rx_buf_count > SCAMAXDESC) + info->rx_buf_count = SCAMAXDESC; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk("%s(%d):%s Allocating %d TX and %d RX DMA buffers.\n", + __FILE__,__LINE__, info->device_name, + info->tx_buf_count,info->rx_buf_count); + + if ( alloc_buf_list( info ) < 0 || + alloc_frame_bufs(info, + info->rx_buf_list, + info->rx_buf_list_ex, + info->rx_buf_count) < 0 || + alloc_frame_bufs(info, + info->tx_buf_list, + info->tx_buf_list_ex, + info->tx_buf_count) < 0 || + alloc_tmp_rx_buf(info) < 0 ) { + printk("%s(%d):%s Can't allocate DMA buffer memory\n", + __FILE__,__LINE__, info->device_name); + return -ENOMEM; + } + + rx_reset_buffers( info ); + + return 0; +} + +/* Allocate DMA buffers for the transmit and receive descriptor lists. + */ +int alloc_buf_list(SLMP_INFO *info) +{ + unsigned int i; + + /* build list in adapter shared memory */ + info->buffer_list = info->memory_base + info->port_array[0]->last_mem_alloc; + info->buffer_list_phys = info->port_array[0]->last_mem_alloc; + info->port_array[0]->last_mem_alloc += BUFFERLISTSIZE; + + memset(info->buffer_list, 0, BUFFERLISTSIZE); + + /* Save virtual address pointers to the receive and */ + /* transmit buffer lists. (Receive 1st). These pointers will */ + /* be used by the processor to access the lists. */ + info->rx_buf_list = (SCADESC *)info->buffer_list; + + info->tx_buf_list = (SCADESC *)info->buffer_list; + info->tx_buf_list += info->rx_buf_count; + + /* Build links for circular buffer entry lists (tx and rx) + * + * Note: links are physical addresses read by the SCA device + * to determine the next buffer entry to use. + */ + + for ( i = 0; i < info->rx_buf_count; i++ ) { + /* calculate and store physical address of this buffer entry */ + info->rx_buf_list_ex[i].phys_entry = + info->buffer_list_phys + (i * sizeof(SCABUFSIZE)); + + /* calculate and store physical address of */ + /* next entry in cirular list of entries */ + info->rx_buf_list[i].next = info->buffer_list_phys; + if ( i < info->rx_buf_count - 1 ) + info->rx_buf_list[i].next += (i + 1) * sizeof(SCADESC); + + info->rx_buf_list[i].length = SCABUFSIZE; + } + + for ( i = 0; i < info->tx_buf_count; i++ ) { + /* calculate and store physical address of this buffer entry */ + info->tx_buf_list_ex[i].phys_entry = info->buffer_list_phys + + ((info->rx_buf_count + i) * sizeof(SCADESC)); + + /* calculate and store physical address of */ + /* next entry in cirular list of entries */ + + info->tx_buf_list[i].next = info->buffer_list_phys + + info->rx_buf_count * sizeof(SCADESC); + + if ( i < info->tx_buf_count - 1 ) + info->tx_buf_list[i].next += (i + 1) * sizeof(SCADESC); + } + + return 0; +} + +/* Allocate the frame DMA buffers used by the specified buffer list. + */ +int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count) +{ + int i; + unsigned long phys_addr; + + for ( i = 0; i < count; i++ ) { + buf_list_ex[i].virt_addr = info->memory_base + info->port_array[0]->last_mem_alloc; + phys_addr = info->port_array[0]->last_mem_alloc; + info->port_array[0]->last_mem_alloc += SCABUFSIZE; + + buf_list[i].buf_ptr = (unsigned short)phys_addr; + buf_list[i].buf_base = (unsigned char)(phys_addr >> 16); + } + + return 0; +} + +void free_dma_bufs(SLMP_INFO *info) +{ + info->buffer_list = NULL; + info->rx_buf_list = NULL; + info->tx_buf_list = NULL; +} + +/* allocate buffer large enough to hold max_frame_size. + * This buffer is used to pass an assembled frame to the line discipline. + */ +int alloc_tmp_rx_buf(SLMP_INFO *info) +{ + info->tmp_rx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); + if (info->tmp_rx_buf == NULL) + return -ENOMEM; + return 0; +} + +void free_tmp_rx_buf(SLMP_INFO *info) +{ + if (info->tmp_rx_buf) + kfree(info->tmp_rx_buf); + info->tmp_rx_buf = NULL; +} + +int claim_resources(SLMP_INFO *info) +{ + if (request_mem_region(info->phys_memory_base,0x40000,"synclinkmp") == NULL) { + printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_memory_base); + goto errout; + } + else + info->shared_mem_requested = 1; + + if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { + printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_lcr_base); + goto errout; + } + else + info->lcr_mem_requested = 1; + + if (request_mem_region(info->phys_sca_base + info->sca_offset,512,"synclinkmp") == NULL) { + printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_sca_base); + goto errout; + } + else + info->sca_base_requested = 1; + + if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,16,"synclinkmp") == NULL) { + printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_statctrl_base); + goto errout; + } + else + info->sca_statctrl_requested = 1; + + info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE); + if (!info->memory_base) { + printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + goto errout; + } + + if ( !memory_test(info) ) { + printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_memory_base ); + goto errout; + } + + info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset; + if (!info->lcr_base) { + printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); + goto errout; + } + + info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE) + info->sca_offset; + if (!info->sca_base) { + printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_sca_base ); + goto errout; + } + + info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE) + info->statctrl_offset; + if (!info->statctrl_base) { + printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n", + __FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); + goto errout; + } + + return 0; + +errout: + release_resources( info ); + return -ENODEV; +} + +void release_resources(SLMP_INFO *info) +{ + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s release_resources() entry\n", + __FILE__,__LINE__,info->device_name ); + + if ( info->irq_requested ) { + free_irq(info->irq_level, info); + info->irq_requested = 0; + } + + if ( info->shared_mem_requested ) { + release_mem_region(info->phys_memory_base,0x40000); + info->shared_mem_requested = 0; + } + if ( info->lcr_mem_requested ) { + release_mem_region(info->phys_lcr_base + info->lcr_offset,128); + info->lcr_mem_requested = 0; + } + if ( info->sca_base_requested ) { + release_mem_region(info->phys_sca_base + info->sca_offset,512); + info->sca_base_requested = 0; + } + if ( info->sca_statctrl_requested ) { + release_mem_region(info->phys_statctrl_base + info->statctrl_offset,16); + info->sca_statctrl_requested = 0; + } + + if (info->memory_base){ + iounmap(info->memory_base); + info->memory_base = 0; + } + + if (info->sca_base) { + iounmap(info->sca_base - info->sca_offset); + info->sca_base=0; + } + + if (info->statctrl_base) { + iounmap(info->statctrl_base - info->statctrl_offset); + info->statctrl_base=0; + } + + if (info->lcr_base){ + iounmap(info->lcr_base - info->lcr_offset); + info->lcr_base = 0; + } + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s release_resources() exit\n", + __FILE__,__LINE__,info->device_name ); +} + +/* Add the specified device instance data structure to the + * global linked list of devices and increment the device count. + */ +void add_device(SLMP_INFO *info) +{ + info->next_device = NULL; + info->line = synclinkmp_device_count; + sprintf(info->device_name,"ttySLM%dp%d",info->adapter_num,info->port_num); + + if (info->line < MAX_DEVICES) { + if (maxframe[info->line]) + info->max_frame_size = maxframe[info->line]; + info->dosyncppp = dosyncppp[info->line]; + } + + synclinkmp_device_count++; + + if ( !synclinkmp_device_list ) + synclinkmp_device_list = info; + else { + SLMP_INFO *current_dev = synclinkmp_device_list; + while( current_dev->next_device ) + current_dev = current_dev->next_device; + current_dev->next_device = info; + } + + if ( info->max_frame_size < 4096 ) + info->max_frame_size = 4096; + else if ( info->max_frame_size > 65535 ) + info->max_frame_size = 65535; + + printk( "SyncLink MultiPort %s: " + "Mem=(%08x %08X %08x %08X) IRQ=%d MaxFrameSize=%u\n", + info->device_name, + info->phys_sca_base, + info->phys_memory_base, + info->phys_statctrl_base, + info->phys_lcr_base, + info->irq_level, + info->max_frame_size ); + +#ifdef CONFIG_SYNCLINK_SYNCPPP + if (info->dosyncppp) + sppp_init(info); +#endif +} + +/* Allocate and initialize a device instance structure + * + * Return Value: pointer to SLMP_INFO if success, otherwise NULL + */ +SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) +{ + SLMP_INFO *info; + + info = (SLMP_INFO *)kmalloc(sizeof(SLMP_INFO), + GFP_KERNEL); + + if (!info) { + printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n", + __FILE__,__LINE__, adapter_num, port_num); + } else { + memset(info, 0, sizeof(SLMP_INFO)); + info->magic = MGSL_MAGIC; + info->task.sync = 0; + info->task.routine = bh_handler; + info->task.data = info; + info->max_frame_size = 4096; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->status_event_wait_q); + init_waitqueue_head(&info->event_wait_q); + spin_lock_init(&info->netlock); + memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); + info->idle_mode = HDLC_TXIDLE_FLAGS; + info->adapter_num = adapter_num; + info->port_num = port_num; + + /* Copy configuration info to device instance data */ + info->irq_level = pdev->irq; + info->phys_lcr_base = pci_resource_start(pdev,0); + info->phys_sca_base = pci_resource_start(pdev,2); + info->phys_memory_base = pci_resource_start(pdev,3); + info->phys_statctrl_base = pci_resource_start(pdev,4); + + /* Because veremap only works on page boundaries we must map + * a larger area than is actually implemented for the LCR + * memory range. We map a full page starting at the page boundary. + */ + info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1); + info->phys_lcr_base &= ~(PAGE_SIZE-1); + + info->sca_offset = info->phys_sca_base & (PAGE_SIZE-1); + info->phys_sca_base &= ~(PAGE_SIZE-1); + + info->statctrl_offset = info->phys_statctrl_base & (PAGE_SIZE-1); + info->phys_statctrl_base &= ~(PAGE_SIZE-1); + + info->bus_type = MGSL_BUS_TYPE_PCI; + info->irq_flags = SA_SHIRQ; + + /* Store the PCI9050 misc control register value because a flaw + * in the PCI9050 prevents LCR registers from being read if + * BIOS assigns an LCR base address with bit 7 set. + * + * Only the misc control register is accessed for which only + * write access is needed, so set an initial value and change + * bits to the device instance data as we write the value + * to the actual misc control register. + */ + info->misc_ctrl_value = 0x087e4546; + + /* initial port state is unknown - if startup errors + * occur, init_error will be set to indicate the + * problem. Once the port is fully initialized, + * this value will be set to 0 to indicate the + * port is available. + */ + info->init_error = -1; + } + + return info; +} + +void device_init(int adapter_num, struct pci_dev *pdev) +{ + SLMP_INFO *port_array[SCA_MAX_PORTS]; + int port; + + /* allocate device instances for up to SCA_MAX_PORTS devices */ + for ( port = 0; port < SCA_MAX_PORTS; ++port ) { + port_array[port] = alloc_dev(adapter_num,port,pdev); + if( port_array[port] == NULL ) { + for ( --port; port >= 0; --port ) + kfree(port_array[port]); + return; + } + } + + /* give copy of port_array to all ports and add to device list */ + for ( port = 0; port < SCA_MAX_PORTS; ++port ) { + memcpy(port_array[port]->port_array,port_array,sizeof(port_array)); + add_device( port_array[port] ); + spin_lock_init(&port_array[port]->lock); + } + + /* Allocate and claim adapter resources */ + if ( !claim_resources(port_array[0]) ) { + + alloc_dma_bufs(port_array[0]); + + /* copy resource information from first port to others */ + for ( port = 1; port < SCA_MAX_PORTS; ++port ) { + port_array[port]->lock = port_array[0]->lock; + port_array[port]->irq_level = port_array[0]->irq_level; + port_array[port]->memory_base = port_array[0]->memory_base; + port_array[port]->sca_base = port_array[0]->sca_base; + port_array[port]->statctrl_base = port_array[0]->statctrl_base; + port_array[port]->lcr_base = port_array[0]->lcr_base; + alloc_dma_bufs(port_array[port]); + } + + if ( request_irq(port_array[0]->irq_level, + synclinkmp_interrupt, + port_array[0]->irq_flags, + port_array[0]->device_name, + port_array[0]) < 0 ) { + printk( "%s(%d):%s Cant request interrupt, IRQ=%d\n", + __FILE__,__LINE__, + port_array[0]->device_name, + port_array[0]->irq_level ); + } + else { + port_array[0]->irq_requested = 1; + adapter_test(port_array[0]); + } + } +} + +/* Driver initialization entry point. + */ + +static int __init synclinkmp_init(void) +{ + SLMP_INFO *info; + + EXPORT_NO_SYMBOLS; + + if (break_on_load) { + synclinkmp_get_text_ptr(); + BREAKPOINT(); + } + + printk("%s %s\n", driver_name, driver_version); + + synclinkmp_adapter_count = -1; + pci_register_driver(&synclinkmp_pci_driver); + + if ( !synclinkmp_device_list ) { + printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__); + return -ENODEV; + } + + memset(serial_table,0,sizeof(struct tty_struct*)*MAX_DEVICES); + memset(serial_termios,0,sizeof(struct termios*)*MAX_DEVICES); + memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_DEVICES); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "synclinkmp"; + serial_driver.name = "ttySLM"; + serial_driver.major = ttymajor; + serial_driver.minor_start = 64; + serial_driver.num = synclinkmp_device_count; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = open; + serial_driver.close = close; + serial_driver.write = write; + serial_driver.put_char = put_char; + serial_driver.flush_chars = flush_chars; + serial_driver.write_room = write_room; + serial_driver.chars_in_buffer = chars_in_buffer; + serial_driver.flush_buffer = flush_buffer; + serial_driver.ioctl = ioctl; + serial_driver.throttle = throttle; + serial_driver.unthrottle = unthrottle; + serial_driver.send_xchar = send_xchar; + serial_driver.break_ctl = set_break; + serial_driver.wait_until_sent = wait_until_sent; + serial_driver.read_proc = read_proc; + serial_driver.set_termios = set_termios; + serial_driver.stop = tx_hold; + serial_driver.start = tx_release; + serial_driver.hangup = hangup; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cuaSLM"; + callout_driver.major = cuamajor; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver) < 0) + printk("%s(%d):Couldn't register serial driver\n", + __FILE__,__LINE__); + + if (tty_register_driver(&callout_driver) < 0) + printk("%s(%d):Couldn't register callout driver\n", + __FILE__,__LINE__); + + printk("%s %s, tty major#%d callout major#%d\n", + driver_name, driver_version, + serial_driver.major, callout_driver.major); + + /* Propagate these values to all device instances */ + + info = synclinkmp_device_list; + while(info){ + info->callout_termios = callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + info = info->next_device; + } + + return 0; +} + +static void __exit synclinkmp_exit(void) +{ + unsigned long flags; + int rc; + SLMP_INFO *info; + SLMP_INFO *tmp; + + printk("Unloading %s %s\n", driver_name, driver_version); + save_flags(flags); + cli(); + if ((rc = tty_unregister_driver(&serial_driver))) + printk("%s(%d) failed to unregister tty driver err=%d\n", + __FILE__,__LINE__,rc); + if ((rc = tty_unregister_driver(&callout_driver))) + printk("%s(%d) failed to unregister callout driver err=%d\n", + __FILE__,__LINE__,rc); + restore_flags(flags); + + info = synclinkmp_device_list; + while(info) { +#ifdef CONFIG_SYNCLINK_SYNCPPP + if (info->dosyncppp) + sppp_delete(info); +#endif + reset_port(info); + if ( info->port_num == 0 ) { + if ( info->irq_requested ) { + free_irq(info->irq_level, info); + info->irq_requested = 0; + } + } + info = info->next_device; + } + + /* port 0 of each adapter originally claimed + * all resources, release those now + */ + info = synclinkmp_device_list; + while(info) { + free_dma_bufs(info); + free_tmp_rx_buf(info); + if ( info->port_num == 0 ) { + spin_lock_irqsave(&info->lock,flags); + reset_adapter(info); + write_reg(info, LPR, 1); /* set low power mode */ + spin_unlock_irqrestore(&info->lock,flags); + release_resources(info); + } + tmp = info; + info = info->next_device; + kfree(tmp); + } + + pci_unregister_driver(&synclinkmp_pci_driver); +} + +module_init(synclinkmp_init); +module_exit(synclinkmp_exit); + +/* Set the port for internal loopback mode. + * The TxCLK and RxCLK signals are generated from the BRG and + * the TxD is looped back to the RxD internally. + */ +void enable_loopback(SLMP_INFO *info, int enable) +{ + if (enable) { + /* MD2 (Mode Register 2) + * 01..00 CNCT<1..0> Channel Connection 11=Local Loopback + */ + write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) | (BIT1 + BIT0))); + + /* degate external TxC clock source */ + info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); + write_control_reg(info); + + /* RXS/TXS (Rx/Tx clock source) + * 07 Reserved, must be 0 + * 06..04 Clock Source, 100=BRG + * 03..00 Clock Divisor, 0000=1 + */ + write_reg(info, RXS, 0x40); + write_reg(info, TXS, 0x40); + + } else { + /* MD2 (Mode Register 2) + * 01..00 CNCT<1..0> Channel connection, 0=normal + */ + write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) & ~(BIT1 + BIT0))); + + /* RXS/TXS (Rx/Tx clock source) + * 07 Reserved, must be 0 + * 06..04 Clock Source, 000=RxC/TxC Pin + * 03..00 Clock Divisor, 0000=1 + */ + write_reg(info, RXS, 0x00); + write_reg(info, TXS, 0x00); + } + + /* set LinkSpeed if available, otherwise default to 2Mbps */ + if (info->params.clock_speed) + set_rate(info, info->params.clock_speed); + else + set_rate(info, 3686400); +} + +/* Set the baud rate register to the desired speed + * + * data_rate data rate of clock in bits per second + * A data rate of 0 disables the AUX clock. + */ +void set_rate( SLMP_INFO *info, u32 data_rate ) +{ + u32 TMCValue; + unsigned char BRValue; + u32 Divisor=0; + + /* fBRG = fCLK/(TMC * 2^BR) + */ + if (data_rate != 0) { + Divisor = 14745600/data_rate; + if (!Divisor) + Divisor = 1; + + TMCValue = Divisor; + + BRValue = 0; + if (TMCValue != 1 && TMCValue != 2) { + /* BRValue of 0 provides 50/50 duty cycle *only* when + * TMCValue is 1 or 2. BRValue of 1 to 9 always provides + * 50/50 duty cycle. + */ + BRValue = 1; + TMCValue >>= 1; + } + + /* while TMCValue is too big for TMC register, divide + * by 2 and increment BR exponent. + */ + for(; TMCValue > 256 && BRValue < 10; BRValue++) + TMCValue >>= 1; + + write_reg(info, TXS, + (unsigned char)((read_reg(info, TXS) & 0xf0) | BRValue)); + write_reg(info, RXS, + (unsigned char)((read_reg(info, RXS) & 0xf0) | BRValue)); + write_reg(info, TMC, (unsigned char)TMCValue); + } + else { + write_reg(info, TXS,0); + write_reg(info, RXS,0); + write_reg(info, TMC, 0); + } +} + +/* Disable receiver + */ +void rx_stop(SLMP_INFO *info) +{ + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):%s rx_stop()\n", + __FILE__,__LINE__, info->device_name ); + + write_reg(info, CMD, RXRESET); + + info->ie0_value &= ~RXRDYE; + write_reg(info, IE0, info->ie0_value); /* disable Rx data interrupts */ + + write_reg(info, RXDMA + DSR, 0); /* disable Rx DMA */ + write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */ + write_reg(info, RXDMA + DIR, 0); /* disable Rx DMA interrupts */ + + info->rx_enabled = 0; + info->rx_overflow = 0; +} + +/* enable the receiver + */ +void rx_start(SLMP_INFO *info) +{ + int i; + + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):%s rx_start()\n", + __FILE__,__LINE__, info->device_name ); + + write_reg(info, CMD, RXRESET); + + if ( info->params.mode == MGSL_MODE_HDLC ) { + /* HDLC, disabe IRQ on rxdata */ + info->ie0_value &= ~RXRDYE; + write_reg(info, IE0, info->ie0_value); + + /* Reset all Rx DMA buffers and program rx dma */ + write_reg(info, RXDMA + DSR, 0); /* disable Rx DMA */ + write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */ + + for (i = 0; i < info->rx_buf_count; i++) { + info->rx_buf_list[i].status = 0xff; + + // throttle to 4 shared memory writes at a time to prevent + // hogging local bus (keep latency time for DMA requests low). + if (!(i % 4)) + read_status_reg(info); + } + info->current_rx_buf = 0; + + /* set current/1st descriptor address */ + write_reg16(info, RXDMA + CDA, + info->rx_buf_list_ex[0].phys_entry); + + /* set new last rx descriptor address */ + write_reg16(info, RXDMA + EDA, + info->rx_buf_list_ex[info->rx_buf_count - 1].phys_entry); + + /* set buffer length (shared by all rx dma data buffers) */ + write_reg16(info, RXDMA + BFL, SCABUFSIZE); + + write_reg(info, RXDMA + DIR, 0x60); /* enable Rx DMA interrupts (EOM/BOF) */ + write_reg(info, RXDMA + DSR, 0xf2); /* clear Rx DMA IRQs, enable Rx DMA */ + } else { + /* async, enable IRQ on rxdata */ + info->ie0_value |= RXRDYE; + write_reg(info, IE0, info->ie0_value); + } + + write_reg(info, CMD, RXENABLE); + + info->rx_overflow = FALSE; + info->rx_enabled = 1; +} + +/* Enable the transmitter and send a transmit frame if + * one is loaded in the DMA buffers. + */ +void tx_start(SLMP_INFO *info) +{ + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):%s tx_start() tx_count=%d\n", + __FILE__,__LINE__, info->device_name,info->tx_count ); + + if (!info->tx_enabled ) { + write_reg(info, CMD, TXRESET); + write_reg(info, CMD, TXENABLE); + info->tx_enabled = TRUE; + } + + if ( info->tx_count ) { + + /* If auto RTS enabled and RTS is inactive, then assert */ + /* RTS and set a flag indicating that the driver should */ + /* negate RTS when the transmission completes. */ + + info->drop_rts_on_tx_done = 0; + + if (info->params.mode != MGSL_MODE_ASYNC) { + + if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) { + get_signals( info ); + if ( !(info->serial_signals & SerialSignal_RTS) ) { + info->serial_signals |= SerialSignal_RTS; + set_signals( info ); + info->drop_rts_on_tx_done = 1; + } + } + + write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ + write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ + + /* set TX CDA (current descriptor address) */ + write_reg16(info, TXDMA + CDA, + info->tx_buf_list_ex[0].phys_entry); + + /* set TX EDA (last descriptor address) */ + write_reg16(info, TXDMA + EDA, + info->tx_buf_list_ex[info->last_tx_buf].phys_entry); + + /* clear IDLE and UDRN status bit */ + info->ie1_value &= ~(IDLE + UDRN); + if (info->params.mode != MGSL_MODE_ASYNC) + info->ie1_value |= UDRN; /* HDLC, IRQ on underrun */ + write_reg(info, IE1, info->ie1_value); /* enable MSCI interrupts */ + write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); + + write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */ + write_reg(info, TXDMA + DSR, 0xf2); /* clear Tx DMA IRQs, enable Tx DMA */ + + info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + add_timer(&info->tx_timer); + } + else { + tx_load_fifo(info); + /* async, enable IRQ on txdata */ + info->ie0_value |= TXRDYE; + write_reg(info, IE0, info->ie0_value); + } + + info->tx_active = 1; + } +} + +/* stop the transmitter and DMA + */ +void tx_stop( SLMP_INFO *info ) +{ + if (debug_level >= DEBUG_LEVEL_ISR) + printk("%s(%d):%s tx_stop()\n", + __FILE__,__LINE__, info->device_name ); + + del_timer(&info->tx_timer); + + write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ + write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ + + write_reg(info, CMD, TXRESET); + + info->ie1_value &= ~(UDRN + IDLE); + write_reg(info, IE1, info->ie1_value); /* disable tx status interrupts */ + write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); /* clear pending */ + + info->ie0_value &= ~TXRDYE; + write_reg(info, IE0, info->ie0_value); /* disable tx data interrupts */ + + info->tx_enabled = 0; + info->tx_active = 0; +} + +/* Fill the transmit FIFO until the FIFO is full or + * there is no more data to load. + */ +void tx_load_fifo(SLMP_INFO *info) +{ + u8 TwoBytes[2]; + + /* do nothing is now tx data available and no XON/XOFF pending */ + + if ( !info->tx_count && !info->x_char ) + return; + + /* load the Transmit FIFO until FIFOs full or all data sent */ + + while( info->tx_count && (read_reg(info,SR0) & BIT1) ) { + + /* there is more space in the transmit FIFO and */ + /* there is more data in transmit buffer */ + + if ( (info->tx_count > 1) && !info->x_char ) { + /* write 16-bits */ + TwoBytes[0] = info->tx_buf[info->tx_get++]; + if (info->tx_get >= info->max_frame_size) + info->tx_get -= info->max_frame_size; + TwoBytes[1] = info->tx_buf[info->tx_get++]; + if (info->tx_get >= info->max_frame_size) + info->tx_get -= info->max_frame_size; + + write_reg16(info, TRB, *((u16 *)TwoBytes)); + + info->tx_count -= 2; + info->icount.tx += 2; + } else { + /* only 1 byte left to transmit or 1 FIFO slot left */ + + if (info->x_char) { + /* transmit pending high priority char */ + write_reg(info, TRB, info->x_char); + info->x_char = 0; + } else { + write_reg(info, TRB, info->tx_buf[info->tx_get++]); + if (info->tx_get >= info->max_frame_size) + info->tx_get -= info->max_frame_size; + info->tx_count--; + } + info->icount.tx++; + } + } +} + +/* Reset a port to a known state + */ +void reset_port(SLMP_INFO *info) +{ + if (info->sca_base) { + + tx_stop(info); + rx_stop(info); + + info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); + set_signals(info); + + /* disable all port interrupts */ + info->ie0_value = 0; + info->ie1_value = 0; + info->ie2_value = 0; + write_reg(info, IE0, info->ie0_value); + write_reg(info, IE1, info->ie1_value); + write_reg(info, IE2, info->ie2_value); + + write_reg(info, CMD, CHRESET); + } +} + +/* Reset all the ports to a known state. + */ +void reset_adapter(SLMP_INFO *info) +{ + int i; + + for ( i=0; i < SCA_MAX_PORTS; ++i) { + if (info->port_array[i]) + reset_port(info->port_array[i]); + } +} + +/* Program port for asynchronous communications. + */ +void async_mode(SLMP_INFO *info) +{ + + unsigned char RegValue; + + tx_stop(info); + rx_stop(info); + + /* MD0, Mode Register 0 + * + * 07..05 PRCTL<2..0>, Protocol Mode, 000=async + * 04 AUTO, Auto-enable (RTS/CTS/DCD) + * 03 Reserved, must be 0 + * 02 CRCCC, CRC Calculation, 0=disabled + * 01..00 STOP<1..0> Stop bits (00=1,10=2) + * + * 0000 0000 + */ + RegValue = 0x00; + if (info->params.stop_bits != 1) + RegValue |= BIT1; + write_reg(info, MD0, RegValue); + + /* MD1, Mode Register 1 + * + * 07..06 BRATE<1..0>, bit rate, 00=1/1 01=1/16 10=1/32 11=1/64 + * 05..04 TXCHR<1..0>, tx char size, 00=8 bits,01=7,10=6,11=5 + * 03..02 RXCHR<1..0>, rx char size + * 01..00 PMPM<1..0>, Parity mode, 00=none 10=even 11=odd + * + * 0100 0000 + */ + RegValue = 0x40; + switch (info->params.data_bits) { + case 7: RegValue |= BIT4 + BIT2; break; + case 6: RegValue |= BIT5 + BIT3; break; + case 5: RegValue |= BIT5 + BIT4 + BIT3 + BIT2; break; + } + if (info->params.parity != ASYNC_PARITY_NONE) { + RegValue |= BIT1; + if (info->params.parity == ASYNC_PARITY_ODD) + RegValue |= BIT0; + } + write_reg(info, MD1, RegValue); + + /* MD2, Mode Register 2 + * + * 07..02 Reserved, must be 0 + * 01..00 CNCT<1..0> Channel connection, 0=normal + * + * 0000 0000 + */ + RegValue = 0x00; + write_reg(info, MD2, RegValue); + + /* RXS, Receive clock source + * + * 07 Reserved, must be 0 + * 06..04 RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL + * 03..00 RXBR<3..0>, rate divisor, 0000=1 + */ + RegValue=BIT6; + write_reg(info, RXS, RegValue); + + /* TXS, Transmit clock source + * + * 07 Reserved, must be 0 + * 06..04 RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock + * 03..00 RXBR<3..0>, rate divisor, 0000=1 + */ + RegValue=BIT6; + write_reg(info, TXS, RegValue); + + /* Control Register + * + * 6,4,2,0 CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out + */ + info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); + write_control_reg(info); + + tx_set_idle(info); + + /* RRC Receive Ready Control 0 + * + * 07..05 Reserved, must be 0 + * 04..00 RRC<4..0> Rx FIFO trigger active 0x00 = 1 byte + */ + write_reg(info, TRC0, 0x00); + + /* TRC0 Transmit Ready Control 0 + * + * 07..05 Reserved, must be 0 + * 04..00 TRC<4..0> Tx FIFO trigger active 0x10 = 16 bytes + */ + write_reg(info, TRC0, 0x10); + + /* TRC1 Transmit Ready Control 1 + * + * 07..05 Reserved, must be 0 + * 04..00 TRC<4..0> Tx FIFO trigger inactive 0x1e = 31 bytes (full-1) + */ + write_reg(info, TRC1, 0x1e); + + /* CTL, MSCI control register + * + * 07..06 Reserved, set to 0 + * 05 UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC) + * 04 IDLC, idle control, 0=mark 1=idle register + * 03 BRK, break, 0=off 1 =on (async) + * 02 SYNCLD, sync char load enable (BSC) 1=enabled + * 01 GOP, go active on poll (LOOP mode) 1=enabled + * 00 RTS, RTS output control, 0=active 1=inactive + * + * 0001 0001 + */ + RegValue = 0x10; + if (!(info->serial_signals & SerialSignal_RTS)) + RegValue |= 0x01; + write_reg(info, CTL, RegValue); + + /* enable status interrupts */ + info->ie0_value |= TXINTE + RXINTE; + write_reg(info, IE0, info->ie0_value); + + /* enable break detect interrupt */ + info->ie1_value = BRKD; + write_reg(info, IE1, info->ie1_value); + + /* enable rx overrun interrupt */ + info->ie2_value = OVRN; + write_reg(info, IE2, info->ie2_value); + + set_rate( info, info->params.data_rate * 16 ); + + if (info->params.loopback) + enable_loopback(info,1); +} + +/* Program the SCA for HDLC communications. + */ +void hdlc_mode(SLMP_INFO *info) +{ + unsigned char RegValue; + u32 DpllDivisor; + + // Can't use DPLL because SCA outputs recovered clock on RxC when + // DPLL mode selected. This causes output contention with RxC receiver. + // Use of DPLL would require external hardware to disable RxC receiver + // when DPLL mode selected. + info->params.flags &= ~(HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL); + + /* disable DMA interrupts */ + write_reg(info, TXDMA + DIR, 0); + write_reg(info, RXDMA + DIR, 0); + + /* MD0, Mode Register 0 + * + * 07..05 PRCTL<2..0>, Protocol Mode, 100=HDLC + * 04 AUTO, Auto-enable (RTS/CTS/DCD) + * 03 Reserved, must be 0 + * 02 CRCCC, CRC Calculation, 1=enabled + * 01 CRC1, CRC selection, 0=CRC-16,1=CRC-CCITT-16 + * 00 CRC0, CRC initial value, 1 = all 1s + * + * 1000 0001 + */ + RegValue = 0x81; + if (info->params.flags & HDLC_FLAG_AUTO_CTS) + RegValue |= BIT4; + if (info->params.flags & HDLC_FLAG_AUTO_DCD) + RegValue |= BIT4; + if (info->params.crc_type == HDLC_CRC_16_CCITT) + RegValue |= BIT2 + BIT1; + write_reg(info, MD0, RegValue); + + /* MD1, Mode Register 1 + * + * 07..06 ADDRS<1..0>, Address detect, 00=no addr check + * 05..04 TXCHR<1..0>, tx char size, 00=8 bits + * 03..02 RXCHR<1..0>, rx char size, 00=8 bits + * 01..00 PMPM<1..0>, Parity mode, 00=no parity + * + * 0000 0000 + */ + RegValue = 0x00; + write_reg(info, MD1, RegValue); + + /* MD2, Mode Register 2 + * + * 07 NRZFM, 0=NRZ, 1=FM + * 06..05 CODE<1..0> Encoding, 00=NRZ + * 04..03 DRATE<1..0> DPLL Divisor, 00=8 + * 02 Reserved, must be 0 + * 01..00 CNCT<1..0> Channel connection, 0=normal + * + * 0000 0000 + */ + RegValue = 0x00; + switch(info->params.encoding) { + case HDLC_ENCODING_NRZI: RegValue |= BIT5; break; + case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT7 + BIT5; break; /* aka FM1 */ + case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT7 + BIT6; break; /* aka FM0 */ + case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT7; break; /* aka Manchester */ +#if 0 + case HDLC_ENCODING_NRZB: /* not supported */ + case HDLC_ENCODING_NRZI_MARK: /* not supported */ + case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: /* not supported */ +#endif + } + if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) { + DpllDivisor = 16; + RegValue |= BIT3; + } else if ( info->params.flags & HDLC_FLAG_DPLL_DIV8 ) { + DpllDivisor = 8; + } else { + DpllDivisor = 32; + RegValue |= BIT4; + } + write_reg(info, MD2, RegValue); + + + /* RXS, Receive clock source + * + * 07 Reserved, must be 0 + * 06..04 RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL + * 03..00 RXBR<3..0>, rate divisor, 0000=1 + */ + RegValue=0; + if (info->params.flags & HDLC_FLAG_RXC_BRG) + RegValue |= BIT6; + if (info->params.flags & HDLC_FLAG_RXC_DPLL) + RegValue |= BIT6 + BIT5; + write_reg(info, RXS, RegValue); + + /* TXS, Transmit clock source + * + * 07 Reserved, must be 0 + * 06..04 RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock + * 03..00 RXBR<3..0>, rate divisor, 0000=1 + */ + RegValue=0; + if (info->params.flags & HDLC_FLAG_TXC_BRG) + RegValue |= BIT6; + if (info->params.flags & HDLC_FLAG_TXC_DPLL) + RegValue |= BIT6 + BIT5; + write_reg(info, TXS, RegValue); + + if (info->params.flags & HDLC_FLAG_RXC_DPLL) + set_rate(info, info->params.clock_speed * DpllDivisor); + else + set_rate(info, info->params.clock_speed); + + /* GPDATA (General Purpose I/O Data Register) + * + * 6,4,2,0 CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out + */ + if (info->params.flags & HDLC_FLAG_TXC_BRG) + info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); + else + info->port_array[0]->ctrlreg_value &= ~(BIT0 << (info->port_num * 2)); + write_control_reg(info); + + /* RRC Receive Ready Control 0 + * + * 07..05 Reserved, must be 0 + * 04..00 RRC<4..0> Rx FIFO trigger active + */ + write_reg(info, RRC, rx_active_fifo_level); + + /* TRC0 Transmit Ready Control 0 + * + * 07..05 Reserved, must be 0 + * 04..00 TRC<4..0> Tx FIFO trigger active + */ + write_reg(info, TRC0, tx_active_fifo_level); + + /* TRC1 Transmit Ready Control 1 + * + * 07..05 Reserved, must be 0 + * 04..00 TRC<4..0> Tx FIFO trigger inactive 0x1f = 32 bytes (full) + */ + write_reg(info, TRC1, (unsigned char)(tx_negate_fifo_level - 1)); + + /* DMR, DMA Mode Register + * + * 07..05 Reserved, must be 0 + * 04 TMOD, Transfer Mode: 1=chained-block + * 03 Reserved, must be 0 + * 02 NF, Number of Frames: 1=multi-frame + * 01 CNTE, Frame End IRQ Counter enable: 0=disabled + * 00 Reserved, must be 0 + * + * 0001 0100 + */ + write_reg(info, TXDMA + DMR, 0x14); + write_reg(info, RXDMA + DMR, 0x14); + + /* Set chain pointer base (upper 8 bits of 24 bit addr) */ + write_reg(info, RXDMA + CPB, + (unsigned char)(info->buffer_list_phys >> 16)); + + /* Set chain pointer base (upper 8 bits of 24 bit addr) */ + write_reg(info, TXDMA + CPB, + (unsigned char)(info->buffer_list_phys >> 16)); + + /* enable status interrupts. other code enables/disables + * the individual sources for these two interrupt classes. + */ + info->ie0_value |= TXINTE + RXINTE; + write_reg(info, IE0, info->ie0_value); + + /* CTL, MSCI control register + * + * 07..06 Reserved, set to 0 + * 05 UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC) + * 04 IDLC, idle control, 0=mark 1=idle register + * 03 BRK, break, 0=off 1 =on (async) + * 02 SYNCLD, sync char load enable (BSC) 1=enabled + * 01 GOP, go active on poll (LOOP mode) 1=enabled + * 00 RTS, RTS output control, 0=active 1=inactive + * + * 0001 0001 + */ + RegValue = 0x10; + if (!(info->serial_signals & SerialSignal_RTS)) + RegValue |= 0x01; + write_reg(info, CTL, RegValue); + + /* preamble not supported ! */ + + tx_set_idle(info); + tx_stop(info); + rx_stop(info); + + set_rate(info, info->params.clock_speed); + + if (info->params.loopback) + enable_loopback(info,1); +} + +/* Set the transmit HDLC idle mode + */ +void tx_set_idle(SLMP_INFO *info) +{ + unsigned char RegValue = 0xff; + + /* Map API idle mode to SCA register bits */ + switch(info->idle_mode) { + case HDLC_TXIDLE_FLAGS: RegValue = 0x7e; break; + case HDLC_TXIDLE_ALT_ZEROS_ONES: RegValue = 0xaa; break; + case HDLC_TXIDLE_ZEROS: RegValue = 0x00; break; + case HDLC_TXIDLE_ONES: RegValue = 0xff; break; + case HDLC_TXIDLE_ALT_MARK_SPACE: RegValue = 0xaa; break; + case HDLC_TXIDLE_SPACE: RegValue = 0x00; break; + case HDLC_TXIDLE_MARK: RegValue = 0xff; break; + } + + write_reg(info, IDL, RegValue); +} + +/* Query the adapter for the state of the V24 status (input) signals. + */ +void get_signals(SLMP_INFO *info) +{ + u16 status = read_reg(info, SR3); + u16 gpstatus = read_status_reg(info); + u16 testbit; + + /* clear all serial signals except DTR and RTS */ + info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS; + + /* set serial signal bits to reflect MISR */ + + if (!(status & BIT3)) + info->serial_signals |= SerialSignal_CTS; + + if ( !(status & BIT2)) + info->serial_signals |= SerialSignal_DCD; + + testbit = BIT1 << (info->port_num * 2); // Port 0..3 RI is GPDATA<1,3,5,7> + if (!(gpstatus & testbit)) + info->serial_signals |= SerialSignal_RI; + + testbit = BIT0 << (info->port_num * 2); // Port 0..3 DSR is GPDATA<0,2,4,6> + if (!(gpstatus & testbit)) + info->serial_signals |= SerialSignal_DSR; +} + +/* Set the state of DTR and RTS based on contents of + * serial_signals member of device context. + */ +void set_signals(SLMP_INFO *info) +{ + unsigned char RegValue; + u16 EnableBit; + + RegValue = read_reg(info, CTL); + if (info->serial_signals & SerialSignal_RTS) + RegValue &= ~BIT0; + else + RegValue |= BIT0; + write_reg(info, CTL, RegValue); + + // Port 0..3 DTR is ctrl reg <1,3,5,7> + EnableBit = BIT1 << (info->port_num*2); + if (info->serial_signals & SerialSignal_DTR) + info->port_array[0]->ctrlreg_value &= ~EnableBit; + else + info->port_array[0]->ctrlreg_value |= EnableBit; + write_control_reg(info); +} + +/*******************/ +/* DMA Buffer Code */ +/*******************/ + +/* Set the count for all receive buffers to SCABUFSIZE + * and set the current buffer to the first buffer. This effectively + * makes all buffers free and discards any data in buffers. + */ +void rx_reset_buffers(SLMP_INFO *info) +{ + rx_free_frame_buffers(info, 0, info->rx_buf_count - 1); +} + +/* Free the buffers used by a received frame + * + * info pointer to device instance data + * first index of 1st receive buffer of frame + * last index of last receive buffer of frame + */ +void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last) +{ + int done = 0; + + while(!done) { + /* reset current buffer for reuse */ + info->rx_buf_list[first].status = 0xff; + + if (first == last) { + done = 1; + /* set new last rx descriptor address */ + write_reg16(info, RXDMA + EDA, info->rx_buf_list_ex[first].phys_entry); + } + + first++; + if (first == info->rx_buf_count) + first = 0; + } + + /* set current buffer to next buffer after last buffer of frame */ + info->current_rx_buf = first; +} + +/* Return a received frame from the receive DMA buffers. + * Only frames received without errors are returned. + * + * Return Value: 1 if frame returned, otherwise 0 + */ +int rx_get_frame(SLMP_INFO *info) +{ + unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ + unsigned short status; + unsigned int framesize = 0; + int ReturnCode = 0; + unsigned long flags; + struct tty_struct *tty = info->tty; + unsigned char addr_field = 0xff; + SCADESC *desc; + SCADESC_EX *desc_ex; + +CheckAgain: + /* assume no frame returned, set zero length */ + framesize = 0; + addr_field = 0xff; + + /* + * current_rx_buf points to the 1st buffer of the next available + * receive frame. To find the last buffer of the frame look for + * a non-zero status field in the buffer entries. (The status + * field is set by the 16C32 after completing a receive frame. + */ + StartIndex = EndIndex = info->current_rx_buf; + + for ( ;; ) { + desc = &info->rx_buf_list[EndIndex]; + desc_ex = &info->rx_buf_list_ex[EndIndex]; + + if (desc->status == 0xff) + goto Cleanup; /* current desc still in use, no frames available */ + + if (framesize == 0 && info->params.addr_filter != 0xff) + addr_field = desc_ex->virt_addr[0]; + + framesize += desc->length; + + /* Status != 0 means last buffer of frame */ + if (desc->status) + break; + + EndIndex++; + if (EndIndex == info->rx_buf_count) + EndIndex = 0; + + if (EndIndex == info->current_rx_buf) { + /* all buffers have been 'used' but none mark */ + /* the end of a frame. Reset buffers and receiver. */ + if ( info->rx_enabled ){ + spin_lock_irqsave(&info->lock,flags); + rx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } + goto Cleanup; + } + + } + + /* check status of receive frame */ + + /* frame status is byte stored after frame data + * + * 7 EOM (end of msg), 1 = last buffer of frame + * 6 Short Frame, 1 = short frame + * 5 Abort, 1 = frame aborted + * 4 Residue, 1 = last byte is partial + * 3 Overrun, 1 = overrun occurred during frame reception + * 2 CRC, 1 = CRC error detected + * + */ + status = desc->status; + + /* ignore CRC bit if not using CRC (bit is undefined) */ + /* Note:CRC is not save to data buffer */ + if (info->params.crc_type == HDLC_CRC_NONE) + status &= ~BIT2; + + if (framesize == 0 || + (addr_field != 0xff && addr_field != info->params.addr_filter)) { + /* discard 0 byte frames, this seems to occur sometime + * when remote is idling flags. + */ + rx_free_frame_buffers(info, StartIndex, EndIndex); + goto CheckAgain; + } + + if (framesize < 2) + status |= BIT6; + + if (status & (BIT6+BIT5+BIT3+BIT2)) { + /* received frame has errors, + * update counts and mark frame size as 0 + */ + if (status & BIT6) + info->icount.rxshort++; + else if (status & BIT5) + info->icount.rxabort++; + else if (status & BIT3) + info->icount.rxover++; + else + info->icount.rxcrc++; + + framesize = 0; + +#ifdef CONFIG_SYNCLINK_SYNCPPP + info->netstats.rx_errors++; + info->netstats.rx_frame_errors++; +#endif + } + + if ( debug_level >= DEBUG_LEVEL_BH ) + printk("%s(%d):%s rx_get_frame() status=%04X size=%d\n", + __FILE__,__LINE__,info->device_name,status,framesize); + + if ( debug_level >= DEBUG_LEVEL_DATA ) + trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr, + MIN(framesize,SCABUFSIZE),0); + + if (framesize) { + if (framesize > info->max_frame_size) + info->icount.rxlong++; + else { + /* copy dma buffer(s) to contiguous intermediate buffer */ + int copy_count = framesize; + int index = StartIndex; + unsigned char *ptmp = info->tmp_rx_buf; + info->tmp_rx_buf_count = framesize; + + info->icount.rxok++; + + while(copy_count) { + int partial_count = MIN(copy_count,SCABUFSIZE); + memcpy( ptmp, + info->rx_buf_list_ex[index].virt_addr, + partial_count ); + ptmp += partial_count; + copy_count -= partial_count; + + if ( ++index == info->rx_buf_count ) + index = 0; + } + +#ifdef CONFIG_SYNCLINK_SYNCPPP + if (info->netcount) { + /* pass frame to syncppp device */ + sppp_rx_done(info,info->tmp_rx_buf,framesize); + } + else +#endif + { + if ( tty && tty->ldisc.receive_buf ) { + /* Call the line discipline receive callback directly. */ + tty->ldisc.receive_buf(tty, + info->tmp_rx_buf, + info->flag_buf, + framesize); + } + } + } + } + /* Free the buffers used by this frame. */ + rx_free_frame_buffers( info, StartIndex, EndIndex ); + + ReturnCode = 1; + +Cleanup: + if ( info->rx_enabled && info->rx_overflow ) { + /* Receiver is enabled, but needs to restarted due to + * rx buffer overflow. If buffers are empty, restart receiver. + */ + if (info->rx_buf_list[EndIndex].status == 0xff) { + spin_lock_irqsave(&info->lock,flags); + rx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + } + } + + return ReturnCode; +} + +/* load the transmit DMA buffer with data + */ +void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) +{ + unsigned short copy_count; + unsigned int i = 0; + SCADESC *desc; + SCADESC_EX *desc_ex; + + if ( debug_level >= DEBUG_LEVEL_DATA ) + trace_block(info,buf, MIN(count,SCABUFSIZE), 1); + + /* Copy source buffer to one or more DMA buffers, starting with + * the first transmit dma buffer. + */ + for(i=0;;) + { + copy_count = MIN(count,SCABUFSIZE); + + desc = &info->tx_buf_list[i]; + desc_ex = &info->tx_buf_list_ex[i]; + + load_pci_memory(info, desc_ex->virt_addr,buf,copy_count); + + desc->length = copy_count; + desc->status = 0; + + buf += copy_count; + count -= copy_count; + + if (!count) + break; + + i++; + if (i >= info->tx_buf_count) + i = 0; + } + + info->tx_buf_list[i].status = 0x81; /* set EOM and EOT status */ + info->last_tx_buf = ++i; +} + +int register_test(SLMP_INFO *info) +{ + static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96}; + static unsigned int count = sizeof(testval)/sizeof(unsigned char); + unsigned int i; + int rc = TRUE; + unsigned long flags; + + spin_lock_irqsave(&info->lock,flags); + reset_port(info); + + /* assume failure */ + info->init_error = DiagStatus_AddressFailure; + + /* Write bit patterns to various registers but do it out of */ + /* sync, then read back and verify values. */ + + for (i = 0 ; i < count ; i++) { + write_reg(info, TMC, testval[i]); + write_reg(info, IDL, testval[(i+1)%count]); + write_reg(info, SA0, testval[(i+2)%count]); + write_reg(info, SA1, testval[(i+3)%count]); + + if ( (read_reg(info, TMC) != testval[i]) || + (read_reg(info, IDL) != testval[(i+1)%count]) || + (read_reg(info, SA0) != testval[(i+2)%count]) || + (read_reg(info, SA1) != testval[(i+3)%count]) ) + { + rc = FALSE; + break; + } + } + + reset_port(info); + spin_unlock_irqrestore(&info->lock,flags); + + return rc; +} + +int irq_test(SLMP_INFO *info) +{ + unsigned long timeout; + unsigned long flags; + + unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; + + spin_lock_irqsave(&info->lock,flags); + reset_port(info); + + /* assume failure */ + info->init_error = DiagStatus_IrqFailure; + info->irq_occurred = FALSE; + + /* setup timer0 on SCA0 to interrupt */ + + /* IER2<7..4> = timer<3..0> interrupt enables (1=enabled) */ + write_reg(info, IER2, (unsigned char)((info->port_num & 1) ? BIT6 : BIT4)); + + write_reg(info, (unsigned char)(timer + TEPR), 0); /* timer expand prescale */ + write_reg16(info, (unsigned char)(timer + TCONR), 1); /* timer constant */ + + + /* TMCS, Timer Control/Status Register + * + * 07 CMF, Compare match flag (read only) 1=match + * 06 ECMI, CMF Interrupt Enable: 1=enabled + * 05 Reserved, must be 0 + * 04 TME, Timer Enable + * 03..00 Reserved, must be 0 + * + * 0101 0000 + */ + write_reg(info, (unsigned char)(timer + TMCS), 0x50); + + spin_unlock_irqrestore(&info->lock,flags); + + timeout=100; + while( timeout-- && !info->irq_occurred ) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(jiffies_from_ms(10)); + } + + spin_lock_irqsave(&info->lock,flags); + reset_port(info); + spin_unlock_irqrestore(&info->lock,flags); + + return info->irq_occurred; +} + +/* initialize individual SCA device (2 ports) + */ +int sca_init(SLMP_INFO *info) +{ + /* set wait controller to single mem partition (low), no wait states */ + write_reg(info, PABR0, 0); /* wait controller addr boundary 0 */ + write_reg(info, PABR1, 0); /* wait controller addr boundary 1 */ + write_reg(info, WCRL, 0); /* wait controller low range */ + write_reg(info, WCRM, 0); /* wait controller mid range */ + write_reg(info, WCRH, 0); /* wait controller high range */ + + /* DPCR, DMA Priority Control + * + * 07..05 Not used, must be 0 + * 04 BRC, bus release condition: 0=all transfers complete + * 03 CCC, channel change condition: 0=every cycle + * 02..00 PR<2..0>, priority 100=round robin + * + * 00000100 = 0x04 + */ + write_reg(info, DPCR, dma_priority); + + /* DMA Master Enable, BIT7: 1=enable all channels */ + write_reg(info, DMER, 0x80); + + /* enable all interrupt classes */ + write_reg(info, IER0, 0xff); /* TxRDY,RxRDY,TxINT,RxINT (ports 0-1) */ + write_reg(info, IER1, 0xff); /* DMIB,DMIA (channels 0-3) */ + write_reg(info, IER2, 0xf0); /* TIRQ (timers 0-3) */ + + /* ITCR, interrupt control register + * 07 IPC, interrupt priority, 0=MSCI->DMA + * 06..05 IAK<1..0>, Acknowledge cycle, 00=non-ack cycle + * 04 VOS, Vector Output, 0=unmodified vector + * 03..00 Reserved, must be 0 + */ + write_reg(info, ITCR, 0); + + return TRUE; +} + +/* initialize adapter hardware + */ +int init_adapter(SLMP_INFO *info) +{ + int i; + + /* Set BIT30 of Local Control Reg 0x50 to reset SCA */ + volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50); + u32 readval; + + info->misc_ctrl_value |= BIT30; + *MiscCtrl = info->misc_ctrl_value; + + /* + * Force at least 170ns delay before clearing + * reset bit. Each read from LCR takes at least + * 30ns so 10 times for 300ns to be safe. + */ + for(i=0;i<10;i++) + readval = *MiscCtrl; + + info->misc_ctrl_value &= ~BIT30; + *MiscCtrl = info->misc_ctrl_value; + + /* init control reg (all DTRs off, all clksel=input) */ + info->ctrlreg_value = 0xaa; + write_control_reg(info); + + { + volatile u32 *LCR1BRDR = (u32 *)(info->lcr_base + 0x2c); + lcr1_brdr_value &= ~(BIT5 + BIT4 + BIT3); + + switch(read_ahead_count) + { + case 16: + lcr1_brdr_value |= BIT5 + BIT4 + BIT3; + break; + case 8: + lcr1_brdr_value |= BIT5 + BIT4; + break; + case 4: + lcr1_brdr_value |= BIT5 + BIT3; + break; + case 0: + lcr1_brdr_value |= BIT5; + break; + } + + *LCR1BRDR = lcr1_brdr_value; + *MiscCtrl = misc_ctrl_value; + } + + sca_init(info->port_array[0]); + sca_init(info->port_array[2]); + + return TRUE; +} + +/* Loopback an HDLC frame to test the hardware + * interrupt and DMA functions. + */ +int loopback_test(SLMP_INFO *info) +{ +#define TESTFRAMESIZE 20 + + unsigned long timeout; + u16 count = TESTFRAMESIZE; + unsigned char buf[TESTFRAMESIZE]; + int rc = FALSE; + unsigned long flags; + + struct tty_struct *oldtty = info->tty; + u32 speed = info->params.clock_speed; + + info->params.clock_speed = 3686400; + info->tty = 0; + + /* assume failure */ + info->init_error = DiagStatus_DmaFailure; + + /* build and send transmit frame */ + for (count = 0; count < TESTFRAMESIZE;++count) + buf[count] = (unsigned char)count; + + memset(info->tmp_rx_buf,0,TESTFRAMESIZE); + + /* program hardware for HDLC and enabled receiver */ + spin_lock_irqsave(&info->lock,flags); + hdlc_mode(info); + enable_loopback(info,1); + rx_start(info); + info->tx_count = count; + tx_load_dma_buffer(info,buf,count); + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + + /* wait for receive complete */ + /* Set a timeout for waiting for interrupt. */ + for ( timeout = 100; timeout; --timeout ) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(jiffies_from_ms(10)); + + if (rx_get_frame(info)) { + rc = TRUE; + break; + } + } + + /* verify received frame length and contents */ + if (rc == TRUE && + ( info->tmp_rx_buf_count != count || + memcmp(buf, info->tmp_rx_buf,count))) { + rc = FALSE; + } + + spin_lock_irqsave(&info->lock,flags); + reset_adapter(info); + spin_unlock_irqrestore(&info->lock,flags); + + info->params.clock_speed = speed; + info->tty = oldtty; + + return rc; +} + +/* Perform diagnostics on hardware + */ +int adapter_test( SLMP_INFO *info ) +{ + unsigned long flags; + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):Testing device %s\n", + __FILE__,__LINE__,info->device_name ); + + spin_lock_irqsave(&info->lock,flags); + init_adapter(info); + spin_unlock_irqrestore(&info->lock,flags); + + info->port_array[0]->port_count = 0; + + if ( register_test(info->port_array[0]) && + register_test(info->port_array[1])) { + + info->port_array[0]->port_count = 2; + + if ( register_test(info->port_array[2]) && + register_test(info->port_array[3]) ) + info->port_array[0]->port_count += 2; + } + else { + printk( "%s(%d):Register test failure for device %s Addr=%08lX\n", + __FILE__,__LINE__,info->device_name, (unsigned long)(info->phys_sca_base)); + return -ENODEV; + } + + if ( !irq_test(info->port_array[0]) || + !irq_test(info->port_array[1]) || + (info->port_count == 4 && !irq_test(info->port_array[2])) || + (info->port_count == 4 && !irq_test(info->port_array[3]))) { + printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n", + __FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) ); + return -ENODEV; + } + + if (!loopback_test(info->port_array[0]) || + !loopback_test(info->port_array[1]) || + (info->port_count == 4 && !loopback_test(info->port_array[2])) || + (info->port_count == 4 && !loopback_test(info->port_array[3]))) { + printk( "%s(%d):DMA test failure for device %s\n", + __FILE__,__LINE__,info->device_name); + return -ENODEV; + } + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):device %s passed diagnostics\n", + __FILE__,__LINE__,info->device_name ); + + info->port_array[0]->init_error = 0; + info->port_array[1]->init_error = 0; + if ( info->port_count > 2 ) { + info->port_array[2]->init_error = 0; + info->port_array[3]->init_error = 0; + } + + return 0; +} + +/* Test the shared memory on a PCI adapter. + */ +int memory_test(SLMP_INFO *info) +{ + static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa, + 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; + unsigned long count = sizeof(testval)/sizeof(unsigned long); + unsigned long i; + unsigned long limit = SCA_MEM_SIZE/sizeof(unsigned long); + unsigned long * addr = (unsigned long *)info->memory_base; + + /* Test data lines with test pattern at one location. */ + + for ( i = 0 ; i < count ; i++ ) { + *addr = testval[i]; + if ( *addr != testval[i] ) + return FALSE; + } + + /* Test address lines with incrementing pattern over */ + /* entire address range. */ + + for ( i = 0 ; i < limit ; i++ ) { + *addr = i * 4; + addr++; + } + + addr = (unsigned long *)info->memory_base; + + for ( i = 0 ; i < limit ; i++ ) { + if ( *addr != i * 4 ) + return FALSE; + addr++; + } + + memset( info->memory_base, 0, SCA_MEM_SIZE ); + return TRUE; +} + +/* Load data into PCI adapter shared memory. + * + * The PCI9050 releases control of the local bus + * after completing the current read or write operation. + * + * While the PCI9050 write FIFO not empty, the + * PCI9050 treats all of the writes as a single transaction + * and does not release the bus. This causes DMA latency problems + * at high speeds when copying large data blocks to the shared memory. + * + * This function breaks a write into multiple transations by + * interleaving a read which flushes the write FIFO and 'completes' + * the write transation. This allows any pending DMA request to gain control + * of the local bus in a timely fasion. + */ +void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count) +{ + /* A load interval of 16 allows for 4 32-bit writes at */ + /* 136ns each for a maximum latency of 542ns on the local bus.*/ + + unsigned short interval = count / sca_pci_load_interval; + unsigned short i; + + for ( i = 0 ; i < interval ; i++ ) + { + memcpy(dest, src, sca_pci_load_interval); + read_status_reg(info); + dest += sca_pci_load_interval; + src += sca_pci_load_interval; + } + + memcpy(dest, src, count % sca_pci_load_interval); +} + +void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) +{ + int i; + int linecount; + if (xmit) + printk("%s tx data:\n",info->device_name); + else + printk("%s rx data:\n",info->device_name); + + while(count) { + if (count > 16) + linecount = 16; + else + linecount = count; + + for(i=0;i=040 && data[i]<=0176) + printk("%c",data[i]); + else + printk("."); + } + printk("\n"); + + data += linecount; + count -= linecount; + } +} /* end of trace_block() */ + +/* called when HDLC frame times out + * update stats and do tx completion processing + */ +void tx_timeout(unsigned long context) +{ + SLMP_INFO *info = (SLMP_INFO*)context; + unsigned long flags; + + if ( debug_level >= DEBUG_LEVEL_INFO ) + printk( "%s(%d):%s tx_timeout()\n", + __FILE__,__LINE__,info->device_name); + if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { + info->icount.txtimeout++; + } + spin_lock_irqsave(&info->lock,flags); + info->tx_active = 0; + info->tx_count = info->tx_put = info->tx_get = 0; + + spin_unlock_irqrestore(&info->lock,flags); + +#ifdef CONFIG_SYNCLINK_SYNCPPP + if (info->netcount) + sppp_tx_done(info); + else +#endif + bh_transmit(info); +} + +/* called to periodically check the DSR/RI modem signal input status + */ +void status_timeout(unsigned long context) +{ + u16 status = 0; + SLMP_INFO *info = (SLMP_INFO*)context; + unsigned long flags; + unsigned char delta; + + + spin_lock_irqsave(&info->lock,flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock,flags); + + /* check for DSR/RI state change */ + + delta = info->old_signals ^ info->serial_signals; + info->old_signals = info->serial_signals; + + if (delta & SerialSignal_DSR) + status |= MISCSTATUS_DSR_LATCHED|(info->serial_signals&SerialSignal_DSR); + + if (delta & SerialSignal_RI) + status |= MISCSTATUS_RI_LATCHED|(info->serial_signals&SerialSignal_RI); + + if (delta & SerialSignal_DCD) + status |= MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD); + + if (delta & SerialSignal_CTS) + status |= MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS); + + if (status) + isr_io_pin(info,status); + + info->status_timer.data = (unsigned long)info; + info->status_timer.function = status_timeout; + info->status_timer.expires = jiffies + jiffies_from_ms(10); + add_timer(&info->status_timer); +} + + +/* Register Access Routines - + * All registers are memory mapped + */ +#define CALC_REGADDR() \ + unsigned char * RegAddr = (unsigned char*)(info->sca_base + Addr); \ + if (info->port_num > 1) \ + RegAddr += 256; /* port 0-1 SCA0, 2-3 SCA1 */ \ + if ( info->port_num & 1) { \ + if (Addr > 0x7f) \ + RegAddr += 0x40; /* DMA access */ \ + else if (Addr > 0x1f && Addr < 0x60) \ + RegAddr += 0x20; /* MSCI access */ \ + } + + +unsigned char read_reg(SLMP_INFO * info, unsigned char Addr) +{ + CALC_REGADDR(); + return *RegAddr; +} +void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value) +{ + CALC_REGADDR(); + *RegAddr = Value; +} + +u16 read_reg16(SLMP_INFO * info, unsigned char Addr) +{ + CALC_REGADDR(); + return *((u16 *)RegAddr); +} + +void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value) +{ + CALC_REGADDR(); + *((u16 *)RegAddr) = Value; +} + +unsigned char read_status_reg(SLMP_INFO * info) +{ + unsigned char *RegAddr = (unsigned char *)info->statctrl_base; + return *RegAddr; +} + +void write_control_reg(SLMP_INFO * info) +{ + unsigned char *RegAddr = (unsigned char *)info->statctrl_base; + *RegAddr = info->port_array[0]->ctrlreg_value; +} + + +static int __init synclinkmp_init_one (struct pci_dev *dev, + const struct pci_device_id *ent) +{ + if (pci_enable_device(dev)) { + printk("error enabling pci device %p\n", dev); + return -EIO; + } + device_init( ++synclinkmp_adapter_count, dev ); + return 0; +} + +static void __exit synclinkmp_remove_one (struct pci_dev *dev) +{ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/char/vt.c linux.20pre2-ac1/drivers/char/vt.c --- linux.20pre2/drivers/char/vt.c 2002-08-13 13:58:26.000000000 +0100 +++ linux.20pre2-ac1/drivers/char/vt.c 2002-08-06 15:42:07.000000000 +0100 @@ -481,7 +481,7 @@ ucval = keyboard_type; goto setchar; -#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) +#if defined(__i386__) || defined(__mc68000__) || defined(__ppc__) || defined(__sparc__) /* * These cannot be implemented on any machine that implements * ioperm() in user level (such as Alpha PCs). diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/hotplug/cpqphp_nvram.c linux.20pre2-ac1/drivers/hotplug/cpqphp_nvram.c --- linux.20pre2/drivers/hotplug/cpqphp_nvram.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/hotplug/cpqphp_nvram.c 2002-08-06 15:42:18.000000000 +0100 @@ -176,12 +176,12 @@ spin_lock_irqsave(&int15_lock, flags); __asm__ ( - "xorl %%ebx,%%ebx - xorl %%edx,%%edx - pushf - push %%cs - cli - call *%6" + "xorl %%ebx,%%ebx \n" + "xorl %%edx,%%edx \n" + "pushf \n" + "push %%cs \n" + "cli \n" + "call *%6 \n" : "=c" (*buf_size), "=a" (ret_val) : "a" (op), "c" (*buf_size), "S" (ev_name), "D" (buffer), "m" (compaq_int15_entry_point) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/adma100.c linux.20pre2-ac1/drivers/ide/adma100.c --- linux.20pre2/drivers/ide/adma100.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/adma100.c 2002-08-06 15:42:11.000000000 +0100 @@ -0,0 +1,30 @@ +/* + * linux/drivers/ide/adma100.c -- basic support for Pacific Digital ADMA-100 boards + * + * Created 09 Apr 2002 by Mark Lord + * + * 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 + +void __init ide_init_adma100 (ide_hwif_t *hwif) +{ + u32 phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20); + void *v_admctl; + + hwif->autodma = 0; // not compatible with normal IDE DMA transfers + hwif->dma_base = 0; // disable DMA completely + hwif->io_ports[IDE_CONTROL_OFFSET] += 4; // chip needs offset of 6 instead of 2 + v_admctl = ioremap_nocache(phy_admctl, 1024); // map config regs, so we can turn on drive IRQs + *((unsigned short *)v_admctl) &= 3; // enable aIEN; preserve PIO mode + iounmap(v_admctl); // all done; unmap config regs +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/aec62xx.c linux.20pre2-ac1/drivers/ide/aec62xx.c --- linux.20pre2/drivers/ide/aec62xx.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/aec62xx.c 2002-08-06 15:42:11.000000000 +0100 @@ -1,8 +1,7 @@ /* - * linux/drivers/ide/aec62xx.c Version 0.09 June. 9, 2000 + * linux/drivers/ide/aec62xx.c Version 0.11 March 27, 2002 * - * Copyright (C) 1999-2000 Andre Hedrick (andre@linux-ide.org) - * May be copied or modified under the terms of the GNU General Public License + * Copyright (C) 1999-2002 Andre Hedrick * */ @@ -48,154 +47,209 @@ static int aec62xx_get_info(char *, char **, off_t, int); extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); -static struct pci_dev *bmide_dev; -static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - - u32 bibma = pci_resource_start(bmide_dev, 4); - u8 c0 = 0, c1 = 0; - u8 art = 0, uart = 0; +#define AEC_MAX_DEVS 5 - switch(bmide_dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP850UF: - p += sprintf(p, "\n AEC6210 Chipset.\n"); - break; - case PCI_DEVICE_ID_ARTOP_ATP860: - p += sprintf(p, "\n AEC6260 No Bios Chipset.\n"); - break; - case PCI_DEVICE_ID_ARTOP_ATP860R: - p += sprintf(p, "\n AEC6260 Chipset.\n"); - break; - default: - p += sprintf(p, "\n AEC62?? Chipset.\n"); - break; - } +static struct pci_dev *aec_devs[AEC_MAX_DEVS]; +static int n_aec_devs; - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((unsigned short)bibma + 0x02); - c1 = inb_p((unsigned short)bibma + 0x0a); - - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - (void) pci_read_config_byte(bmide_dev, 0x4a, &art); - p += sprintf(p, " %sabled %sabled\n", - (art&0x02)?" en":"dis",(art&0x04)?" en":"dis"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no "); +#undef DEBUG_AEC_REGS - switch(bmide_dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP850UF: - (void) pci_read_config_byte(bmide_dev, 0x54, &art); - p += sprintf(p, "DMA Mode: %s(%s) %s(%s) %s(%s) %s(%s)\n", +static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + char *chipset_nums[] = {"error", "error", "error", "error", + "error", "error", "850UF", "860", + "860R", "865", "865R", "error" }; +// char *modes_33[] = {}; +// char *modes_34[] = {}; + int i; + + for (i = 0; i < n_aec_devs; i++) { + struct pci_dev *dev = aec_devs[i]; + // u32 iobase = dev->resource[4].start; + u32 iobase = pci_resource_start(dev, 4); + u8 c0 = inb_p(iobase + 0x02); + u8 c1 = inb_p(iobase + 0x0a); + u8 art = 0; +#ifdef DEBUG_AEC_REGS + u8 uart = 0; +#endif /* DEBUG_AEC_REGS */ + + p += sprintf(p, "\nController: %d\n", i); + p += sprintf(p, "Chipset: AEC%s\n", chipset_nums[dev->device]); + + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + (void) pci_read_config_byte(dev, 0x4a, &art); + p += sprintf(p, " %sabled ", + (art&0x02)?" en":"dis"); + p += sprintf(p, " %sabled\n", + (art&0x04)?" en":"dis"); + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s ", + (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no "); + p += sprintf(p, " %s %s\n", + (c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no "); + + if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { + (void) pci_read_config_byte(dev, 0x54, &art); + p += sprintf(p, "DMA Mode: %s(%s)", (c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO", - (art&0x02)?"2":(art&0x01)?"1":"0", + (art&0x02)?"2":(art&0x01)?"1":"0"); + p += sprintf(p, " %s(%s)", (c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO", - (art&0x08)?"2":(art&0x04)?"1":"0", + (art&0x08)?"2":(art&0x04)?"1":"0"); + p += sprintf(p, " %s(%s)", (c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO", - (art&0x20)?"2":(art&0x10)?"1":"0", + (art&0x20)?"2":(art&0x10)?"1":"0"); + p += sprintf(p, " %s(%s)\n", (c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO", (art&0x80)?"2":(art&0x40)?"1":"0"); - (void) pci_read_config_byte(bmide_dev, 0x40, &art); +#ifdef DEBUG_AEC_REGS + (void) pci_read_config_byte(dev, 0x40, &art); p += sprintf(p, "Active: 0x%02x", art); - (void) pci_read_config_byte(bmide_dev, 0x42, &art); + (void) pci_read_config_byte(dev, 0x42, &art); p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(bmide_dev, 0x44, &art); + (void) pci_read_config_byte(dev, 0x44, &art); p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(bmide_dev, 0x46, &art); + (void) pci_read_config_byte(dev, 0x46, &art); p += sprintf(p, " 0x%02x\n", art); - (void) pci_read_config_byte(bmide_dev, 0x41, &art); + (void) pci_read_config_byte(dev, 0x41, &art); p += sprintf(p, "Recovery: 0x%02x", art); - (void) pci_read_config_byte(bmide_dev, 0x43, &art); + (void) pci_read_config_byte(dev, 0x43, &art); p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(bmide_dev, 0x45, &art); + (void) pci_read_config_byte(dev, 0x45, &art); p += sprintf(p, " 0x%02x", art); - (void) pci_read_config_byte(bmide_dev, 0x47, &art); + (void) pci_read_config_byte(dev, 0x47, &art); p += sprintf(p, " 0x%02x\n", art); - break; - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: - (void) pci_read_config_byte(bmide_dev, 0x44, &art); - p += sprintf(p, "DMA Mode: %s(%s) %s(%s)", +#endif /* DEBUG_AEC_REGS */ + } else { + /* + * case PCI_DEVICE_ID_ARTOP_ATP860: + * case PCI_DEVICE_ID_ARTOP_ATP860R: + * case PCI_DEVICE_ID_ARTOP_ATP865: + * case PCI_DEVICE_ID_ARTOP_ATP865R: + */ + (void) pci_read_config_byte(dev, 0x44, &art); + p += sprintf(p, "DMA Mode: %s(%s)", (c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO", - ((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?", + ((art&0x07)==0x07)?"6": + ((art&0x06)==0x06)?"5": + ((art&0x05)==0x05)?"4": + ((art&0x04)==0x04)?"3": + ((art&0x03)==0x03)?"2": + ((art&0x02)==0x02)?"1": + ((art&0x01)==0x01)?"0":"?"); + p += sprintf(p, " %s(%s)", (c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO", - ((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?"); - (void) pci_read_config_byte(bmide_dev, 0x45, &art); - p += sprintf(p, " %s(%s) %s(%s)\n", + ((art&0x70)==0x70)?"6": + ((art&0x60)==0x60)?"5": + ((art&0x50)==0x50)?"4": + ((art&0x40)==0x40)?"3": + ((art&0x30)==0x30)?"2": + ((art&0x20)==0x20)?"1": + ((art&0x10)==0x10)?"0":"?"); + (void) pci_read_config_byte(dev, 0x45, &art); + p += sprintf(p, " %s(%s)", (c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO", - ((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?", + ((art&0x07)==0x07)?"6": + ((art&0x06)==0x06)?"5": + ((art&0x05)==0x05)?"4": + ((art&0x04)==0x04)?"3": + ((art&0x03)==0x03)?"2": + ((art&0x02)==0x02)?"1": + ((art&0x01)==0x01)?"0":"?"); + p += sprintf(p, " %s(%s)\n", (c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO", - ((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?"); - (void) pci_read_config_byte(bmide_dev, 0x40, &art); + ((art&0x70)==0x70)?"6": + ((art&0x60)==0x60)?"5": + ((art&0x50)==0x50)?"4": + ((art&0x40)==0x40)?"3": + ((art&0x30)==0x30)?"2": + ((art&0x20)==0x20)?"1": + ((art&0x10)==0x10)?"0":"?"); +#ifdef DEBUG_AEC_REGS + (void) pci_read_config_byte(dev, 0x40, &art); p += sprintf(p, "Active: 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(bmide_dev, 0x41, &art); + (void) pci_read_config_byte(dev, 0x41, &art); p += sprintf(p, " 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(bmide_dev, 0x42, &art); + (void) pci_read_config_byte(dev, 0x42, &art); p += sprintf(p, " 0x%02x", HIGH_4(art)); - (void) pci_read_config_byte(bmide_dev, 0x43, &art); + (void) pci_read_config_byte(dev, 0x43, &art); p += sprintf(p, " 0x%02x\n", HIGH_4(art)); - (void) pci_read_config_byte(bmide_dev, 0x40, &art); + (void) pci_read_config_byte(dev, 0x40, &art); p += sprintf(p, "Recovery: 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(bmide_dev, 0x41, &art); + (void) pci_read_config_byte(dev, 0x41, &art); p += sprintf(p, " 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(bmide_dev, 0x42, &art); + (void) pci_read_config_byte(dev, 0x42, &art); p += sprintf(p, " 0x%02x", LOW_4(art)); - (void) pci_read_config_byte(bmide_dev, 0x43, &art); + (void) pci_read_config_byte(dev, 0x43, &art); p += sprintf(p, " 0x%02x\n", LOW_4(art)); - (void) pci_read_config_byte(bmide_dev, 0x49, &uart); + (void) pci_read_config_byte(dev, 0x49, &uart); p += sprintf(p, "reg49h = 0x%02x ", uart); - (void) pci_read_config_byte(bmide_dev, 0x4a, &uart); + (void) pci_read_config_byte(dev, 0x4a, &uart); p += sprintf(p, "reg4ah = 0x%02x\n", uart); - break; - default: - break; +#endif /* DEBUG_AEC_REGS */ + } } - return p-buffer;/* => must be less than 4k! */ } #endif /* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */ byte aec62xx_proc = 0; -#ifdef CONFIG_AEC62XX_TUNING - struct chipset_bus_clock_list_entry { byte xfer_speed; - - byte chipset_settings_34; - byte ultra_settings_34; - - byte chipset_settings_33; - byte ultra_settings_33; + byte chipset_settings; + byte ultra_settings; }; -struct chipset_bus_clock_list_entry aec62xx_base [] = { +struct chipset_bus_clock_list_entry aec6xxx_33_base [] = { #ifdef CONFIG_BLK_DEV_IDEDMA - { XFER_UDMA_4, 0x41, 0x04, 0x31, 0x05 }, - { XFER_UDMA_3, 0x41, 0x03, 0x31, 0x04 }, - { XFER_UDMA_2, 0x41, 0x02, 0x31, 0x03 }, - { XFER_UDMA_1, 0x41, 0x01, 0x31, 0x02 }, - { XFER_UDMA_0, 0x41, 0x01, 0x31, 0x01 }, - - { XFER_MW_DMA_2, 0x41, 0x00, 0x31, 0x00 }, - { XFER_MW_DMA_1, 0x42, 0x00, 0x31, 0x00 }, - { XFER_MW_DMA_0, 0x7a, 0x00, 0x0a, 0x00 }, + { XFER_UDMA_6, 0x31, 0x07 }, + { XFER_UDMA_5, 0x31, 0x06 }, + { XFER_UDMA_4, 0x31, 0x05 }, + { XFER_UDMA_3, 0x31, 0x04 }, + { XFER_UDMA_2, 0x31, 0x03 }, + { XFER_UDMA_1, 0x31, 0x02 }, + { XFER_UDMA_0, 0x31, 0x01 }, + + { XFER_MW_DMA_2, 0x31, 0x00 }, + { XFER_MW_DMA_1, 0x31, 0x00 }, + { XFER_MW_DMA_0, 0x0a, 0x00 }, #endif /* CONFIG_BLK_DEV_IDEDMA */ - { XFER_PIO_4, 0x41, 0x00, 0x31, 0x00 }, - { XFER_PIO_3, 0x43, 0x00, 0x33, 0x00 }, - { XFER_PIO_2, 0x78, 0x00, 0x08, 0x00 }, - { XFER_PIO_1, 0x7a, 0x00, 0x0a, 0x00 }, - { XFER_PIO_0, 0x70, 0x00, 0x00, 0x00 }, - { 0, 0x00, 0x00, 0x00, 0x00 } + { XFER_PIO_4, 0x31, 0x00 }, + { XFER_PIO_3, 0x33, 0x00 }, + { XFER_PIO_2, 0x08, 0x00 }, + { XFER_PIO_1, 0x0a, 0x00 }, + { XFER_PIO_0, 0x00, 0x00 }, + { 0, 0x00, 0x00 } }; -extern char *ide_xfer_verbose (byte xfer_rate); +struct chipset_bus_clock_list_entry aec6xxx_34_base [] = { +#ifdef CONFIG_BLK_DEV_IDEDMA + { XFER_UDMA_6, 0x41, 0x06 }, + { XFER_UDMA_5, 0x41, 0x05 }, + { XFER_UDMA_4, 0x41, 0x04 }, + { XFER_UDMA_3, 0x41, 0x03 }, + { XFER_UDMA_2, 0x41, 0x02 }, + { XFER_UDMA_1, 0x41, 0x01 }, + { XFER_UDMA_0, 0x41, 0x01 }, + + { XFER_MW_DMA_2, 0x41, 0x00 }, + { XFER_MW_DMA_1, 0x42, 0x00 }, + { XFER_MW_DMA_0, 0x7a, 0x00 }, +#endif /* CONFIG_BLK_DEV_IDEDMA */ + { XFER_PIO_4, 0x41, 0x00 }, + { XFER_PIO_3, 0x43, 0x00 }, + { XFER_PIO_2, 0x78, 0x00 }, + { XFER_PIO_1, 0x7a, 0x00 }, + { XFER_PIO_0, 0x70, 0x00 }, + { 0, 0x00, 0x00 } +}; /* * TO DO: active tuning and correction of cards without a bios. @@ -203,31 +257,73 @@ static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) { - int bus_speed = system_bus_clock(); - for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { - return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34)); + return chipset_table->chipset_settings; } - return 0x00; + return chipset_table->chipset_settings; } static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table) { - int bus_speed = system_bus_clock(); - for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { - return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34)); + return chipset_table->ultra_settings; } - return 0x00; + return chipset_table->ultra_settings; +} + +static byte aec62xx_ratemask (ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = 0x00; + + if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { + mode |= 0x01; + } else if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP860) || + (dev->device == PCI_DEVICE_ID_ARTOP_ATP860R)) { + mode |= 0x02; + } else if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) || + (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) { + u32 bmide = pci_resource_start(dev, 4); + if (IN_BYTE(bmide+2) & 0x10) + mode |= 0x04; + else + mode |= 0x03; + } + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte aec62xx_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + byte mode = aec62xx_ratemask(drive); + + switch(mode) { + case 0x04: while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; } -static int aec6210_tune_chipset (ide_drive_t *drive, byte speed) +static int aec6210_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int err = 0; + byte speed = aec62xx_ratefilter(drive, xferspeed); unsigned short d_conf = 0x0000; byte ultra = 0x00; byte ultra_conf = 0x00; @@ -236,11 +332,10 @@ byte tmp2 = 0x00; unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - + local_irq_save(flags); pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf); - tmp0 = pci_bus_clock_list(speed, aec62xx_base); + tmp0 = pci_bus_clock_list(speed, + (struct chipset_bus_clock_list_entry *) dev->driver_data); SPLIT_BYTE(tmp0,tmp1,tmp2); MAKE_WORD(d_conf,tmp1,tmp2); pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf); @@ -249,23 +344,21 @@ tmp2 = 0x00; pci_read_config_byte(dev, 0x54, &ultra); tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn)))); - ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base); + ultra_conf = pci_bus_clock_list_ultra(speed, + (struct chipset_bus_clock_list_entry *) dev->driver_data); tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn)))); pci_write_config_byte(dev, 0x54, tmp2); - - __restore_flags(flags); /* local CPU only */ - - err = ide_config_drive_speed(drive, speed); - return(err); + local_irq_restore(flags); + return(ide_config_drive_speed(drive, speed)); } -static int aec6260_tune_chipset (ide_drive_t *drive, byte speed) +static int aec6260_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; byte unit = (drive->select.b.unit & 0x01); byte ultra_pci = hwif->channel ? 0x45 : 0x44; - int err = 0; + byte speed = aec62xx_ratefilter(drive, xferspeed); byte drive_conf = 0x00; byte ultra_conf = 0x00; byte ultra = 0x00; @@ -273,143 +366,91 @@ byte tmp2 = 0x00; unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - + local_irq_save(flags); pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf); - drive_conf = pci_bus_clock_list(speed, aec62xx_base); + drive_conf = pci_bus_clock_list(speed, + (struct chipset_bus_clock_list_entry *) dev->driver_data); pci_write_config_byte(dev, 0x40|drive->dn, drive_conf); pci_read_config_byte(dev, ultra_pci, &ultra); tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit)))); - ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base); + ultra_conf = pci_bus_clock_list_ultra(speed, + (struct chipset_bus_clock_list_entry *) dev->driver_data); tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit)))); pci_write_config_byte(dev, ultra_pci, tmp2); - __restore_flags(flags); /* local CPU only */ - - if (!drive->init_speed) - drive->init_speed = speed; - - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - return(err); + local_irq_restore(flags); + return(ide_config_drive_speed(drive, speed)); } - static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed) { - if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { - return ((int) aec6210_tune_chipset(drive, speed)); - } else { - return ((int) aec6260_tune_chipset(drive, speed)); + switch (HWIF(drive)->pci_dev->device) { + case PCI_DEVICE_ID_ARTOP_ATP865: + case PCI_DEVICE_ID_ARTOP_ATP865R: + case PCI_DEVICE_ID_ARTOP_ATP860: + case PCI_DEVICE_ID_ARTOP_ATP860R: + return ((int) aec6260_tune_chipset(drive, speed)); + case PCI_DEVICE_ID_ARTOP_ATP850UF: + return ((int) aec6210_tune_chipset(drive, speed)); + default: + return -1; } } #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra) +static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - byte unit = (drive->select.b.unit & 0x01); - unsigned long dma_base = hwif->dma_base; - byte speed = -1; - - if (drive->media != ide_disk) - return ((int) ide_dma_off_quietly); - - if (((id->dma_ultra & 0x0010) || - (id->dma_ultra & 0x0008) || - (id->dma_ultra & 0x0004)) && (ultra)) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (ultra)) { - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (ultra)) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); - } - - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - (void) aec6210_tune_chipset(drive, speed); - - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); -} - -static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra) -{ - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - byte unit = (drive->select.b.unit & 0x01); - unsigned long dma_base = hwif->dma_base; - byte speed = -1; - byte ultra66 = eighty_ninty_three(drive); + byte mode = aec62xx_ratemask(drive); + byte speed; if (drive->media != ide_disk) return ((int) ide_dma_off_quietly); - - if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) { - speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (ultra) && (ultra66)) { - speed = XFER_UDMA_3; - } else if ((id->dma_ultra & 0x0004) && (ultra)) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (ultra)) { - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (ultra)) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); + + switch(mode) { + case 0x04: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_6; break; } + case 0x03: + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + if (id->dma_1word & 0x0002) + { speed = XFER_SW_DMA_1; break; } + if (id->dma_1word & 0x0001) + { speed = XFER_SW_DMA_0; break; } + default: + return ((int) ide_dma_off_quietly); } - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - (void) aec6260_tune_chipset(drive, speed); + (void) aec62xx_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 11) & 15) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); -} - -static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) -{ - switch(HWIF(drive)->pci_dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP850UF: - return config_aec6210_chipset_for_dma(drive, ultra); - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: - return config_aec6260_chipset_for_dma(drive, ultra); - default: - return ((int) ide_dma_off_quietly); - } +// return ((int) ide_dma_on); } #endif /* CONFIG_BLK_DEV_IDEDMA */ @@ -427,16 +468,7 @@ case 1: speed = XFER_PIO_1; break; default: speed = XFER_PIO_0; break; } - - switch(HWIF(drive)->pci_dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP850UF: - (void) aec6210_tune_chipset(drive, speed); - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: - (void) aec6260_tune_chipset(drive, speed); - default: - break; - } + (void) aec62xx_tune_chipset(drive, speed); } #ifdef CONFIG_BLK_DEV_IDEDMA @@ -453,9 +485,9 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x001F) { + if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; @@ -465,7 +497,7 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } @@ -474,7 +506,7 @@ goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } else { @@ -494,49 +526,81 @@ */ int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); case ide_dma_lostirq: case ide_dma_timeout: - switch(HWIF(drive)->pci_dev->device) { + switch(dev->device) { case PCI_DEVICE_ID_ARTOP_ATP860: case PCI_DEVICE_ID_ARTOP_ATP860R: -// { -// int i = 0; -// byte reg49h = 0; -// pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, ®49h); -// for (i=0;i<256;i++) -// pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10); -// pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10); -// } -// return 0; + case PCI_DEVICE_ID_ARTOP_ATP865: + case PCI_DEVICE_ID_ARTOP_ATP865R: + printk(" AEC62XX time out "); +#if 0 + { + int i = 0; + byte reg49h = 0; + pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, ®49h); + for (i=0;i<256;i++) + pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10); + pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10); + } + return 0; +#endif default: break; } default: break; } +#if 0 + { + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + unsigned long dma_base = hwif->dma_base; + byte tmp1 = 0x00; + byte tmp2 = 0x00; + + pci_read_config_byte(dev, 0x44, &tmp1); + pci_read_config_byte(dev, 0x45, &tmp2); + printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2); + if (hwif->channel) + dma_base -= 0x08; + tmp1=IN_BYTE(dma_base+2) & 0x10; + printk(" AEC6280 133=%x ",tmp1); + } +#endif return ide_dmaproc(func, drive); /* use standard DMA stuff */ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -#endif /* CONFIG_AEC62XX_TUNING */ unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name) { + int bus_speed = system_bus_clock(); + if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } + aec_devs[n_aec_devs++] = dev; + #if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS) if (!aec62xx_proc) { aec62xx_proc = 1; - bmide_dev = dev; aec62xx_display_info = &aec62xx_get_info; } #endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */ + if (bus_speed <= 33) + dev->driver_data = (void *) aec6xxx_33_base; + else + dev->driver_data = (void *) aec6xxx_34_base; + return dev->irq; } @@ -551,32 +615,56 @@ void __init ide_init_aec62xx (ide_hwif_t *hwif) { -#ifdef CONFIG_AEC62XX_TUNING + hwif->autodma = 0; hwif->tuneproc = &aec62xx_tune_drive; hwif->speedproc = &aec62xx_tune_chipset; -#ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) - hwif->dmaproc = &aec62xx_dmaproc; -#else /* !CONFIG_BLK_DEV_IDEDMA */ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + return; + +#ifdef CONFIG_BLK_DEV_IDEDMA + hwif->dmaproc = &aec62xx_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* CONFIG_BLK_DEV_IDEDMA */ -#endif /* CONFIG_AEC62XX_TUNING */ + + } void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase) { -#ifdef CONFIG_AEC62XX_TUNING + struct pci_dev *dev = hwif->pci_dev; + byte reg54h = 0; unsigned long flags; - byte reg54h = 0; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + spin_lock_irqsave(&io_request_lock, flags); + pci_read_config_byte(dev, 0x54, ®54h); + pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F)); + spin_unlock_irqrestore(&io_request_lock, flags); + ide_setup_dma(hwif, dmabase, 8); +} - pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); - pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F)); +extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *); - __restore_flags(flags); /* local CPU only */ -#endif /* CONFIG_AEC62XX_TUNING */ - ide_setup_dma(hwif, dmabase, 8); +void __init fixup_device_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d) +{ + u32 bar4reg = pci_resource_start(dev, 4); + + if (IN_BYTE(bar4reg+2) & 0x10) { + strcpy(d->name, "AEC6880"); + if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) + strcpy(d->name, "AEC6880R"); + } else { + strcpy(d->name, "AEC6280"); + if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) + strcpy(d->name, "AEC6280R"); + } + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ali14xx.c linux.20pre2-ac1/drivers/ide/ali14xx.c --- linux.20pre2/drivers/ide/ali14xx.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ali14xx.c 2002-08-06 15:42:11.000000000 +0100 @@ -95,7 +95,7 @@ static inline byte inReg (byte reg) { outb_p(reg, regPort); - return inb(dataPort); + return IN_BYTE(dataPort); } /* @@ -137,15 +137,14 @@ /* stuff timing parameters into controller registers */ driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); outb_p(regOn, basePort); outReg(param1, regTab[driveNum].reg1); outReg(param2, regTab[driveNum].reg2); outReg(param3, regTab[driveNum].reg3); outReg(param4, regTab[driveNum].reg4); outb_p(regOff, basePort); - restore_flags(flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); } /* @@ -157,19 +156,18 @@ byte t; unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); for (i = 0; i < ALI_NUM_PORTS; ++i) { basePort = ports[i]; - regOff = inb(basePort); + regOff = IN_BYTE(basePort); for (regOn = 0x30; regOn <= 0x33; ++regOn) { outb_p(regOn, basePort); - if (inb(basePort) == regOn) { + if (IN_BYTE(basePort) == regOn) { regPort = basePort + 4; dataPort = basePort + 8; t = inReg(0) & 0xf0; outb_p(regOff, basePort); - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); if (t != 0x50) return 0; return 1; /* success */ @@ -177,7 +175,7 @@ } outb_p(regOff, basePort); } - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); return 0; } @@ -189,15 +187,14 @@ byte t; unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); outb_p(regOn, basePort); for (p = initData; p->reg != 0; ++p) outReg(p->data, p->reg); outb_p(0x01, regPort); - t = inb(regPort) & 0x01; + t = IN_BYTE(regPort) & 0x01; outb_p(regOff, basePort); - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); return t; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/alim15x3.c linux.20pre2-ac1/drivers/ide/alim15x3.c --- linux.20pre2/drivers/ide/alim15x3.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/alim15x3.c 2002-08-11 21:55:36.000000000 +0100 @@ -89,8 +89,8 @@ * at that point bibma+0x2 et bibma+0xa are byte * registers to investigate: */ - c0 = inb((unsigned short)bibma + 0x02); - c1 = inb((unsigned short)bibma + 0x0a); + c0 = IN_BYTE((unsigned short)bibma + 0x02); + c1 = IN_BYTE((unsigned short)bibma + 0x0a); p += sprintf(p, "\n Ali M15x3 Chipset.\n"); @@ -112,16 +112,20 @@ (reg53h & 0x80) ? " OVERRD." : "." ); p += sprintf(p, - "-------------------primary channel-------------------secondary channel---------\n\n"); + "-------------------primary channel" + "-------------------secondary channel" + "---------\n\n"); pci_read_config_byte(bmide_dev, 0x09, ®53h); p += sprintf(p, - "channel status: %s %s\n", + "channel status: %s" + " %s\n", (reg53h & 0x20) ? "On " : "Off", (reg53h & 0x10) ? "On " : "Off" ); p += sprintf(p, - "both channels togth: %s %s\n", + "both channels togth: %s" + " %s\n", (c0&0x80) ? "No " : "Yes", (c1&0x80) ? "No " : "Yes" ); @@ -134,24 +138,29 @@ pci_read_config_byte(bmide_dev, 0x58, ®5xh); pci_read_config_byte(bmide_dev, 0x5c, ®5yh); p += sprintf(p, - "Add. Setup Timing: %dT %dT\n", + "Add. Setup Timing: %dT" + " %dT\n", (reg5xh & 0x07) ? (reg5xh & 0x07) : 8, (reg5yh & 0x07) ? (reg5yh & 0x07) : 8 ); pci_read_config_byte(bmide_dev, 0x59, ®5xh); pci_read_config_byte(bmide_dev, 0x5d, ®5yh); p += sprintf(p, - "Command Act. Count: %dT %dT\n" - "Command Rec. Count: %dT %dT\n\n", + "Command Act. Count: %dT" + " %dT\n" + "Command Rec. Count: %dT" + " %dT\n\n", (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8, (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16, (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 ); p += sprintf(p, - "----------------drive0-----------drive1------------drive0-----------drive1------\n\n"); + "----------------drive0-----------drive1" + "------------drive0-----------drive1------\n\n"); p += sprintf(p, - "DMA enabled: %s %s %s %s\n", + "DMA enabled: %s %s" + " %s %s\n", (c0&0x20) ? "Yes" : "No ", (c0&0x40) ? "Yes" : "No ", (c1&0x20) ? "Yes" : "No ", @@ -159,7 +168,8 @@ pci_read_config_byte(bmide_dev, 0x54, ®5xh); pci_read_config_byte(bmide_dev, 0x55, ®5yh); - q = "FIFO threshold: %2d Words %2d Words %2d Words %2d Words\n"; + q = "FIFO threshold: %2d Words %2d Words" + " %2d Words %2d Words\n"; if (rev < 0xc1) { if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) { p += sprintf(p, q, 8, 8, 8, 8); @@ -180,7 +190,8 @@ #if 0 p += sprintf(p, - "FIFO threshold: %2d Words %2d Words %2d Words %2d Words\n", + "FIFO threshold: %2d Words %2d Words" + " %2d Words %2d Words\n", (reg5xh & 0x03) + 12, ((reg5xh & 0x30)>>4) + 12, (reg5yh & 0x03) + 12, @@ -200,9 +211,12 @@ pci_read_config_byte(bmide_dev, 0x5f, ®5yh1); p += sprintf(p,/* - "------------------drive0-----------drive1------------drive0-----------drive1------\n")*/ - "Dt RW act. Cnt %2dT %2dT %2dT %2dT\n" - "Dt RW rec. Cnt %2dT %2dT %2dT %2dT\n\n", + "------------------drive0-----------drive1" + "------------drive0-----------drive1------\n")*/ + "Dt RW act. Cnt %2dT %2dT" + " %2dT %2dT\n" + "Dt RW rec. Cnt %2dT %2dT" + " %2dT %2dT\n\n", (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8, (reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8, (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, @@ -213,13 +227,16 @@ (reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 ); p += sprintf(p, - "-----------------------------------UDMA Timings--------------------------------\n\n"); + "-----------------------------------UDMA Timings" + "--------------------------------\n\n"); pci_read_config_byte(bmide_dev, 0x56, ®5xh); pci_read_config_byte(bmide_dev, 0x57, ®5yh); p += sprintf(p, - "UDMA: %s %s %s %s\n" - "UDMA timings: %s %s %s %s\n\n", + "UDMA: %s %s" + " %s %s\n" + "UDMA timings: %s %s" + " %s %s\n\n", (reg5xh & 0x08) ? "OK" : "No", (reg5xh & 0x80) ? "OK" : "No", (reg5yh & 0x08) ? "OK" : "No", @@ -248,7 +265,7 @@ byte s_clc, a_clc, r_clc; unsigned long flags; int bus_speed = system_bus_clock(); - int port = hwif->index ? 0x5c : 0x58; + int port = hwif->channel ? 0x5c : 0x58; int portFIFO = hwif->channel ? 0x55 : 0x54; byte cd_dma_fifo = 0; @@ -272,21 +289,20 @@ if (r_clc >= 16) r_clc = 0; } - __save_flags(flags); - __cli(); + local_irq_save(flags); /* * PIO mode => ATA FIFO on, ATAPI FIFO off */ pci_read_config_byte(dev, portFIFO, &cd_dma_fifo); if (drive->media==ide_disk) { - if (hwif->index) { + if (hwif->channel) { pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50); } else { pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05); } } else { - if (hwif->index) { + if (hwif->channel) { pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F); } else { pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0); @@ -295,7 +311,7 @@ pci_write_config_byte(dev, port, s_clc); pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc); - __restore_flags(flags); + local_irq_restore(flags); /* * setup active rec @@ -309,14 +325,79 @@ } -static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed) +static byte ali15x3_can_ultra (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); +#ifndef CONFIG_WDC_ALI15X3 + struct hd_driveid *id = drive->id; +#endif /* CONFIG_WDC_ALI15X3 */ + + if (m5229_revision <= 0x20) { + return 0; + } else if ((m5229_revision < 0xC2) && +#ifndef CONFIG_WDC_ALI15X3 + ((chip_is_1543c_e && strstr(id->model, "WDC ")) || + (drive->media!=ide_disk))) { +#else /* CONFIG_WDC_ALI15X3 */ + (drive->media!=ide_disk)) { +#endif /* CONFIG_WDC_ALI15X3 */ + return 0; + } else { + return 1; + } +} + +static byte ali15x3_ratemask (ide_drive_t *drive) +{ +// struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = 0x00; + byte can_ultra = ali15x3_can_ultra(drive); + + if ((m5229_revision >= 0xC4) && (can_ultra)) { + mode |= 0x03; + } else if ((m5229_revision >= 0xC2) && (can_ultra)) { + mode |= 0x02; + } else if (can_ultra) { + mode |= 0x01; + } else { + return (mode &= ~0xFF); + } + + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte ali15x3_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + byte mode = ali15x3_ratemask(drive); + + switch(mode) { + case 0x04: while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + +static int ali15x3_tune_chipset (ide_drive_t *drive, byte xferspeed) +{ + ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; + byte speed = ali15x3_ratefilter(drive, xferspeed); byte unit = (drive->select.b.unit & 0x01); byte tmpbyte = 0x00; - int m5229_udma = hwif->channel? 0x57 : 0x56; - int err = 0; + int m5229_udma = (hwif->channel) ? 0x57 : 0x56; if (speed < XFER_UDMA_0) { byte ultra_enable = (unit) ? 0x7f : 0xf7; @@ -326,18 +407,11 @@ pci_read_config_byte(dev, m5229_udma, &tmpbyte); tmpbyte &= ultra_enable; pci_write_config_byte(dev, m5229_udma, tmpbyte); - } - - err = ide_config_drive_speed(drive, speed); + if (speed < XFER_SW_DMA_0) + ali15x3_tune_drive(drive, speed); #ifdef CONFIG_BLK_DEV_IDEDMA - if (speed >= XFER_SW_DMA_0) { - unsigned long dma_base = hwif->dma_base; - - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - } - - if (speed >= XFER_UDMA_0) { + } else { pci_read_config_byte(dev, m5229_udma, &tmpbyte); tmpbyte &= (0x0f << ((1-unit) << 2)); /* @@ -350,89 +424,58 @@ tmpbyte |= 1; pci_write_config_byte(dev, 0x4b, tmpbyte); } - } #endif /* CONFIG_BLK_DEV_IDEDMA */ - - drive->current_speed = speed; - - return (err); -} - -static void config_chipset_for_pio (ide_drive_t *drive) -{ - ali15x3_tune_drive(drive, 5); + } + return (ide_config_drive_speed(drive, speed)); } #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33) +static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - byte speed = 0x00; - byte ultra66 = eighty_ninty_three(drive); - byte ultra100 = (m5229_revision>=0xc4) ? 1 : 0; - int rval; - - if ((id->dma_ultra & 0x0020) && (ultra100) && (ultra66) && (ultra33)) { - speed = XFER_UDMA_5; - } else if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) { - speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (ultra66) && (ultra33)) { - speed = XFER_UDMA_3; - } else if ((id->dma_ultra & 0x0004) && (ultra33)) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (ultra33)) { - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (ultra33)) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); + byte mode = ali15x3_ratemask(drive); + byte speed = 0; + + switch(mode) { + case 0x03: + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + if (id->dma_1word & 0x0002) + { speed = XFER_SW_DMA_1; break; } + if (id->dma_1word & 0x0001) + { speed = XFER_SW_DMA_0; break; } + default: + return ((int) ide_dma_off_quietly); } (void) ali15x3_tune_chipset(drive, speed); - - if (!drive->init_speed) - drive->init_speed = speed; - - rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : +// return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly); + return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); - - return rval; -} - -static byte ali15x3_can_ultra (ide_drive_t *drive) -{ -#ifndef CONFIG_WDC_ALI15X3 - struct hd_driveid *id = drive->id; -#endif /* CONFIG_WDC_ALI15X3 */ - - if (m5229_revision <= 0x20) { - return 0; - } else if ((m5229_revision < 0xC2) && -#ifndef CONFIG_WDC_ALI15X3 - ((chip_is_1543c_e && strstr(id->model, "WDC ")) || - (drive->media!=ide_disk))) { -#else /* CONFIG_WDC_ALI15X3 */ - (drive->media!=ide_disk)) { -#endif /* CONFIG_WDC_ALI15X3 */ - return 0; - } else { - return 1; - } } static int ali15x3_config_drive_for_dma(ide_drive_t *drive) @@ -440,11 +483,12 @@ struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); ide_dma_action_t dma_func = ide_dma_on; - byte can_ultra_dma = ali15x3_can_ultra(drive); if ((m5229_revision<=0x20) && (drive->media!=ide_disk)) return hwif->dmaproc(ide_dma_off_quietly, drive); + drive->init_speed = 0; + if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { @@ -455,7 +499,7 @@ if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) { if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, can_ultra_dma); + dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; @@ -465,7 +509,7 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, can_ultra_dma); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } @@ -474,7 +518,7 @@ goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, can_ultra_dma); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } else { @@ -484,7 +528,7 @@ fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - config_chipset_for_pio(drive); + hwif->tuneproc(drive, 5); } return hwif->dmaproc(dma_func, drive); } @@ -495,7 +539,8 @@ case ide_dma_check: return ali15x3_config_drive_for_dma(drive); case ide_dma_write: - if ((m5229_revision < 0xC2) && (drive->media != ide_disk)) + if ((m5229_revision < 0xC2) && + (drive->media != ide_disk)) return 1; /* try PIO instead of DMA */ break; default: @@ -505,10 +550,19 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ +#define ALI_INIT_CODE_TEST + unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name) { unsigned long fixdma_base = pci_resource_start(dev, 4); +#ifdef ALI_INIT_CODE_TEST + unsigned long flags; + byte tmpbyte; + struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0)); + int program_79 = 1; +#endif /* ALI_INIT_CODE_TEST */ + pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision); isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); @@ -521,9 +575,9 @@ /* * enable DMA capable bit, and "not" simplex only */ - outb(inb(fixdma_base+2) & 0x60, fixdma_base+2); + OUT_BYTE(IN_BYTE(fixdma_base+2) & 0x60, fixdma_base+2); - if (inb(fixdma_base+2) & 0x80) + if (IN_BYTE(fixdma_base+2) & 0x80) printk("%s: simplex device: DMA will fail!!\n", name); } @@ -535,6 +589,61 @@ } #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ +#ifdef ALI_INIT_CODE_TEST + + if(north->vendor != PCI_VENDOR_ID_AL) + program_79 = 0; + + local_irq_save(flags); + + if (m5229_revision >= 0xC2) { + /* + * 1543C-B?, 1535, 1535D, 1553 + * Note 1: not all "motherboard" support this detection + * Note 2: if no udma 66 device, the detection may "error". + * but in this case, we will not set the device to + * ultra 66, the detection result is not important + */ + + /* + * enable "Cable Detection", m5229, 0x4b, bit3 + */ + pci_read_config_byte(dev, 0x4b, &tmpbyte); + pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08); + + if(program_79) + { + /* + * set south-bridge's enable bit, m1533, 0x79 + */ + pci_read_config_byte(isa_dev, 0x79, &tmpbyte); + if (m5229_revision == 0xC2) { + /* + * 1543C-B0 (m1533, 0x79, bit 2) + */ + pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04); + } else if (m5229_revision >= 0xC3) { + /* + * 1553/1535 (m1533, 0x79, bit 1) + */ + pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02); + } + } + } else { + /* + * revision 0x20 (1543-E, 1543-F) + * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E) + * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7 + */ + pci_read_config_byte(dev, 0x4b, &tmpbyte); + /* + * clear bit 7 + */ + pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F); + } + + local_irq_save(flags); +#endif /* ALI_INIT_CODE_TEST */ return 0; } @@ -552,10 +661,10 @@ unsigned long flags; byte tmpbyte; - __save_flags(flags); - __cli(); + local_irq_save(flags); if (m5229_revision >= 0xC2) { +#ifndef ALI_INIT_CODE_TEST /* * 1543C-B?, 1535, 1535D, 1553 * Note 1: not all "motherboard" support this detection @@ -585,6 +694,7 @@ */ pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02); } +#endif /* ALI_INIT_CODE_TEST */ /* * Ultra66 cable detection (from Host View) * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin @@ -605,6 +715,7 @@ */ ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0]; } else { +#ifndef ALI_INIT_CODE_TEST /* * revision 0x20 (1543-E, 1543-F) * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E) @@ -615,6 +726,7 @@ * clear bit 7 */ pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F); +#endif /* ALI_INIT_CODE_TEST */ /* * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010 */ @@ -633,7 +745,7 @@ pci_write_config_byte(dev, 0x53, tmpbyte); - __restore_flags(flags); + local_irq_restore(flags); return(ata66); } @@ -657,7 +769,8 @@ ideic = ideic & 0x03; /* get IRQ for IDE Controller */ - if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) { + if ((hwif->channel && ideic == 0x03) || + (!hwif->channel && !ideic)) { /* * get SIRQ1 routing table */ @@ -675,25 +788,31 @@ } #endif /* CONFIG_SPARC64 */ + hwif->autodma = 0; hwif->tuneproc = &ali15x3_tune_drive; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->speedproc = &ali15x3_tune_chipset; + if (!hwif->dma_base) + return; + #ifdef CONFIG_BLK_DEV_IDEDMA - if ((hwif->dma_base) && (m5229_revision >= 0x20)) { + if (m5229_revision >= 0x20) { /* * M1543C or newer for DMAing */ hwif->dmaproc = &ali15x3_dmaproc; - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; } - - if (noautodma) - hwif->autodma = 0; -#else - hwif->autodma = 0; #endif /* CONFIG_BLK_DEV_IDEDMA */ + + /* Don't use LBA48 on ALi devices before rev 0xC5 */ + + if(m5229_revision <= 0xC4) + hwif->addressing = 1; + } void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) @@ -703,3 +822,16 @@ } ide_setup_dma(hwif, dmabase, 8); } + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_ali15x3 (struct pci_dev *dev, ide_pci_device_t *d) +{ + if (dev->resource[0].start != 0x01F1) + ide_register_xp_fix(dev); + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/amd74xx.c linux.20pre2-ac1/drivers/ide/amd74xx.c --- linux.20pre2/drivers/ide/amd74xx.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/amd74xx.c 2002-08-06 15:42:11.000000000 +0100 @@ -34,7 +34,6 @@ static int amd74xx_get_info(char *, char **, off_t, int); extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count) @@ -47,16 +46,22 @@ * at that point bibma+0x2 et bibma+0xa are byte registers * to investigate: */ - c0 = inb_p((unsigned short)bibma + 0x02); - c1 = inb_p((unsigned short)bibma + 0x0a); + c0 = IN_BYTE((unsigned short)bibma + 0x02); + c1 = IN_BYTE((unsigned short)bibma + 0x0a); - p += sprintf(p, "\n AMD %04X VIPER Chipset.\n", bmide_dev->device); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", + p += sprintf(p, "\n " + "AMD %04X VIPER Chipset.\n", bmide_dev->device); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", (c0&0x80) ? "dis" : " en", (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s " + " %s %s\n", (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); p += sprintf(p, "UDMA\n"); @@ -69,40 +74,85 @@ byte amd74xx_proc = 0; -extern char *ide_xfer_verbose (byte xfer_rate); +static int amd74xx_mode5_check (struct pci_dev *dev) +{ + switch(dev->device) { + case PCI_DEVICE_ID_AMD_VIPER_7411: + case PCI_DEVICE_ID_AMD_VIPER_7441: + return 1; + default: + return 0; + } +} static unsigned int amd74xx_swdma_check (struct pci_dev *dev) { unsigned int class_rev; - if ((dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) || - (dev->device == PCI_DEVICE_ID_AMD_VIPER_7441)) - return 0; + if (amd74xx_mode5_check(dev)) + return 1; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; return ((int) (class_rev >= 7) ? 1 : 0); } -static int amd74xx_swdma_error(ide_drive_t *drive) +static int amd74xx_swdma_error (ide_drive_t *drive) { printk("%s: single-word DMA not support (revision < C4)\n", drive->name); return 0; } +static byte amd74xx_ratemask (ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = 0x00; + + switch(dev->device) { + case PCI_DEVICE_ID_AMD_VIPER_7441: + case PCI_DEVICE_ID_AMD_VIPER_7411: { mode |= 0x03; break; } + case PCI_DEVICE_ID_AMD_VIPER_7409: { mode |= 0x02; break; } + case PCI_DEVICE_ID_AMD_COBRA_7401: { mode |= 0x01; break; } + default: + return (mode &= ~0xFF); + } + + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte amd74xx_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + byte mode = amd74xx_ratemask(drive); + + switch(mode) { + case 0x04: // while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + /* * Here is where all the hard work goes to program the chipset. - * */ -static int amd74xx_tune_chipset (ide_drive_t *drive, byte speed) +static int amd74xx_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int err = 0; - byte unit = (drive->select.b.unit & 0x01); -#ifdef CONFIG_BLK_DEV_IDEDMA - unsigned long dma_base = hwif->dma_base; -#endif /* CONFIG_BLK_DEV_IDEDMA */ + byte speed = amd74xx_ratefilter(drive, xferspeed); byte drive_pci = 0x00; byte drive_pci2 = 0x00; byte ultra_timing = 0x00; @@ -122,20 +172,10 @@ pci_read_config_byte(dev, drive_pci2, &dma_pio_timing); pci_read_config_byte(dev, 0x4c, &pio_timing); -#ifdef DEBUG - printk("%s:%d: Speed 0x%02x UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", - drive->name, drive->dn, speed, ultra_timing, dma_pio_timing, pio_timing); -#endif - ultra_timing &= ~0xC7; dma_pio_timing &= ~0xFF; pio_timing &= ~(0x03 << drive->dn); -#ifdef DEBUG - printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", - drive->name, ultra_timing, dma_pio_timing, pio_timing); -#endif - switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_7: @@ -162,7 +202,7 @@ dma_pio_timing |= 0x20; break; case XFER_UDMA_0: - ultra_timing |= 0x42; + ultra_timing |= 0x42; dma_pio_timing |= 0x20; break; case XFER_MW_DMA_2: @@ -210,75 +250,19 @@ pio_timing |= (0x03 << drive->dn); - if (!drive->init_speed) - drive->init_speed = speed; - #ifdef CONFIG_BLK_DEV_IDEDMA pci_write_config_byte(dev, drive_pci, ultra_timing); #endif /* CONFIG_BLK_DEV_IDEDMA */ pci_write_config_byte(dev, drive_pci2, dma_pio_timing); pci_write_config_byte(dev, 0x4c, pio_timing); -#ifdef DEBUG - printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", - drive->name, ultra_timing, dma_pio_timing, pio_timing); -#endif - -#ifdef CONFIG_BLK_DEV_IDEDMA - if (speed > XFER_PIO_4) { - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - } else { - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - } -#endif /* CONFIG_BLK_DEV_IDEDMA */ - - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - return (err); -} - -static void config_chipset_for_pio (ide_drive_t *drive) -{ - unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; - unsigned short xfer_pio = drive->id->eide_pio_modes; - byte timing, speed, pio; - - pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - - if (xfer_pio> 4) - xfer_pio = 0; - - if (drive->id->eide_pio_iordy > 0) { - for (xfer_pio = 5; - xfer_pio>0 && - drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; - xfer_pio--); - } else { - xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : - (drive->id->eide_pio_modes & 2) ? 0x04 : - (drive->id->eide_pio_modes & 1) ? 0x03 : - (drive->id->tPIO & 2) ? 0x02 : - (drive->id->tPIO & 1) ? 0x01 : xfer_pio; - } - - timing = (xfer_pio >= pio) ? xfer_pio : pio; - - switch(timing) { - case 4: speed = XFER_PIO_4;break; - case 3: speed = XFER_PIO_3;break; - case 2: speed = XFER_PIO_2;break; - case 1: speed = XFER_PIO_1;break; - default: - speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - break; - } - (void) amd74xx_tune_chipset(drive, speed); - drive->current_speed = speed; + return (ide_config_drive_speed(drive, speed)); } static void amd74xx_tune_drive (ide_drive_t *drive, byte pio) { byte speed; + pio = ide_get_best_pio_mode(drive, pio, 5, NULL); switch(pio) { case 4: speed = XFER_PIO_4;break; case 3: speed = XFER_PIO_3;break; @@ -297,56 +281,69 @@ */ static int config_chipset_for_dma (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - struct hd_driveid *id = drive->id; - byte udma_66 = eighty_ninty_three(drive); - byte udma_100 = ((dev->device==PCI_DEVICE_ID_AMD_VIPER_7411)|| - (dev->device==PCI_DEVICE_ID_AMD_VIPER_7441)) ? 1 : 0; - byte speed = 0x00; + struct hd_driveid *id = drive->id; + byte mode = amd74xx_ratemask(drive); + byte swdma = amd74xx_swdma_check(HWIF(drive)->pci_dev); + byte speed = 0; int rval; - if (udma_100) - udma_66 = eighty_ninty_three(drive); - - if ((id->dma_ultra & 0x0020) && (udma_66) && (udma_100)) { - speed = XFER_UDMA_5; - } else if ((id->dma_ultra & 0x0010) && (udma_66)) { - speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (udma_66)) { - speed = XFER_UDMA_3; - } else if (id->dma_ultra & 0x0004) { - speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0002) { - speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0001) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); + amd74xx_tune_drive(drive, 5); + + switch(mode) { + case 0x04: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_6; break; } + case 0x03: + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } + if ((id->dma_1word & 0x0004) && (swdma)) + { speed = XFER_SW_DMA_2; break; } + if ((id->dma_1word & 0x0002) && (swdma)) + { speed = XFER_SW_DMA_1; break; } + if ((id->dma_1word & 0x0001) && (swdma)) + { speed = XFER_SW_DMA_0; break; } + default: + return ((int) ide_dma_off_quietly); } (void) amd74xx_tune_chipset(drive, speed); - - rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : +// return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly); + rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + (((id->dma_1word >> 8) & 7) && (swdma)) ? ide_dma_on : ide_dma_off_quietly); - return rval; } static int config_drive_xfer_rate (ide_drive_t *drive) { - struct hd_driveid *id = drive->id; + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); ide_dma_action_t dma_func = ide_dma_on; - if (id && (id->capability & 1) && HWIF(drive)->autodma) { + drive->init_speed = 0; + + if (id && (id->capability & 1) && hwif->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { dma_func = ide_dma_off; @@ -387,8 +384,7 @@ fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - - config_chipset_for_pio(drive); + amd74xx_tune_drive(drive, 5); } return HWIF(drive)->dmaproc(dma_func, drive); } @@ -426,9 +422,9 @@ /* * enable DMA capable bit, and "not" simplex only */ - outb(inb(fixdma_base+2) & 0x60, fixdma_base+2); + OUT_BYTE(IN_BYTE(fixdma_base+2) & 0x60, fixdma_base+2); - if (inb(fixdma_base+2) & 0x80) + if (IN_BYTE(fixdma_base+2) & 0x80) printk("%s: simplex device: DMA will fail!!\n", name); } #if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) @@ -488,22 +484,19 @@ hwif->tuneproc = &amd74xx_tune_drive; hwif->speedproc = &amd74xx_tune_chipset; -#ifndef CONFIG_BLK_DEV_IDEDMA - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - hwif->autodma = 0; - return; -#else - - if (hwif->dma_base) { - hwif->dmaproc = &amd74xx_dmaproc; - if (!noautodma) - hwif->autodma = 1; - } else { - hwif->autodma = 0; + if (!hwif->dma_base) { hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; + hwif->autodma = 0; + return; } + +#ifndef CONFIG_BLK_DEV_IDEDMA + hwif->dmaproc = &amd74xx_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* CONFIG_BLK_DEV_IDEDMA */ } @@ -511,3 +504,16 @@ { ide_setup_dma(hwif, dmabase, 8); } + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_amd74xx (struct pci_dev *dev, ide_pci_device_t *d) +{ + if (dev->resource[0].start != 0x01F1) + ide_register_xp_fix(dev); + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ataraid.c linux.20pre2-ac1/drivers/ide/ataraid.c --- linux.20pre2/drivers/ide/ataraid.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ataraid.c 2002-08-06 15:42:11.000000000 +0100 @@ -123,8 +123,7 @@ ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO); if (!ptr) { __set_current_state(TASK_RUNNING); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } return ptr; @@ -139,8 +138,7 @@ ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO); if (!ptr) { __set_current_state(TASK_RUNNING); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } return ptr; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/cmd640.c linux.20pre2-ac1/drivers/ide/cmd640.c --- linux.20pre2/drivers/ide/cmd640.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/cmd640.c 2002-08-06 15:42:11.000000000 +0100 @@ -217,11 +217,10 @@ { unsigned long flags; - save_flags(flags); - cli(); - outl_p((reg & 0xfc) | cmd640_key, 0xcf8); + spin_lock_irqsave(&io_request_lock, flags); + outb_p((reg & 0xfc) | cmd640_key, 0xcf8); outb_p(val, (reg & 3) | 0xcfc); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); } static byte get_cmd640_reg_pci1 (unsigned short reg) @@ -229,11 +228,10 @@ byte b; unsigned long flags; - save_flags(flags); - cli(); - outl_p((reg & 0xfc) | cmd640_key, 0xcf8); + spin_lock_irqsave(&io_request_lock, flags); + outb_p((reg & 0xfc) | cmd640_key, 0xcf8); b = inb_p((reg & 3) | 0xcfc); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return b; } @@ -243,12 +241,11 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); outb_p(0x10, 0xcf8); outb_p(val, cmd640_key + reg); outb_p(0, 0xcf8); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); } static byte get_cmd640_reg_pci2 (unsigned short reg) @@ -256,12 +253,11 @@ byte b; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); outb_p(0x10, 0xcf8); b = inb_p(cmd640_key + reg); outb_p(0, 0xcf8); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return b; } @@ -271,11 +267,10 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); outb_p(reg, cmd640_key); outb_p(val, cmd640_key + 4); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); } static byte get_cmd640_reg_vlb (unsigned short reg) @@ -283,11 +278,10 @@ byte b; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); outb_p(reg, cmd640_key); b = inb_p(cmd640_key + 4); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return b; } @@ -315,7 +309,9 @@ { get_cmd640_reg = get_cmd640_reg_pci1; put_cmd640_reg = put_cmd640_reg_pci1; - for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) { + for (cmd640_key = 0x80000000; + cmd640_key <= 0x8000f800; + cmd640_key += 0x800) { if (match_pci_cmd640_device()) return 1; /* success */ } @@ -364,8 +360,7 @@ { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */ udelay(100); @@ -373,11 +368,11 @@ outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */ udelay(100); if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return 0; /* nothing responded */ } } - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return 1; /* success */ } @@ -458,8 +453,7 @@ byte b; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); b = get_cmd640_reg(reg); if (mode) { /* want prefetch on? */ #if CMD640_PREFETCH_MASKS @@ -475,7 +469,7 @@ b |= prefetch_masks[index]; /* disable prefetch */ } put_cmd640_reg(reg, b); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); } /* @@ -576,8 +570,7 @@ /* * Now that everything is ready, program the new timings */ - save_flags (flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); /* * Program the address_setup clocks into ARTTIM reg, * and then the active/recovery counts into the DRWTIM reg @@ -586,7 +579,7 @@ setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f; put_cmd640_reg(arttim_regs[index], setup_count); put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count)); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); } /* @@ -692,6 +685,41 @@ #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ +static int pci_conf1(void) +{ + u32 tmp; + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + OUT_BYTE(0x01, 0xCFB); + tmp = inl(0xCF8); + outl(0x80000000, 0xCF8); + if (inl(0xCF8) == 0x80000000) { + outl(tmp, 0xCF8); + spin_unlock_irqrestore(&io_request_lock, flags); + return 1; + } + outl(tmp, 0xCF8); + spin_unlock_irqrestore(&io_request_lock, flags); + return 0; +} + +static int pci_conf2(void) +{ + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + OUT_BYTE(0x00, 0xCFB); + OUT_BYTE(0x00, 0xCF8); + OUT_BYTE(0x00, 0xCFA); + if (IN_BYTE(0xCF8) == 0x00 && IN_BYTE(0xCF8) == 0x00) { + spin_unlock_irqrestore(&io_request_lock, flags); + return 1; + } + spin_unlock_irqrestore(&io_request_lock, flags); + return 0; +} + /* * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c */ @@ -709,9 +737,11 @@ bus_type = "VLB"; } else { cmd640_vlb = 0; - if (probe_for_cmd640_pci1()) + /* Find out what kind of PCI probing is supported otherwise + Justin Gibbs will sulk.. */ + if (pci_conf1() && probe_for_cmd640_pci1()) bus_type = "PCI (type1)"; - else if (probe_for_cmd640_pci2()) + else if (pci_conf2() && probe_for_cmd640_pci2()) bus_type = "PCI (type2)"; else return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/cmd64x.c linux.20pre2-ac1/drivers/ide/cmd64x.c --- linux.20pre2/drivers/ide/cmd64x.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/cmd64x.c 2002-08-06 15:42:11.000000000 +0100 @@ -8,9 +8,10 @@ * Due to massive hardware bugs, UltraDMA is only supported * on the 646U2 and not on the 646U. * - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 1999-2000 Andre Hedrick + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1998 David S. Miller (davem@redhat.com) + * + * Copyright (C) 1999-2002 Andre Hedrick */ #include @@ -32,7 +33,7 @@ #define CMD_DEBUG 0 #if CMD_DEBUG -#define cmdprintk(x...) printk(##x) +#define cmdprintk(x...) printk(x) #else #define cmdprintk(x...) #endif @@ -85,82 +86,97 @@ #include #include +static char * print_cmd64x_get_info(char *, struct pci_dev *, int); +static char * print_sii_get_info(char *, struct pci_dev *, int); static int cmd64x_get_info(char *, char **, off_t, int); -static int cmd680_get_info(char *, char **, off_t, int); extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); -static struct pci_dev *bmide_dev; -static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) +byte cmd64x_proc = 0; + +#define CMD_MAX_DEVS 5 + +static struct pci_dev *cmd_devs[CMD_MAX_DEVS]; +static int n_cmd_devs; + +#undef DEBUG_CMD_REGS + +static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index) { - char *p = buffer; + char *p = buf; + u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0; /* primary */ u8 reg57 = 0, reg58 = 0, reg5b; /* secondary */ u8 reg72 = 0, reg73 = 0; /* primary */ u8 reg7a = 0, reg7b = 0; /* secondary */ u8 reg50 = 0, reg71 = 0; /* extra */ +#ifdef DEBUG_CMD_REGS u8 hi_byte = 0, lo_byte = 0; +#endif /* DEBUG_CMD_REGS */ - switch(bmide_dev->device) { - case PCI_DEVICE_ID_CMD_649: - p += sprintf(p, "\n CMD649 Chipset.\n"); - break; - case PCI_DEVICE_ID_CMD_648: - p += sprintf(p, "\n CMD648 Chipset.\n"); - break; - case PCI_DEVICE_ID_CMD_646: - p += sprintf(p, "\n CMD646 Chipset.\n"); - break; - case PCI_DEVICE_ID_CMD_643: - p += sprintf(p, "\n CMD643 Chipset.\n"); - break; - default: - p += sprintf(p, "\n CMD64? Chipse.\n"); - break; - } - (void) pci_read_config_byte(bmide_dev, CFR, ®50); - (void) pci_read_config_byte(bmide_dev, ARTTIM0, ®53); - (void) pci_read_config_byte(bmide_dev, DRWTIM0, ®54); - (void) pci_read_config_byte(bmide_dev, ARTTIM1, ®55); - (void) pci_read_config_byte(bmide_dev, DRWTIM1, ®56); - (void) pci_read_config_byte(bmide_dev, ARTTIM2, ®57); - (void) pci_read_config_byte(bmide_dev, DRWTIM2, ®58); - (void) pci_read_config_byte(bmide_dev, DRWTIM3, ®5b); - (void) pci_read_config_byte(bmide_dev, MRDMODE, ®71); - (void) pci_read_config_byte(bmide_dev, BMIDESR0, ®72); - (void) pci_read_config_byte(bmide_dev, UDIDETCR0, ®73); - (void) pci_read_config_byte(bmide_dev, BMIDESR1, ®7a); - (void) pci_read_config_byte(bmide_dev, UDIDETCR1, ®7b); - - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", - (reg72&0x80)?"dis":" en",(reg7a&0x80)?"dis":" en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (reg72&0x20)?"yes":"no ",(reg72&0x40)?"yes":"no ",(reg7a&0x20)?"yes":"no ",(reg7a&0x40)?"yes":"no "); - p += sprintf(p, "DMA Mode: %s(%s) %s(%s) %s(%s) %s(%s)\n", + p += sprintf(p, "\nController: %d\n", index); + p += sprintf(p, "CMD%x Chipset.\n", dev->device); + (void) pci_read_config_byte(dev, CFR, ®50); + (void) pci_read_config_byte(dev, ARTTIM0, ®53); + (void) pci_read_config_byte(dev, DRWTIM0, ®54); + (void) pci_read_config_byte(dev, ARTTIM1, ®55); + (void) pci_read_config_byte(dev, DRWTIM1, ®56); + (void) pci_read_config_byte(dev, ARTTIM2, ®57); + (void) pci_read_config_byte(dev, DRWTIM2, ®58); + (void) pci_read_config_byte(dev, DRWTIM3, ®5b); + (void) pci_read_config_byte(dev, MRDMODE, ®71); + (void) pci_read_config_byte(dev, BMIDESR0, ®72); + (void) pci_read_config_byte(dev, UDIDETCR0, ®73); + (void) pci_read_config_byte(dev, BMIDESR1, ®7a); + (void) pci_read_config_byte(dev, UDIDETCR1, ®7b); + + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", + (reg72&0x80)?"dis":" en", + (reg7a&0x80)?"dis":" en"); + p += sprintf(p, "--------------- drive0 " + "--------- drive1 -------- drive0 " + "---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s" + " %s %s\n", + (reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ", + (reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no "); + + p += sprintf(p, "DMA Mode: %s(%s) %s(%s)", (reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO", - (reg72&0x20)?( ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"): - ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"): - ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"): - ((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):"X"):"?", + (reg72&0x20)?( + ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"): + ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"): + ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"): + ((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"): + "X"):"?", (reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO", - (reg72&0x40)?( ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"): - ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"): - ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"): - ((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):"X"):"?", + (reg72&0x40)?( + ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"): + ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"): + ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"): + ((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"): + "X"):"?"); + p += sprintf(p, " %s(%s) %s(%s)\n", (reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO", - (reg7a&0x20)?( ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"): - ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"): - ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"): - ((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):"X"):"?", + (reg7a&0x20)?( + ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"): + ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"): + ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"): + ((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"): + "X"):"?", (reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO", - (reg7a&0x40)?( ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"): - ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"): - ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"): - ((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):"X"):"?" ); - p += sprintf(p, "PIO Mode: %s %s %s %s\n", - "?", "?", "?", "?"); + (reg7a&0x40)?( + ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"): + ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"): + ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"): + ((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"): + "X"):"?" ); + p += sprintf(p, "PIO Mode: %s %s" + " %s %s\n", + "?", "?", "?", "?"); p += sprintf(p, " %s %s\n", (reg50 & CFR_INTR_CH0) ? "interrupting" : "polling ", (reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling"); @@ -171,32 +187,58 @@ (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled", (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled"); +#ifdef DEBUG_CMD_REGS SPLIT_BYTE(reg50, hi_byte, lo_byte); - p += sprintf(p, "CFR = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg50, hi_byte, lo_byte); + p += sprintf(p, "CFR = 0x%02x, HI = 0x%02x, " + "LOW = 0x%02x\n", reg50, hi_byte, lo_byte); SPLIT_BYTE(reg57, hi_byte, lo_byte); - p += sprintf(p, "ARTTIM23 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg57, hi_byte, lo_byte); + p += sprintf(p, "ARTTIM23 = 0x%02x, HI = 0x%02x, " + "LOW = 0x%02x\n", reg57, hi_byte, lo_byte); SPLIT_BYTE(reg71, hi_byte, lo_byte); - p += sprintf(p, "MRDMODE = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg71, hi_byte, lo_byte); + p += sprintf(p, "MRDMODE = 0x%02x, HI = 0x%02x, " + "LOW = 0x%02x\n", reg71, hi_byte, lo_byte); +#endif /* DEBUG_CMD_REGS */ - return p-buffer; /* => must be less than 4k! */ + return (char *)p; } -static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count) +static char * print_sii_get_info (char *buf, struct pci_dev *dev, int index) +{ + char *p = buf; + + p += sprintf(p, "\nController: %d\n", index); + p += sprintf(p, "SII%x Chipset.\n", dev->device); + + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "PIO Mode: %s %s" + " %s %s\n", + "?", "?", "?", "?"); + return (char *)p; +} + +static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - p += sprintf(p, "\n CMD680 Chipset.\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "PIO Mode: %s %s %s %s\n", - "?", "?", "?", "?"); + int i; + + p += sprintf(p, "\n"); + for (i = 0; i < n_cmd_devs; i++) { + struct pci_dev *dev = cmd_devs[i]; + + if (dev->device <= PCI_DEVICE_ID_CMD_649) + p = print_cmd64x_get_info(p, dev, i); + else + p = print_sii_get_info(p, dev, i); + } return p-buffer; /* => must be less than 4k! */ } #endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */ -byte cmd64x_proc = 0; -byte cmd680_proc = 0; - /* * Registers and masks for easy access by drive index: */ @@ -212,6 +254,7 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count) { unsigned long flags; + struct pci_dev *dev = HWIF(drive)->pci_dev; ide_drive_t *drives = HWIF(drive)->drives; byte temp_b; static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; @@ -250,25 +293,29 @@ active_count &= 0xf; /* Remember, max value is 16 */ recovery_count = (int) recovery_counts[recovery_count]; - cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count); + cmdprintk("Final values = %d,%d,%d\n", + setup_count, active_count, recovery_count); /* * Now that everything is ready, program the new timings */ - __save_flags (flags); - __cli(); + local_irq_save(flags); /* * Program the address_setup clocks into ARTTIM reg, * and then the active/recovery counts into the DRWTIM reg */ - (void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b); - (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], + (void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b); + (void) pci_write_config_byte(dev, arttim_regs[channel][slave], ((byte) setup_count) | (temp_b & 0x3f)); - (void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave], + (void) pci_write_config_byte(dev, drwtim_regs[channel][slave], (byte) ((active_count << 4) | recovery_count)); - cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]); - cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]); - __restore_flags(flags); + cmdprintk ("Write %x to %x\n", + ((byte) setup_count) | (temp_b & 0x3f), + arttim_regs[channel][slave]); + cmdprintk ("Write %x to %x\n", + (byte) ((active_count << 4) | recovery_count), + drwtim_regs[channel][slave]); + local_irq_restore(flags); } /* @@ -292,7 +339,8 @@ case 9: /* set prefetch on */ mode_wanted &= 1; /*set_prefetch_mode(index, mode_wanted);*/ - cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis"); + cmdprintk("%s: %sabled cmd640 prefetch\n", + drive->name, mode_wanted ? "en" : "dis"); return; } @@ -301,8 +349,8 @@ cycle_time = d.cycle_time; /* - * I copied all this complicated stuff from cmd640.c and made a few minor changes. - * For now I am just going to pray that it is correct. + * I copied all this complicated stuff from cmd640.c and made a few + * minor changes. For now I am just going to pray that it is correct. */ if (pio_mode > 5) pio_mode = 5; @@ -332,17 +380,85 @@ * (using WIN_SETFEATURE) before continuing. * * But we do not, because: - * 1) this is the wrong place to do it (proper is do_special() in ide.c) + * 1) this is the wrong place to do it + * (proper is do_special() in ide.c) * 2) in practice this is rarely, if ever, necessary */ program_drive_counts (drive, setup_count, active_count, recovery_count); - cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, clocks=%d/%d/%d\n", + cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, " + "clocks=%d/%d/%d\n", drive->name, pio_mode, mode_wanted, cycle_time, d.overridden ? " (overriding vendor mode)" : "", setup_count, active_count, recovery_count); } +static byte cmd64x_ratemask (ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = 0x00; + + switch(dev->device) { + case PCI_DEVICE_ID_CMD_680: { mode |= 0x04; break; } + case PCI_DEVICE_ID_CMD_649: { mode |= 0x03; break; } + case PCI_DEVICE_ID_CMD_648: { mode |= 0x02; break; } + case PCI_DEVICE_ID_CMD_643: { mode |= 0x01; break; } + + case PCI_DEVICE_ID_CMD_646: + { + unsigned int class_rev = 0; + pci_read_config_dword(dev, + PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + /* + * UltraDMA only supported on PCI646U and PCI646U2, which + * correspond to revisions 0x03, 0x05 and 0x07 respectively. + * Actually, although the CMD tech support people won't + * tell me the details, the 0x03 revision cannot support + * UDMA correctly without hardware modifications, and even + * then it only works with Quantum disks due to some + * hold time assumptions in the 646U part which are fixed + * in the 646U2. + * + * So we only do UltraDMA on revision 0x05 and 0x07 chipsets. + */ + switch(class_rev) { + case 0x07: + case 0x05: { mode |= 0x01; break; } + case 0x03: + case 0x01: + default: { mode |= 0x00; break; } + } + } + } + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte cmd64x_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + byte mode = cmd64x_ratemask(drive); + + switch(mode) { + case 0x04: while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + static byte cmd680_taskfile_timing (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; @@ -422,35 +538,40 @@ cmd680_tuneproc(drive, set_pio); speed = XFER_PIO_0 + set_pio; - if (set_speed) { + if (set_speed) (void) ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - } } static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) { - if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) { - config_cmd680_chipset_for_pio(drive, set_speed); - } else { - config_cmd64x_chipset_for_pio(drive, set_speed); + switch(HWIF(drive)->pci_dev->device) { + case PCI_DEVICE_ID_CMD_680: + config_cmd680_chipset_for_pio(drive, set_speed); + return; + default: + break; } + config_cmd64x_chipset_for_pio(drive, set_speed); } -static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed) +static int cmd64x_tune_chipset (ide_drive_t *drive, byte xferspeed) { #ifdef CONFIG_BLK_DEV_IDEDMA ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int err = 0; u8 unit = (drive->select.b.unit & 0x01); u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0; u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0; u8 regU = 0; u8 regD = 0; +#endif /* CONFIG_BLK_DEV_IDEDMA */ - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return 1; + u8 speed = cmd64x_ratefilter(drive, xferspeed); + +#ifdef CONFIG_BLK_DEV_IDEDMA + if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) + return 1; (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); @@ -458,10 +579,12 @@ regU &= ~(unit ? 0xCA : 0x35); (void) pci_write_config_byte(dev, pciD, regD); (void) pci_write_config_byte(dev, pciU, regU); - (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_5: regU |= (unit ? 0x0A : 0x05); break; case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break; case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break; @@ -474,10 +597,6 @@ case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; -#else - int err = 0; - - switch(speed) { #endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break; case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break; @@ -491,33 +610,26 @@ #ifdef CONFIG_BLK_DEV_IDEDMA (void) pci_write_config_byte(dev, pciU, regU); -#endif /* CONFIG_BLK_DEV_IDEDMA */ - - err = ide_config_drive_speed(drive, speed); - - drive->current_speed = speed; - -#ifdef CONFIG_BLK_DEV_IDEDMA regD |= (unit ? 0x40 : 0x20); (void) pci_write_config_byte(dev, pciD, regD); #endif /* CONFIG_BLK_DEV_IDEDMA */ - return err; + return (ide_config_drive_speed(drive, speed)); } -static int cmd680_tune_chipset (ide_drive_t *drive, byte speed) +static int cmd680_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 addr_mask = (hwif->channel) ? 0x84 : 0x80; u8 unit = (drive->select.b.unit & 0x01); + u8 speed = cmd64x_ratefilter(drive, xferspeed); u8 dma_pci = 0; u8 udma_pci = 0; u8 mode_pci = 0; u8 scsc = 0; u16 ultra = 0; u16 multi = 0; - int err = 0; pci_read_config_byte(dev, addr_mask, &mode_pci); pci_read_config_byte(dev, 0x8A, &scsc); @@ -538,6 +650,11 @@ if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) { pci_write_config_byte(dev, 0x8A, scsc|0x01); pci_read_config_byte(dev, 0x8A, &scsc); +#if 0 + /* if 133 clock fails, switch to 2xbus clock */ + if (!(scsc & 0x01)) + pci_write_config_byte(dev, 0x8A, scsc|0x10); +#endif } switch(speed) { @@ -599,7 +716,6 @@ default: return 1; } - if (speed >= XFER_MW_DMA_0) config_cmd680_chipset_for_pio(drive, 0); @@ -615,117 +731,59 @@ pci_write_config_word(dev, dma_pci, multi); pci_write_config_word(dev, udma_pci, ultra); - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - return err; + return (ide_config_drive_speed(drive, speed)); } #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) +static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - + byte mode = cmd64x_ratemask(drive); byte speed = 0x00; byte set_pio = 0x00; - byte udma_33 = ((rev >= 0x05) || (ultra_66)) ? 1 : 0; - byte udma_66 = eighty_ninty_three(drive); - byte udma_100 = 0; int rval; - switch(dev->device) { - case PCI_DEVICE_ID_CMD_649: udma_100 = 1; break; - case PCI_DEVICE_ID_CMD_648: - case PCI_DEVICE_ID_CMD_646: - case PCI_DEVICE_ID_CMD_643: - default: - break; - } - if (drive->media != ide_disk) { - cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n"); + cmdprintk("CMD64X: drive->media != ide_disk at double check," + " inital check failed!!\n"); return ((int) ide_dma_off); } - /* UltraDMA only supported on PCI646U and PCI646U2, - * which correspond to revisions 0x03, 0x05 and 0x07 respectively. - * Actually, although the CMD tech support people won't - * tell me the details, the 0x03 revision cannot support - * UDMA correctly without hardware modifications, and even - * then it only works with Quantum disks due to some - * hold time assumptions in the 646U part which are fixed - * in the 646U2. - * So we only do UltraDMA on revision 0x05 and 0x07 chipsets. - */ - if ((id->dma_ultra & 0x0020) && (udma_100) && (udma_66) && (udma_33)) { - speed = XFER_UDMA_5; - } else if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) { - speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) { - speed = XFER_UDMA_3; - } else if ((id->dma_ultra & 0x0004) && (udma_33)) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (udma_33)) { - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (udma_33)) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; - } else { - set_pio = 1; - } - - if (!drive->init_speed) - drive->init_speed = speed; - - config_chipset_for_pio(drive, set_pio); - - if (set_pio) - return ((int) ide_dma_off_quietly); - - if (cmd64x_tune_chipset(drive, speed)) - return ((int) ide_dma_off); - - rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); - - return rval; -} - -static int config_cmd680_chipset_for_dma (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - byte udma_66 = eighty_ninty_three(drive); - byte speed = 0x00; - byte set_pio = 0x00; - int rval; - - if ((id->dma_ultra & 0x0040) && (udma_66)) speed = XFER_UDMA_6; - else if ((id->dma_ultra & 0x0020) && (udma_66)) speed = XFER_UDMA_5; - else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4; - else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3; - else if (id->dma_ultra & 0x0004) speed = XFER_UDMA_2; - else if (id->dma_ultra & 0x0002) speed = XFER_UDMA_1; - else if (id->dma_ultra & 0x0001) speed = XFER_UDMA_0; - else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; - else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; - else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; - else { - set_pio = 1; + switch(mode) { + case 0x04: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_6; break; } + case 0x03: + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + if (id->dma_1word & 0x0002) + { speed = XFER_SW_DMA_1; break; } + if (id->dma_1word & 0x0001) + { speed = XFER_SW_DMA_0; break; } + default: + { set_pio = 1; break; } } if (!drive->init_speed) @@ -736,7 +794,7 @@ if (set_pio) return ((int) ide_dma_off_quietly); - if (cmd680_tune_chipset(drive, speed)) + if (hwif->speedproc(drive, speed)) return ((int) ide_dma_off); rval = (int)( ((id->dma_ultra >> 14) & 3) ? ide_dma_on : @@ -745,50 +803,16 @@ ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); - return rval; -} -static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) -{ - if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) - return (config_cmd680_chipset_for_dma(drive)); - return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66)); + return rval; } static int cmd64x_config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - unsigned int class_rev = 0; - byte can_ultra_33 = 0; - byte can_ultra_66 = 0; - byte can_ultra_100 = 0; - byte can_ultra_133 = 0; ide_dma_action_t dma_func = ide_dma_on; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - switch(dev->device) { - case PCI_DEVICE_ID_CMD_680: - can_ultra_133 = 1; - case PCI_DEVICE_ID_CMD_649: - can_ultra_100 = 1; - case PCI_DEVICE_ID_CMD_648: - can_ultra_66 = 1; - case PCI_DEVICE_ID_CMD_643: - can_ultra_33 = 1; - break; - case PCI_DEVICE_ID_CMD_646: - can_ultra_33 = (class_rev >= 0x05) ? 1 : 0; - can_ultra_66 = 0; - can_ultra_100 = 0; - break; - default: - return hwif->dmaproc(ide_dma_off, drive); - } - if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma && (drive->media == ide_disk)) { /* Consult the list of known "bad" drives */ @@ -797,10 +821,10 @@ goto fast_ata_pio; } dma_func = ide_dma_off_quietly; - if ((id->field_valid & 4) && (can_ultra_33)) { + if ((id->field_valid & 4) && cmd64x_ratemask(drive)) { if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66); + dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; @@ -810,7 +834,7 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, class_rev, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } @@ -819,7 +843,7 @@ goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, class_rev, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } else { @@ -846,47 +870,64 @@ return ide_dmaproc(func, drive); } +static int cmd64x_alt_dma_status (struct pci_dev *dev) +{ + switch(dev->device) { + case PCI_DEVICE_ID_CMD_648: + case PCI_DEVICE_ID_CMD_649: + return 1; + default: + break; + } + return 0; +} + static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { byte dma_stat = 0; byte dma_alt_stat = 0; - byte mask = (HWIF(drive)->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; - unsigned long dma_base = HWIF(drive)->dma_base; - struct pci_dev *dev = HWIF(drive)->pci_dev; - byte jack_slap = ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0; + ide_hwif_t *hwif = HWIF(drive); + byte mask = (hwif->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; + unsigned long dma_base = hwif->dma_base; + struct pci_dev *dev = hwif->pci_dev; + byte alt_dma_stat = cmd64x_alt_dma_status(dev); switch (func) { case ide_dma_check: return cmd64x_config_drive_for_dma(drive); case ide_dma_end: /* returns 1 on error, 0 otherwise */ drive->waiting_for_dma = 0; - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - if (jack_slap) { + /* stop DMA */ + OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base); + /* get DMA status */ + dma_stat = IN_BYTE(dma_base+2); + /* clear the INTR & ERROR bits */ + OUT_BYTE(dma_stat|6, dma_base+2); + if (alt_dma_stat) { byte dma_intr = 0; - byte dma_mask = (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; - byte dma_reg = (HWIF(drive)->channel) ? ARTTIM2 : CFR; + byte dma_mask = (hwif->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; + byte dma_reg = (hwif->channel) ? ARTTIM2 : CFR; (void) pci_read_config_byte(dev, dma_reg, &dma_intr); - /* - * DAMN BMIDE is not connected to PCI space! - * Have to manually jack-slap that bitch! - * To allow the PCI side to read incoming interrupts. - */ - (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask); /* clear the INTR bit */ + /* clear the INTR bit */ + (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask); } - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (dma_stat & 7) != 4; /* verify good DMA status */ + /* purge DMA mappings */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + return (dma_stat & 7) != 4; case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); + dma_stat = IN_BYTE(dma_base+2); (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat); #ifdef DEBUG - printk("%s: dma_stat: 0x%02x dma_alt_stat: 0x%02x mask: 0x%02x\n", drive->name, dma_stat, dma_alt_stat, mask); + printk("%s: dma_stat: 0x%02x dma_alt_stat: " + "0x%02x mask: 0x%02x\n", drive->name, + dma_stat, dma_alt_stat, mask); #endif if (!(dma_alt_stat & mask)) { return 0; } - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ + /* return 1 if INTR asserted */ + return (dma_stat & 4) == 4; default: break; } @@ -909,11 +950,16 @@ return cmd64x_config_drive_for_dma(drive); case ide_dma_end: drive->waiting_for_dma = 0; - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - ide_destroy_dmatable(drive); /* and free any DMA resources */ - return (dma_stat & 7) != 4; /* verify good DMA status */ + /* get DMA status */ + dma_stat = IN_BYTE(dma_base+2); + /* stop DMA */ + OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base); + /* clear the INTR & ERROR bits */ + OUT_BYTE(dma_stat|6, dma_base+2); + /* and free any DMA resources */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + return (dma_stat & 7) != 4; default: break; } @@ -975,6 +1021,13 @@ pci_write_config_byte(dev, 0x84, 0x00); pci_read_config_byte(dev, 0x8A, &tmpbyte); pci_write_config_byte(dev, 0x8A, tmpbyte|0x01); +#if 0 + /* if 133 clock fails, switch to 2xbus clock */ + if (!(tmpbyte & 0x01)) { + pci_read_config_byte(dev, 0x8A, &tmpbyte); + pci_write_config_byte(dev, 0x8A, tmpbyte|0x10); + } +#endif pci_write_config_word(dev, 0xA2, 0x328A); pci_write_config_dword(dev, 0xA4, 0x328A); pci_write_config_dword(dev, 0xA8, 0x4392); @@ -984,13 +1037,15 @@ pci_write_config_dword(dev, 0xB8, 0x4392); pci_write_config_dword(dev, 0xBC, 0x4009); + cmd_devs[n_cmd_devs++] = dev; + #if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) if (!cmd64x_proc) { cmd64x_proc = 1; - bmide_dev = dev; - cmd64x_display_info = &cmd680_get_info; + cmd64x_display_info = &cmd64x_get_info; } #endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */ + return 0; } @@ -1072,10 +1127,11 @@ (void) pci_write_config_byte(dev, UDIDETCR0, 0xf0); #endif /* CONFIG_PPC */ + cmd_devs[n_cmd_devs++] = dev; + #if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) if (!cmd64x_proc) { cmd64x_proc = 1; - bmide_dev = dev; cmd64x_display_info = &cmd64x_get_info; } #endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */ @@ -1085,8 +1141,12 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name) { - if (dev->device == PCI_DEVICE_ID_CMD_680) - return cmd680_pci_init (dev, name); + switch(dev->device) { + case PCI_DEVICE_ID_CMD_680: + return cmd680_pci_init (dev, name); + default: + break; + } return cmd64x_pci_init (dev, name); } @@ -1110,9 +1170,12 @@ unsigned int __init ata66_cmd64x (ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; - if (dev->device == PCI_DEVICE_ID_CMD_680) - return cmd680_ata66(hwif); + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_CMD_680: + return cmd680_ata66(hwif); + default: + break; + } return cmd64x_ata66(hwif); } @@ -1127,14 +1190,13 @@ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; - if (!hwif->dma_base) - return; - -#ifdef CONFIG_BLK_DEV_IDEDMA switch(dev->device) { case PCI_DEVICE_ID_CMD_680: hwif->busproc = &cmd680_busproc; - hwif->dmaproc = &cmd680_dmaproc; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (hwif->dma_base) + hwif->dmaproc = &cmd680_dmaproc; +#endif /* CONFIG_BLK_DEV_IDEDMA */ hwif->resetproc = &cmd680_reset; hwif->speedproc = &cmd680_tune_chipset; hwif->tuneproc = &cmd680_tuneproc; @@ -1142,22 +1204,33 @@ case PCI_DEVICE_ID_CMD_649: case PCI_DEVICE_ID_CMD_648: case PCI_DEVICE_ID_CMD_643: - hwif->dmaproc = &cmd64x_dmaproc; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (hwif->dma_base) + hwif->dmaproc = &cmd64x_dmaproc; +#endif /* CONFIG_BLK_DEV_IDEDMA */ hwif->tuneproc = &cmd64x_tuneproc; hwif->speedproc = &cmd64x_tune_chipset; break; case PCI_DEVICE_ID_CMD_646: hwif->chipset = ide_cmd646; - if (class_rev == 0x01) { - hwif->dmaproc = &cmd646_1_dmaproc; - } else { - hwif->dmaproc = &cmd64x_dmaproc; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (hwif->dma_base) { + if (class_rev == 0x01) + hwif->dmaproc = &cmd646_1_dmaproc; + else + hwif->dmaproc = &cmd64x_dmaproc; } +#endif /* CONFIG_BLK_DEV_IDEDMA */ hwif->tuneproc = &cmd64x_tuneproc; hwif->speedproc = &cmd64x_tune_chipset; break; default: break; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ + +#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IDEDMA_AUTO) + if (hwif->dma_base) + if (!noautodma) + hwif->autodma = 1; +#endif /* CONFIG_BLK_DEV_IDEDMA && CONFIG_IDEDMA_AUTO*/ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/Config.in linux.20pre2-ac1/drivers/ide/Config.in --- linux.20pre2/drivers/ide/Config.in 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/Config.in 2002-08-13 14:22:48.000000000 +0100 @@ -34,7 +34,7 @@ dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI bool ' IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL -# bool ' IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO + bool ' IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO comment 'IDE chipset support/bugfixes' if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then @@ -55,17 +55,13 @@ dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP -# dep_bool ' Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL - define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI -# dep_bool ' Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL - dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX dep_bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP - dep_bool ' CMD64X and CMD680 chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI + dep_bool ' CMD64X, CMD680 chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X dep_bool ' CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI @@ -82,14 +78,15 @@ fi dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL -# dep_mbool ' Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL + dep_bool ' Pacific Digital ADMA100 basic support' CONFIG_BLK_DEV_ADMA100 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX dep_bool ' Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX - dep_bool ' ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 + dep_bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 + dep_bool ' ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 - dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL + dep_bool ' Tekram TRM290 chipset support' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/cs5530.c linux.20pre2-ac1/drivers/ide/cs5530.c --- linux.20pre2/drivers/ide/cs5530.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/cs5530.c 2002-08-06 15:42:11.000000000 +0100 @@ -37,7 +37,6 @@ static int cs5530_get_info(char *, char **, off_t, int); extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count) @@ -54,13 +53,19 @@ c0 = inb_p((unsigned short)bibma + 0x02); c1 = inb_p((unsigned short)bibma + 0x0a); - p += sprintf(p, "\n Cyrix 5530 Chipset.\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", + p += sprintf(p, "\n " + "Cyrix 5530 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", (c0&0x80) ? "dis" : " en", (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s " + " %s %s\n", (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); @@ -74,19 +79,14 @@ byte cs5530_proc = 0; -extern char *ide_xfer_verbose (byte xfer_rate); - /* * Set a new transfer mode at the drive */ int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode) { - int error = 0; - - printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode)); - error = ide_config_drive_speed(drive, mode); - - return error; + printk("%s: cs5530_set_xfer_mode(%s)\n", + drive->name, ide_xfer_verbose(mode)); + return (ide_config_drive_speed(drive, mode)); } /* @@ -115,12 +115,13 @@ { ide_hwif_t *hwif = HWIF(drive); unsigned int format, basereg = CS5530_BASEREG(hwif); - static byte modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4}; + static byte modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4}; pio = ide_get_best_pio_mode(drive, pio, 4, NULL); if (!cs5530_set_xfer_mode(drive, modes[pio])) { format = (inl(basereg+4) >> 31) & 1; - outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3)); + outl(cs5530_pio_timings[format][pio], + basereg+(drive->select.b.unit<<3)); } } @@ -138,12 +139,13 @@ struct hd_driveid *id = drive->id; unsigned int basereg, reg, timings; - /* * Default to DMA-off in case we run into trouble here. */ - (void)hwif->dmaproc(ide_dma_off_quietly, drive); /* turn off DMA while we fiddle */ - outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */ + (void)hwif->dmaproc(ide_dma_off_quietly, drive); + /* turn off DMA while we fiddle */ + (void)hwif->dmaproc(ide_dma_host_off, drive); + /* clear DMA_capable bit */ /* * The CS5530 specifies that two drives sharing a cable cannot @@ -156,10 +158,13 @@ */ if (mate->present) { struct hd_driveid *mateid = mate->id; - if (mateid && (mateid->capability & 1) && !hwif->dmaproc(ide_dma_bad_drive, mate)) { - if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7)) + if (mateid && (mateid->capability & 1) && + !hwif->dmaproc(ide_dma_bad_drive, mate)) { + if ((mateid->field_valid & 4) && + (mateid->dma_ultra & 7)) udma_ok = 1; - else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7)) + else if ((mateid->field_valid & 2) && + (mateid->dma_mword & 7)) udma_ok = 0; else udma_ok = 1; @@ -170,7 +175,8 @@ * Now see what the current drive is capable of, * selecting UDMA only if the mate said it was ok. */ - if (id && (id->capability & 1) && hwif->autodma && !hwif->dmaproc(ide_dma_bad_drive, drive)) { + if (id && (id->capability & 1) && hwif->autodma && + !hwif->dmaproc(ide_dma_bad_drive, drive)) { if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) { if (id->dma_ultra & 4) mode = XFER_UDMA_2; @@ -206,11 +212,12 @@ case XFER_MW_DMA_1: timings = 0x00012121; break; case XFER_MW_DMA_2: timings = 0x00002020; break; default: - printk("%s: cs5530_config_dma: huh? mode=%02x\n", drive->name, mode); + printk("%s: cs5530_config_dma: huh? mode=%02x\n", + drive->name, mode); return 1; /* failure */ } basereg = CS5530_BASEREG(hwif); - reg = inl(basereg+4); /* get drive0 config register */ + reg = inl(basereg+4); /* get drive0 config register */ timings |= reg & 0x80000000; /* preserve PIO format bit */ if (unit == 0) { /* are we configuring drive0? */ outl(timings, basereg+4); /* write drive0 config register */ @@ -222,7 +229,8 @@ outl(reg, basereg+4); /* write drive0 config register */ outl(timings, basereg+12); /* write drive1 config register */ } - outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */ + (void)hwif->dmaproc(ide_dma_host_on, drive); + /* set DMA_capable bit */ /* * Finally, turn DMA on in software, and exit. @@ -286,8 +294,8 @@ return 0; } - save_flags(flags); - cli(); /* all CPUs (there should only be one CPU with this chipset) */ + spin_lock_irqsave(&io_request_lock, flags); + /* all CPUs (there should only be one CPU with this chipset) */ /* * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530: @@ -333,7 +341,7 @@ pci_write_config_byte(master_0, 0x42, 0x00); pci_write_config_byte(master_0, 0x43, 0xc1); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return 0; } @@ -344,31 +352,35 @@ */ void __init ide_init_cs5530 (ide_hwif_t *hwif) { + unsigned int basereg, d0_timings; + hwif->autodma = 0; + if (hwif->mate) hwif->serialized = hwif->mate->serialized = 1; - if (!hwif->dma_base) { - hwif->autodma = 0; - } else { - unsigned int basereg, d0_timings; + + hwif->tuneproc = &cs5530_tuneproc; + basereg = CS5530_BASEREG(hwif); + d0_timings = inl(basereg+0); + if (CS5530_BAD_PIO(d0_timings)) { + /* PIO timings not initialized? */ + outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0); + if (!hwif->drives[0].autotune) + hwif->drives[0].autotune = 1; + /* needs autotuning later */ + } + if (CS5530_BAD_PIO(inl(basereg+8))) { + /* PIO timings not initialized? */ + outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8); + if (!hwif->drives[1].autotune) + hwif->drives[1].autotune = 1; + /* needs autotuning later */ + } #ifdef CONFIG_BLK_DEV_IDEDMA - hwif->dmaproc = &cs5530_dmaproc; -#else - hwif->autodma = 0; + hwif->dmaproc = &cs5530_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* CONFIG_BLK_DEV_IDEDMA */ - - hwif->tuneproc = &cs5530_tuneproc; - basereg = CS5530_BASEREG(hwif); - d0_timings = inl(basereg+0); - if (CS5530_BAD_PIO(d0_timings)) { /* PIO timings not initialized? */ - outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0); - if (!hwif->drives[0].autotune) - hwif->drives[0].autotune = 1; /* needs autotuning later */ - } - if (CS5530_BAD_PIO(inl(basereg+8))) { /* PIO timings not initialized? */ - outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8); - if (!hwif->drives[1].autotune) - hwif->drives[1].autotune = 1; /* needs autotuning later */ - } - } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/cy82c693.c linux.20pre2-ac1/drivers/ide/cy82c693.c --- linux.20pre2/drivers/ide/cy82c693.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/cy82c693.c 2002-08-06 15:42:11.000000000 +0100 @@ -105,10 +105,10 @@ /* the struct for the PIO mode timings */ typedef struct pio_clocks_s { - byte address_time; /* Address setup (clocks) */ - byte time_16r; /* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */ - byte time_16w; /* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */ - byte time_8; /* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */ + byte address_time; /* Address setup (clocks) */ + byte time_16r; /* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */ + byte time_16w; /* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */ + byte time_8; /* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */ } pio_clocks_t; /* @@ -183,24 +183,26 @@ */ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) { - byte index; + byte index; byte data; - if (mode>2) /* make sure we set a valid mode */ + if (mode>2) /* make sure we set a valid mode */ mode = 2; if (mode > drive->id->tDMA) /* to be absolutly sure we have a valid mode */ mode = drive->id->tDMA; - index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1; + index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1; #if CY82C693_DEBUG_LOGS - /* for debug let's show the previous values */ + /* for debug let's show the previous values */ OUT_BYTE(index, CY82_INDEX_PORT); data = IN_BYTE(CY82_DATA_PORT); - printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1)); + printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", + drive->name, HWIF(drive)->channel, drive->select.b.unit, + (data&0x3), ((data>>2)&1)); #endif /* CY82C693_DEBUG_LOGS */ data = (byte)mode|(byte)(single<<2); @@ -209,7 +211,9 @@ OUT_BYTE(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single); + printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", + drive->name, HWIF(drive)->channel, drive->select.b.unit, + mode, single); #endif /* CY82C693_DEBUG_INFO */ /* @@ -227,7 +231,8 @@ OUT_BYTE(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", drive->name, data); + printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", + drive->name, data); #endif /* CY82C693_DEBUG_INFO */ } @@ -318,7 +323,10 @@ pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8); } - printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); + printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is " + "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", + drive->name, hwif->channel, drive->select.b.unit, + addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); #endif /* CY82C693_DEBUG_LOGS */ /* first let's calc the pio modes */ @@ -371,7 +379,10 @@ } #if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); + printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to " + "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", + drive->name, hwif->channel, drive->select.b.unit, + addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); #endif /* CY82C693_DEBUG_INFO */ } @@ -391,7 +402,7 @@ #endif /* CY82C693_SETDMA_CLOCK */ /* write info about this verion of the driver */ - printk (KERN_INFO CY82_VERSION "\n"); + printk(KERN_INFO CY82_VERSION "\n"); #ifdef CY82C693_SETDMA_CLOCK /* okay let's set the DMA clock speed */ @@ -400,7 +411,8 @@ data = IN_BYTE(CY82_DATA_PORT); #if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data); + printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", + name, data); #endif /* CY82C693_DEBUG_INFO */ /* @@ -421,7 +433,8 @@ OUT_BYTE(data, CY82_DATA_PORT); #if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data); + printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", + name, data); #endif /* CY82C693_DEBUG_INFO */ #endif /* CY82C693_SETDMA_CLOCK */ @@ -439,11 +452,27 @@ hwif->drives[1].autotune = 1; hwif->autodma = 0; + if (!hwif->dma_base) + return; #ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) { - hwif->dmaproc = &cy82c693_dmaproc; - if (!noautodma) - hwif->autodma = 1; - } + hwif->dmaproc = &cy82c693_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* CONFIG_BLK_DEV_IDEDMA */ } + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_cy82c693 (struct pci_dev *dev, ide_pci_device_t *d) +{ + if ((!(PCI_FUNC(dev->devfn) & 1) || + (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))) + return; /* CY82C693 is more than only a IDE controller */ + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/dtc2278.c linux.20pre2-ac1/drivers/ide/dtc2278.c --- linux.20pre2/drivers/ide/dtc2278.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/dtc2278.c 2002-08-06 15:42:11.000000000 +0100 @@ -57,14 +57,14 @@ int i; for(i = 0; i < 3; ++i) { - inb(0x3f6); + IN_BYTE(0x3f6); outb_p(b,0xb0); - inb(0x3f6); + IN_BYTE(0x3f6); outb_p(c,0xb4); - inb(0x3f6); - if(inb(0xb4) == c) { + IN_BYTE(0x3f6); + if(IN_BYTE(0xb4) == c) { outb_p(7,0xb0); - inb(0x3f6); + IN_BYTE(0x3f6); return; /* success */ } } @@ -77,14 +77,13 @@ pio = ide_get_best_pio_mode(drive, pio, 4, NULL); if (pio >= 3) { - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); /* * This enables PIO mode4 (3?) on the first interface */ sub22(1,0xc3); sub22(0,0xa0); - restore_flags(flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); } else { /* we don't know how to set it back again.. */ } @@ -100,15 +99,14 @@ { unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); /* * This enables the second interface */ outb_p(4,0xb0); - inb(0x3f6); + IN_BYTE(0x3f6); outb_p(0x20,0xb4); - inb(0x3f6); + IN_BYTE(0x3f6); #ifdef ALWAYS_SET_DTC2278_PIO_MODE /* * This enables PIO mode4 (3?) on the first interface @@ -117,7 +115,7 @@ sub22(1,0xc3); sub22(0,0xa0); #endif - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); ide_hwifs[0].serialized = 1; ide_hwifs[1].serialized = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/hd.c linux.20pre2-ac1/drivers/ide/hd.c --- linux.20pre2/drivers/ide/hd.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/hd.c 2002-08-07 14:14:14.000000000 +0100 @@ -62,6 +62,16 @@ #define HD_IRQ IRQ_HARDDISK #endif +#ifndef HAVE_ARCH_OUT_BYTE +#ifdef REALLY_FAST_IO +#define OUT_BYTE(b,p) outb((b),(p)) +#define OUT_WORD(w,p) outw((w),(p)) +#else +#define OUT_BYTE(b,p) outb_p((b),(p)) +#define OUT_WORD(w,p) outw_p((w),(p)) +#endif +#endif + static int revalidate_hddisk(kdev_t, int); #define HD_DELAY 0 @@ -135,13 +145,12 @@ unsigned long t, flags; int i; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); - i |= inb(0x40) << 8; - restore_flags(flags); + i |= IN_BYTE(0x40) << 8; + spin_unlock_irqrestore(&io_request_lock, flags); return(t - i); } #endif @@ -185,7 +194,7 @@ if ((stat & ERR_STAT) == 0) { hd_error = 0; } else { - hd_error = inb(HD_ERROR); + hd_error = IN_BYTE(HD_ERROR); printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff); if (hd_error & BBD_ERR) printk("BadSector "); if (hd_error & ECC_ERR) printk("UncorrectableError "); @@ -195,8 +204,9 @@ if (hd_error & MARK_ERR) printk("AddrMarkNotFound "); printk("}"); if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { - printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL), - inb(HD_CURRENT) & 0xf, inb(HD_SECTOR)); + printk(", CHS=%d/%d/%d", + (IN_BYTE(HD_HCYL)<<8) + IN_BYTE(HD_LCYL), + IN_BYTE(HD_CURRENT) & 0xf, IN_BYTE(HD_SECTOR)); if (!QUEUE_EMPTY) printk(", sector=%ld", CURRENT->sector); } @@ -207,7 +217,7 @@ if ((stat & ERR_STAT) == 0) { hd_error = 0; } else { - hd_error = inb(HD_ERROR); + hd_error = IN_BYTE(HD_ERROR); printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff); } #endif /* verbose errors */ @@ -318,7 +328,7 @@ for(i = 0; i < 1000; i++) barrier(); if (drive_busy()) printk("hd: controller still busy\n"); - else if ((hd_error = inb(HD_ERROR)) != 1) + else if ((hd_error = IN_BYTE(HD_ERROR)) != 1) printk("hd: controller reset failed: %02x\n",hd_error); } @@ -346,6 +356,13 @@ hd_request(); } +void do_reset_hd(void) +{ + DEVICE_INTR = NULL; + reset = 1; + reset_hd(); +} + /* * Ok, don't know what to do with the unexpected interrupts: on some machines * doing a reset and a retry seems to result in an eternal loop. Right now I @@ -876,14 +893,13 @@ target = DEVICE_NR(dev); gdev = &GENDISK_STRUCT; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); if (DEVICE_BUSY || USAGE > maxusage) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return -EBUSY; } DEVICE_BUSY = 1; - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); max_p = gdev->max_p; start = target << gdev->minor_shift; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/hpt34x.c linux.20pre2-ac1/drivers/ide/hpt34x.c --- linux.20pre2/drivers/ide/hpt34x.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/hpt34x.c 2002-08-06 15:42:11.000000000 +0100 @@ -50,41 +50,57 @@ #undef DISPLAY_HPT34X_TIMINGS +#define HPT34X_MAX_DEVS 8 +static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS]; +static int n_hpt34x_devs; + #if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) #include #include static int hpt34x_get_info(char *, char **, off_t, int); extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); -static struct pci_dev *bmide_dev; static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - u32 bibma = pci_resource_start(bmide_dev, 4); - u8 c0 = 0, c1 = 0; + int i; - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((unsigned short)bibma + 0x02); - c1 = inb_p((unsigned short)bibma + 0x0a); - - p += sprintf(p, "\n HPT34X Chipset.\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", - (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); - - p += sprintf(p, "UDMA\n"); - p += sprintf(p, "DMA\n"); - p += sprintf(p, "PIO\n"); + p += sprintf(p, "\n " + "HPT34X Chipset.\n"); + for (i = 0; i < n_hpt34x_devs; i++) { + struct pci_dev *dev = hpt34x_devs[i]; + u32 bibma = pci_resource_start(dev, 4); + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + p += sprintf(p, "\nController: %d\n", i); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s" + " %s %s\n", + (c0&0x20) ? "yes" : "no ", + (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", + (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + } + p += sprintf(p, "\n"); return p-buffer; /* => must be less than 4k! */ } @@ -92,27 +108,65 @@ byte hpt34x_proc = 0; -extern char *ide_xfer_verbose (byte xfer_rate); +static byte hpt34x_ratemask (ide_drive_t *drive) +{ + byte mode = 0x00; + + mode |= 0x01; + + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte hpt34x_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA +# ifdef CONFIG_HPT34X_AUTODMA +byte mode = hpt34x_ratemask(drive); + + switch(mode) { + case 0x04: // while (speed > XFER_UDMA_6) speed--; break; + case 0x03: // while (speed > XFER_UDMA_5) speed--; break; + case 0x02: // while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +# else /* !CONFIG_HPT34X_AUTODMA */ + while (speed > XFER_PIO_4) speed--; +# endif /* CONFIG_HPT34X_AUTODMA */ +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} static void hpt34x_clear_chipset (ide_drive_t *drive) { + struct pci_dev *dev = HWIF(drive)->pci_dev; unsigned int reg1 = 0, tmp1 = 0; unsigned int reg2 = 0, tmp2 = 0; - pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); - pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); + pci_read_config_dword(dev, 0x44, ®1); + pci_read_config_dword(dev, 0x48, ®2); tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); tmp2 = (reg2 & ~(0x11 << drive->dn)); - pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); - pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); + pci_write_config_dword(dev, 0x44, tmp1); + pci_write_config_dword(dev, 0x48, tmp2); } -static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed) +static int hpt34x_tune_chipset (ide_drive_t *drive, byte xferspeed) { - int err; - byte hi_speed, lo_speed; + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte speed = hpt34x_ratefilter(drive, xferspeed); unsigned int reg1 = 0, tmp1 = 0; unsigned int reg2 = 0, tmp2 = 0; + byte hi_speed, lo_speed; SPLIT_BYTE(speed, hi_speed, lo_speed); @@ -123,76 +177,35 @@ lo_speed >>= 5; } - pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); - pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); + pci_read_config_dword(dev, 0x44, ®1); + pci_read_config_dword(dev, 0x48, ®2); tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); tmp2 = ((hi_speed << drive->dn) | reg2); - err = ide_config_drive_speed(drive, speed); - pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); - pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); - - if (!drive->init_speed) - drive->init_speed = speed; + pci_write_config_dword(dev, 0x44, tmp1); + pci_write_config_dword(dev, 0x48, tmp2); #if HPT343_DEBUG_DRIVE_INFO printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \ - " (0x%02x 0x%02x) 0x%04x\n", + " (0x%02x 0x%02x)\n", drive->name, ide_xfer_verbose(speed), drive->dn, reg1, tmp1, reg2, tmp2, - hi_speed, lo_speed, err); + hi_speed, lo_speed); #endif /* HPT343_DEBUG_DRIVE_INFO */ - drive->current_speed = speed; - return(err); -} - -static void config_chipset_for_pio (ide_drive_t *drive) -{ - unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; - unsigned short xfer_pio = drive->id->eide_pio_modes; - - byte timing, speed, pio; - - pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - - if (xfer_pio> 4) - xfer_pio = 0; - - if (drive->id->eide_pio_iordy > 0) { - for (xfer_pio = 5; - xfer_pio>0 && - drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; - xfer_pio--); - } else { - xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : - (drive->id->eide_pio_modes & 2) ? 0x04 : - (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio; - } - - timing = (xfer_pio >= pio) ? xfer_pio : pio; - - switch(timing) { - case 4: speed = XFER_PIO_4;break; - case 3: speed = XFER_PIO_3;break; - case 2: speed = XFER_PIO_2;break; - case 1: speed = XFER_PIO_1;break; - default: - speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - break; - } - (void) hpt34x_tune_chipset(drive, speed); + return(ide_config_drive_speed(drive, speed)); } static void hpt34x_tune_drive (ide_drive_t *drive, byte pio) { byte speed; + pio = ide_get_best_pio_mode(drive, pio, 5, NULL); switch(pio) { - case 4: speed = XFER_PIO_4;break; - case 3: speed = XFER_PIO_3;break; - case 2: speed = XFER_PIO_2;break; - case 1: speed = XFER_PIO_1;break; - default: speed = XFER_PIO_0;break; + case 4: speed = XFER_PIO_4; break; + case 3: speed = XFER_PIO_3; break; + case 2: speed = XFER_PIO_2; break; + case 1: speed = XFER_PIO_1; break; + default: speed = XFER_PIO_0; break; } hpt34x_clear_chipset(drive); (void) hpt34x_tune_chipset(drive, speed); @@ -205,42 +218,41 @@ * after the drive is reported by the OS. Initally for designed for * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc. */ -static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; + byte mode = hpt34x_ratemask(drive); byte speed = 0x00; if (drive->media != ide_disk) return ((int) ide_dma_off_quietly); - hpt34x_clear_chipset(drive); - - if ((id->dma_ultra & 0x0010) && ultra) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0008) && ultra) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0004) && ultra) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && ultra) { - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && ultra) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); + switch(mode) { + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + if (id->dma_1word & 0x0002) + { speed = XFER_SW_DMA_1; break; } + if (id->dma_1word & 0x0001) + { speed = XFER_SW_DMA_0; break; } + default: + return ((int) ide_dma_off_quietly); } + hpt34x_clear_chipset(drive); (void) hpt34x_tune_chipset(drive, speed); return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_off : @@ -255,6 +267,8 @@ struct hd_driveid *id = drive->id; ide_dma_action_t dma_func = ide_dma_on; + drive->init_speed = 0; + if (id && (id->capability & 1) && HWIF(drive)->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { @@ -265,7 +279,7 @@ if (id->field_valid & 4) { if (id->dma_ultra & 0x0007) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; @@ -275,7 +289,7 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } @@ -284,7 +298,7 @@ goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } else { @@ -294,7 +308,7 @@ fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - config_chipset_for_pio(drive); + hpt34x_tune_drive(drive, 255); } #ifndef CONFIG_HPT34X_AUTODMA @@ -316,6 +330,7 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); +// ide_task_t *args = HWGROUP(drive)->rq->special; unsigned long dma_base = hwif->dma_base; unsigned int count, reading = 0; byte dma_stat; @@ -327,24 +342,52 @@ reading = 1 << 3; case ide_dma_write: if (!(count = ide_build_dmatable(drive, func))) - return 1; /* try PIO instead of DMA */ - outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */ + return 1; + /* try PIO instead of DMA */ + outl(hwif->dmatable_dma, dma_base + 4); + /* PRD table */ reading |= 0x01; - outb(reading, dma_base); /* specify r/w */ - outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + OUT_BYTE(reading, dma_base); + /* specify r/w */ + OUT_BYTE(IN_BYTE(dma_base+2)|6, dma_base+2); + /* clear INTR & ERROR flags */ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ - OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - return 0; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); + /* issue cmd to drive */ + /* + * FIX ME to use only ACB ide_task_t args Struct + */ +#if 0 + { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + { +#else + if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } else if (drive->addressing == 1) + OUT_BYTE((reading == 9) ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); + else + OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); +#endif + return HWIF(drive)->dmaproc(ide_dma_begin, drive); case ide_dma_end: /* returns 1 on error, 0 otherwise */ drive->waiting_for_dma = 0; - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (dma_stat & 7) != 4; /* verify good DMA status */ + /* stop DMA */ + OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base); + /* get DMA status */ + dma_stat = IN_BYTE(dma_base+2); + /* clear the INTR & ERROR bits */ + OUT_BYTE(dma_stat|6, dma_base+2); + /* purge DMA mappings */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + return (dma_stat & 7) != 4; default: break; } @@ -361,11 +404,11 @@ { int i = 0; unsigned long hpt34xIoBase = pci_resource_start(dev, 4); + unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c }; unsigned short cmd; unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00); pci_read_config_word(dev, PCI_COMMAND, &cmd); @@ -373,35 +416,34 @@ if (cmd & PCI_COMMAND_MEMORY) { if (pci_resource_start(dev, PCI_ROM_RESOURCE)) { pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start); + printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", + dev->resource[PCI_ROM_RESOURCE].start); } pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); } else { pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } - pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); - dev->resource[0].start = (hpt34xIoBase + 0x20); - dev->resource[1].start = (hpt34xIoBase + 0x34); - dev->resource[2].start = (hpt34xIoBase + 0x28); - dev->resource[3].start = (hpt34xIoBase + 0x3c); - for(i=0; i<4; i++) - dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; /* * Since 20-23 can be assigned and are R/W, we correct them. */ - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start); - pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start); + pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); + for(i=0; i<4; i++) { + dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]); + dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; + pci_write_config_dword(dev, + (PCI_BASE_ADDRESS_0 + (i * 4)), + dev->resource[i].start); + } pci_write_config_word(dev, PCI_COMMAND, cmd); - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); + + hpt34x_devs[n_hpt34x_devs++] = dev; #if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) if (!hpt34x_proc) { hpt34x_proc = 1; - bmide_dev = dev; hpt34x_display_info = &hpt34x_get_info; } #endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */ @@ -411,27 +453,39 @@ void __init ide_init_hpt34x (ide_hwif_t *hwif) { + unsigned short pcicmd = 0; hwif->tuneproc = &hpt34x_tune_drive; hwif->speedproc = &hpt34x_tune_chipset; - -#ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) { - unsigned short pcicmd = 0; - - pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); - if (!noautodma) - hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; - else - hwif->autodma = 0; - - hwif->dmaproc = &hpt34x_dmaproc; - } else { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - } -#else /* !CONFIG_BLK_DEV_IDEDMA */ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0; + + pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); + + if (!hwif->dma_base) + return; + +#ifdef CONFIG_BLK_DEV_IDEDMA + hwif->dmaproc = &hpt34x_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* CONFIG_BLK_DEV_IDEDMA */ } + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_hpt343 (struct pci_dev *dev, ide_pci_device_t *d) +{ + char *chipset_names[] = {"HPT343", "HPT345"}; + unsigned short pcicmd = 0; + + pci_read_config_word(dev, PCI_COMMAND, &pcicmd); + + strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]); + d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/hpt366.c linux.20pre2-ac1/drivers/ide/hpt366.c --- linux.20pre2/drivers/ide/hpt366.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/hpt366.c 2002-08-06 15:42:11.000000000 +0100 @@ -1,9 +1,8 @@ /* - * linux/drivers/ide/hpt366.c Version 0.22 20 Sep 2001 + * linux/drivers/ide/hpt366.c Version 0.33 April 17, 2002 * - * Copyright (C) 1999-2000 Andre Hedrick + * Copyright (C) 1999-2002 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. - * May be copied or modified under the terms of the GNU General Public License * * Thanks to HighPoint Technologies for their assistance, and hardware. * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his @@ -42,6 +41,7 @@ * Mike Waychison */ + #include #include #include @@ -67,16 +67,14 @@ /* various tuning parameters */ #define HPT_RESET_STATE_ENGINE -/*#define HPT_DELAY_INTERRUPT*/ -/*#define HPT_SERIALIZE_IO*/ +#undef HPT_DELAY_INTERRUPT +#undef HPT_SERIALIZE_IO #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) #include #include #endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ -extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); - const char *quirk_drives[] = { "QUANTUM FIREBALLlct08 08", "QUANTUM FIREBALLP KA6.4", @@ -166,9 +164,8 @@ * PIO. * 31 FIFO enable. */ -struct chipset_bus_clock_list_entry forty_base [] = { - - { XFER_UDMA_4, 0x900fd943 }, +struct chipset_bus_clock_list_entry forty_base_hpt366[] = { + { XFER_UDMA_4, 0x900fd943 }, { XFER_UDMA_3, 0x900ad943 }, { XFER_UDMA_2, 0x900bd943 }, { XFER_UDMA_1, 0x9008d943 }, @@ -186,8 +183,7 @@ { 0, 0x0120d9d9 } }; -struct chipset_bus_clock_list_entry thirty_three_base [] = { - +struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = { { XFER_UDMA_4, 0x90c9a731 }, { XFER_UDMA_3, 0x90cfa731 }, { XFER_UDMA_2, 0x90caa731 }, @@ -206,7 +202,7 @@ { 0, 0x0120a7a7 } }; -struct chipset_bus_clock_list_entry twenty_five_base [] = { +struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = { { XFER_UDMA_4, 0x90c98521 }, { XFER_UDMA_3, 0x90cf8521 }, @@ -226,51 +222,9 @@ { 0, 0x01208585 } }; -#if 1 -/* these are the current (4 sep 2001) timings from highpoint */ -struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = { - { XFER_UDMA_5, 0x12446231 }, - { XFER_UDMA_4, 0x12446231 }, - { XFER_UDMA_3, 0x126c6231 }, - { XFER_UDMA_2, 0x12486231 }, - { XFER_UDMA_1, 0x124c6233 }, - { XFER_UDMA_0, 0x12506297 }, - - { XFER_MW_DMA_2, 0x22406c31 }, - { XFER_MW_DMA_1, 0x22406c33 }, - { XFER_MW_DMA_0, 0x22406c97 }, - - { XFER_PIO_4, 0x06414e31 }, - { XFER_PIO_3, 0x06414e42 }, - { XFER_PIO_2, 0x06414e53 }, - { XFER_PIO_1, 0x06814e93 }, - { XFER_PIO_0, 0x06814ea7 }, - { 0, 0x06814ea7 } -}; - -/* 2x 33MHz timings */ -struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = { - { XFER_UDMA_5, 0x1488e673 }, - { XFER_UDMA_4, 0x1488e673 }, - { XFER_UDMA_3, 0x1498e673 }, - { XFER_UDMA_2, 0x1490e673 }, - { XFER_UDMA_1, 0x1498e677 }, - { XFER_UDMA_0, 0x14a0e73f }, - - { XFER_MW_DMA_2, 0x2480fa73 }, - { XFER_MW_DMA_1, 0x2480fa77 }, - { XFER_MW_DMA_0, 0x2480fb3f }, - - { XFER_PIO_4, 0x0c82be73 }, - { XFER_PIO_3, 0x0c82be95 }, - { XFER_PIO_2, 0x0c82beb7 }, - { XFER_PIO_1, 0x0d02bf37 }, - { XFER_PIO_0, 0x0d02bf5f }, - { 0, 0x0d02bf5f } -}; -#else /* from highpoint documentation. these are old values */ struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = { +/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */ { XFER_UDMA_5, 0x16454e31 }, { XFER_UDMA_4, 0x16454e31 }, { XFER_UDMA_3, 0x166d4e31 }, @@ -309,9 +263,50 @@ { XFER_PIO_0, 0x06914e57 }, { 0, 0x06514e57 } }; -#endif -struct chipset_bus_clock_list_entry fifty_base_hpt370[] = { +/* these are the current (4 sep 2001) timings from highpoint */ +struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = { + { XFER_UDMA_5, 0x12446231 }, + { XFER_UDMA_4, 0x12446231 }, + { XFER_UDMA_3, 0x126c6231 }, + { XFER_UDMA_2, 0x12486231 }, + { XFER_UDMA_1, 0x124c6233 }, + { XFER_UDMA_0, 0x12506297 }, + + { XFER_MW_DMA_2, 0x22406c31 }, + { XFER_MW_DMA_1, 0x22406c33 }, + { XFER_MW_DMA_0, 0x22406c97 }, + + { XFER_PIO_4, 0x06414e31 }, + { XFER_PIO_3, 0x06414e42 }, + { XFER_PIO_2, 0x06414e53 }, + { XFER_PIO_1, 0x06814e93 }, + { XFER_PIO_0, 0x06814ea7 }, + { 0, 0x06814ea7 } +}; + +/* 2x 33MHz timings */ +struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = { + { XFER_UDMA_5, 0x1488e673 }, + { XFER_UDMA_4, 0x1488e673 }, + { XFER_UDMA_3, 0x1498e673 }, + { XFER_UDMA_2, 0x1490e673 }, + { XFER_UDMA_1, 0x1498e677 }, + { XFER_UDMA_0, 0x14a0e73f }, + + { XFER_MW_DMA_2, 0x2480fa73 }, + { XFER_MW_DMA_1, 0x2480fa77 }, + { XFER_MW_DMA_0, 0x2480fb3f }, + + { XFER_PIO_4, 0x0c82be73 }, + { XFER_PIO_3, 0x0c82be95 }, + { XFER_PIO_2, 0x0c82beb7 }, + { XFER_PIO_1, 0x0d02bf37 }, + { XFER_PIO_0, 0x0d02bf5f }, + { 0, 0x0d02bf5f } +}; + +struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = { { XFER_UDMA_5, 0x12848242 }, { XFER_UDMA_4, 0x12ac8242 }, { XFER_UDMA_3, 0x128c8242 }, @@ -331,7 +326,149 @@ { 0, 0x0ac1f48a } }; +struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = { + { XFER_UDMA_6, 0x1c81dc62 }, + { XFER_UDMA_5, 0x1c6ddc62 }, + { XFER_UDMA_4, 0x1c8ddc62 }, + { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */ + { XFER_UDMA_2, 0x1c91dc62 }, + { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */ + { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */ + + { XFER_MW_DMA_2, 0x2c829262 }, + { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */ + { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */ + + { XFER_PIO_4, 0x0c829c62 }, + { XFER_PIO_3, 0x0c829c84 }, + { XFER_PIO_2, 0x0c829ca6 }, + { XFER_PIO_1, 0x0d029d26 }, + { XFER_PIO_0, 0x0d029d5e }, + { 0, 0x0d029d5e } +}; + +struct chipset_bus_clock_list_entry fifty_base_hpt372[] = { + { XFER_UDMA_5, 0x12848242 }, + { XFER_UDMA_4, 0x12ac8242 }, + { XFER_UDMA_3, 0x128c8242 }, + { XFER_UDMA_2, 0x120c8242 }, + { XFER_UDMA_1, 0x12148254 }, + { XFER_UDMA_0, 0x121882ea }, + + { XFER_MW_DMA_2, 0x22808242 }, + { XFER_MW_DMA_1, 0x22808254 }, + { XFER_MW_DMA_0, 0x228082ea }, + + { XFER_PIO_4, 0x0a81f442 }, + { XFER_PIO_3, 0x0a81f443 }, + { XFER_PIO_2, 0x0a81f454 }, + { XFER_PIO_1, 0x0ac1f465 }, + { XFER_PIO_0, 0x0ac1f48a }, + { 0, 0x0a81f443 } +}; + +struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = { + { XFER_UDMA_6, 0x1c869c62 }, + { XFER_UDMA_5, 0x1cae9c62 }, + { XFER_UDMA_4, 0x1c8a9c62 }, + { XFER_UDMA_3, 0x1c8e9c62 }, + { XFER_UDMA_2, 0x1c929c62 }, + { XFER_UDMA_1, 0x1c9a9c62 }, + { XFER_UDMA_0, 0x1c829c62 }, + + { XFER_MW_DMA_2, 0x2c829c62 }, + { XFER_MW_DMA_1, 0x2c829c66 }, + { XFER_MW_DMA_0, 0x2c829d2e }, + + { XFER_PIO_4, 0x0c829c62 }, + { XFER_PIO_3, 0x0c829c84 }, + { XFER_PIO_2, 0x0c829ca6 }, + { XFER_PIO_1, 0x0d029d26 }, + { XFER_PIO_0, 0x0d029d5e }, + { 0, 0x0d029d26 } +}; + +struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = { + { XFER_UDMA_6, 0x12808242 }, + { XFER_UDMA_5, 0x12848242 }, + { XFER_UDMA_4, 0x12ac8242 }, + { XFER_UDMA_3, 0x128c8242 }, + { XFER_UDMA_2, 0x120c8242 }, + { XFER_UDMA_1, 0x12148254 }, + { XFER_UDMA_0, 0x121882ea }, + + { XFER_MW_DMA_2, 0x22808242 }, + { XFER_MW_DMA_1, 0x22808254 }, + { XFER_MW_DMA_0, 0x228082ea }, + + { XFER_PIO_4, 0x0a81f442 }, + { XFER_PIO_3, 0x0a81f443 }, + { XFER_PIO_2, 0x0a81f454 }, + { XFER_PIO_1, 0x0ac1f465 }, + { XFER_PIO_0, 0x0ac1f48a }, + { 0, 0x06814e93 } +}; + +#if 0 +struct chipset_bus_clock_list_entry fifty_base_hpt374[] = { + { XFER_UDMA_6, }, + { XFER_UDMA_5, }, + { XFER_UDMA_4, }, + { XFER_UDMA_3, }, + { XFER_UDMA_2, }, + { XFER_UDMA_1, }, + { XFER_UDMA_0, }, + { XFER_MW_DMA_2, }, + { XFER_MW_DMA_1, }, + { XFER_MW_DMA_0, }, + { XFER_PIO_4, }, + { XFER_PIO_3, }, + { XFER_PIO_2, }, + { XFER_PIO_1, }, + { XFER_PIO_0, }, + { 0, } +}; +#endif +#if 0 +struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = { + { XFER_UDMA_6, 0x12406231 }, /* checkme */ + { XFER_UDMA_5, 0x12446231 }, + 0x14846231 + { XFER_UDMA_4, 0x16814ea7 }, + 0x14886231 + { XFER_UDMA_3, 0x16814ea7 }, + 0x148c6231 + { XFER_UDMA_2, 0x16814ea7 }, + 0x148c6231 + { XFER_UDMA_1, 0x16814ea7 }, + 0x14906231 + { XFER_UDMA_0, 0x16814ea7 }, + 0x14986231 + { XFER_MW_DMA_2, 0x16814ea7 }, + 0x26514e21 + { XFER_MW_DMA_1, 0x16814ea7 }, + 0x26514e97 + { XFER_MW_DMA_0, 0x16814ea7 }, + 0x26514e97 + { XFER_PIO_4, 0x06814ea7 }, + 0x06514e21 + { XFER_PIO_3, 0x06814ea7 }, + 0x06514e22 + { XFER_PIO_2, 0x06814ea7 }, + 0x06514e33 + { XFER_PIO_1, 0x06814ea7 }, + 0x06914e43 + { XFER_PIO_0, 0x06814ea7 }, + 0x06914e57 + { 0, 0x06814ea7 } +}; +#endif + #define HPT366_DEBUG_DRIVE_INFO 0 +#define HPT374_ALLOW_ATA133_6 0 +#define HPT371_ALLOW_ATA133_6 0 +#define HPT302_ALLOW_ATA133_6 0 +#define HPT372_ALLOW_ATA133_6 1 #define HPT370_ALLOW_ATA100_5 1 #define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 @@ -345,35 +482,33 @@ static struct pci_dev *hpt_devs[HPT366_MAX_DEVS]; static int n_hpt_devs; -static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev); -static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev); +static unsigned int hpt_revision(struct pci_dev *dev); +static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision); + byte hpt366_proc = 0; byte hpt363_shared_irq; byte hpt363_shared_pin; -extern char *ide_xfer_verbose (byte xfer_rate); #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) static int hpt366_get_info(char *, char **, off_t, int); extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - char *chipset_nums[] = {"366", "366", "368", "370", "370A"}; + char *chipset_nums[] = {"366", "366", "368", + "370", "370A", "372", + "302", "371", "374" }; int i; p += sprintf(p, "\n " - "HighPoint HPT366/368/370\n"); + "HighPoint HPT366/368/370/372/374\n"); for (i = 0; i < n_hpt_devs; i++) { struct pci_dev *dev = hpt_devs[i]; unsigned long iobase = dev->resource[4].start; - u32 class_rev; + u32 class_rev = hpt_revision(dev); u8 c0, c1; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - p += sprintf(p, "\nController: %d\n", i); p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]); p += sprintf(p, "--------------- Primary Channel " @@ -388,7 +523,7 @@ (c0 & 0x80) ? "no" : "yes", (c1 & 0x80) ? "no" : "yes"); - if (pci_rev_check_hpt3xx(dev)) { + if (hpt_minimum_revision(dev, 3)) { u8 cbl; cbl = inb_p(iobase + 0x7b); outb_p(cbl | 1, iobase + 0x7b); @@ -437,20 +572,121 @@ } #endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ -static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev) +static unsigned int hpt_revision (struct pci_dev *dev) { unsigned int class_rev; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - return ((int) (class_rev > 0x02) ? 1 : 0); + + switch(dev->device) { + case PCI_DEVICE_ID_TTI_HPT374: + class_rev = PCI_DEVICE_ID_TTI_HPT374; break; + case PCI_DEVICE_ID_TTI_HPT371: + class_rev = PCI_DEVICE_ID_TTI_HPT371; break; + case PCI_DEVICE_ID_TTI_HPT302: + class_rev = PCI_DEVICE_ID_TTI_HPT302; break; + case PCI_DEVICE_ID_TTI_HPT372: + class_rev = PCI_DEVICE_ID_TTI_HPT372; break; + default: + break; + } + return class_rev; } -static unsigned int pci_rev2_check_hpt3xx (struct pci_dev *dev) +static unsigned int hpt_minimum_revision (struct pci_dev *dev, int revision) { - unsigned int class_rev; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - return ((int) (class_rev > 0x01) ? 1 : 0); + unsigned int class_rev = hpt_revision(dev); + revision--; + return ((int) (class_rev > revision) ? 1 : 0); +} + +static int check_in_drive_lists(ide_drive_t *drive, const char **list); + +static byte hpt3xx_ratemask (ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = 0x00; + + if (hpt_minimum_revision(dev, 8)) { /* HPT374 */ + mode |= (HPT374_ALLOW_ATA133_6) ? 0x04 : 0x03; + } else if (hpt_minimum_revision(dev, 7)) { /* HPT371 */ + mode |= (HPT371_ALLOW_ATA133_6) ? 0x04 : 0x03; + } else if (hpt_minimum_revision(dev, 6)) { /* HPT302 */ + mode |= (HPT302_ALLOW_ATA133_6) ? 0x04 : 0x03; + } else if (hpt_minimum_revision(dev, 5)) { /* HPT372 */ + mode |= (HPT372_ALLOW_ATA133_6) ? 0x04 : 0x03; + } else if (hpt_minimum_revision(dev, 4)) { /* HPT370A */ + mode |= (HPT370_ALLOW_ATA100_5) ? 0x03 : 0x02; + } else if (hpt_minimum_revision(dev, 3)) { /* HPT370 */ + mode |= (HPT370_ALLOW_ATA100_5) ? 0x03 : 0x02; + if (check_in_drive_lists(drive, bad_ata33)) + return (mode &= ~0xFF); + } else { /* HPT366 and HPT368 */ + mode |= 0x02; + if (check_in_drive_lists(drive, bad_ata33)) + return (mode &= ~0xFF); + } + + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte hpt3xx_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = hpt3xx_ratemask(drive); + + if (drive->media != ide_disk) + while (speed > XFER_PIO_4) speed--; + + switch(mode) { + case 0x04: + while (speed > XFER_UDMA_6) speed--; + break; + case 0x03: + while (speed > XFER_UDMA_5) speed--; + if (hpt_minimum_revision(dev, 5)) + break; + if (check_in_drive_lists(drive, bad_ata100_5)) + while (speed > XFER_UDMA_4) speed--; + break; + case 0x02: + while (speed > XFER_UDMA_4) speed--; + /* + * CHECK ME, Does this need to be set to 5 ?? + */ + if (hpt_minimum_revision(dev, 3)) + break; + if ((check_in_drive_lists(drive, bad_ata66_4)) || + (!(HPT366_ALLOW_ATA66_4))) + while (speed > XFER_UDMA_3) speed--; + if ((check_in_drive_lists(drive, bad_ata66_3)) || + (!(HPT366_ALLOW_ATA66_3))) + while (speed > XFER_UDMA_2) speed--; + break; + case 0x01: + while (speed > XFER_UDMA_2) speed--; + /* + * CHECK ME, Does this need to be set to 5 ?? + */ + if (hpt_minimum_revision(dev, 3)) + break; + if (check_in_drive_lists(drive, bad_ata33)) + while (speed > XFER_MW_DMA_2) speed--; + break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; } static int check_in_drive_lists (ide_drive_t *drive, const char **list) @@ -482,48 +718,35 @@ return chipset_table->chipset_settings; } -static void hpt366_tune_chipset (ide_drive_t *drive, byte speed) +static void hpt366_tune_chipset (ide_drive_t *drive, byte xferspeed) { + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte speed = hpt3xx_ratefilter(drive, xferspeed); byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; - /* - * since the channel is always 0 it does not matter. - */ - + byte drive_fast = 0; unsigned int reg1 = 0; unsigned int reg2 = 0; - byte drive_fast = 0; /* - * Disable the "fast interrupt" prediction. + * Disable the "fast interrupt" prediction. */ - pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast); - if (drive_fast & 0x02) - pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20); - - pci_read_config_dword(HWIF(drive)->pci_dev, regtime, ®1); - /* detect bus speed by looking at control reg timing: */ - switch((reg1 >> 8) & 7) { - case 5: - reg2 = pci_bus_clock_list(speed, forty_base); - break; - case 9: - reg2 = pci_bus_clock_list(speed, twenty_five_base); - break; - default: - case 7: - reg2 = pci_bus_clock_list(speed, thirty_three_base); - break; - } + pci_read_config_byte(dev, regfast, &drive_fast); #if 0 - /* this is a nice idea ... */ - list_conf = pci_bus_clock_list(speed, - (struct chipset_bus_clock_list_entry *) - dev->sysdata); + if (drive_fast & 0x02) + pci_write_config_byte(dev, regfast, drive_fast & ~0x20); +#else + if (drive_fast & 0x80) + pci_write_config_byte(dev, regfast, drive_fast & ~0x80); #endif + + reg2 = pci_bus_clock_list(speed, + (struct chipset_bus_clock_list_entry *) dev->driver_data); /* - * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later) + * Disable on-chip PIO FIFO/buffer + * (to avoid problems handling I/O errors later) */ + pci_read_config_dword(dev, regtime, ®1); if (speed >= XFER_MW_DMA_0) { reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000); } else { @@ -531,11 +754,17 @@ } reg2 &= ~0x80000000; - pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2); + pci_write_config_dword(dev, regtime, reg2); } -static void hpt370_tune_chipset (ide_drive_t *drive, byte speed) +static void hpt368_tune_chipset (ide_drive_t *drive, byte speed) { + hpt366_tune_chipset(drive, speed); +} + +static void hpt370_tune_chipset (ide_drive_t *drive, byte xferspeed) +{ + byte speed = hpt3xx_ratefilter(drive, xferspeed); byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; unsigned int list_conf = 0; unsigned int drive_conf = 0; @@ -561,11 +790,11 @@ new_fast |= 0x01; #endif if (new_fast != drive_fast) - pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast); + pci_write_config_byte(dev, regfast, new_fast); list_conf = pci_bus_clock_list(speed, (struct chipset_bus_clock_list_entry *) - dev->sysdata); + dev->driver_data); pci_read_config_dword(dev, drive_pci, &drive_conf); list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); @@ -577,70 +806,75 @@ pci_write_config_dword(dev, drive_pci, list_conf); } -static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed) +static void hpt372_tune_chipset (ide_drive_t *drive, byte xferspeed) { - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) - return -1; + byte speed = hpt3xx_ratefilter(drive, xferspeed); + byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; + unsigned int list_conf = 0; + unsigned int drive_conf = 0; + unsigned int conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; + byte drive_pci = 0x40 + (drive->dn * 4); + byte drive_fast = 0; + struct pci_dev *dev = HWIF(drive)->pci_dev; - if (!drive->init_speed) - drive->init_speed = speed; + /* + * Disable the "fast interrupt" prediction. + * don't holdoff on interrupts. (== 0x01 despite what the docs say) + */ + pci_read_config_byte(dev, regfast, &drive_fast); + drive_fast &= ~0x07; + pci_write_config_byte(dev, regfast, drive_fast); + + list_conf = pci_bus_clock_list(speed, + (struct chipset_bus_clock_list_entry *) + dev->driver_data); + pci_read_config_dword(dev, drive_pci, &drive_conf); + list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); + if (speed < XFER_MW_DMA_0) + list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ + pci_write_config_dword(dev, drive_pci, list_conf); +} - if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) { - hpt370_tune_chipset(drive, speed); - } else { - hpt366_tune_chipset(drive, speed); - } - drive->current_speed = speed; - return ((int) ide_config_drive_speed(drive, speed)); +static void hpt374_tune_chipset (ide_drive_t *drive, byte speed) +{ + hpt372_tune_chipset(drive, speed); } -static void config_chipset_for_pio (ide_drive_t *drive) +static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed) { - unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; - unsigned short xfer_pio = drive->id->eide_pio_modes; - byte timing, speed, pio; - - pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - - if (xfer_pio> 4) - xfer_pio = 0; - - if (drive->id->eide_pio_iordy > 0) { - for (xfer_pio = 5; - xfer_pio>0 && - drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; - xfer_pio--); - } else { - xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : - (drive->id->eide_pio_modes & 2) ? 0x04 : - (drive->id->eide_pio_modes & 1) ? 0x03 : - (drive->id->tPIO & 2) ? 0x02 : - (drive->id->tPIO & 1) ? 0x01 : xfer_pio; - } + struct pci_dev *dev = HWIF(drive)->pci_dev; - timing = (xfer_pio >= pio) ? xfer_pio : pio; - - switch(timing) { - case 4: speed = XFER_PIO_4;break; - case 3: speed = XFER_PIO_3;break; - case 2: speed = XFER_PIO_2;break; - case 1: speed = XFER_PIO_1;break; - default: - speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - break; - } - (void) hpt3xx_tune_chipset(drive, speed); + if (hpt_minimum_revision(dev, 8)) + hpt374_tune_chipset(drive, speed); +#if 0 + else if (hpt_minimum_revision(dev, 7)) + hpt371_tune_chipset(drive, speed); + else if (hpt_minimum_revision(dev, 6)) + hpt302_tune_chipset(drive, speed); +#endif + else if (hpt_minimum_revision(dev, 5)) + hpt372_tune_chipset(drive, speed); + else if (hpt_minimum_revision(dev, 3)) + hpt370_tune_chipset(drive, speed); + else if (hpt_minimum_revision(dev, 2)) + hpt368_tune_chipset(drive, speed); + else + hpt366_tune_chipset(drive, speed); + + return ((int) ide_config_drive_speed(drive, speed)); } static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio) { byte speed; + + pio = ide_get_best_pio_mode(drive, pio, 5, NULL); switch(pio) { - case 4: speed = XFER_PIO_4;break; - case 3: speed = XFER_PIO_3;break; - case 2: speed = XFER_PIO_2;break; - case 1: speed = XFER_PIO_1;break; - default: speed = XFER_PIO_0;break; + case 4: speed = XFER_PIO_4; break; + case 3: speed = XFER_PIO_3; break; + case 2: speed = XFER_PIO_2; break; + case 1: speed = XFER_PIO_1; break; + default: speed = XFER_PIO_0; break; } (void) hpt3xx_tune_chipset(drive, speed); } @@ -660,54 +894,49 @@ static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; + byte mode = hpt3xx_ratemask(drive); byte speed = 0x00; - byte ultra66 = eighty_ninty_three(drive); - int rval; - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) - return ((int) ide_dma_off_quietly); + if (drive->media != ide_disk) + mode |= 0x08; - if ((id->dma_ultra & 0x0020) && - (!check_in_drive_lists(drive, bad_ata100_5)) && - (HPT370_ALLOW_ATA100_5) && - (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) && - (ultra66)) { - speed = XFER_UDMA_5; - } else if ((id->dma_ultra & 0x0010) && - (!check_in_drive_lists(drive, bad_ata66_4)) && - (HPT366_ALLOW_ATA66_4) && - (ultra66)) { - speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && - (!check_in_drive_lists(drive, bad_ata66_3)) && - (HPT366_ALLOW_ATA66_3) && - (ultra66)) { - speed = XFER_UDMA_3; - } else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) { - if (id->dma_ultra & 0x0004) { - speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0002) { - speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0001) { - speed = XFER_UDMA_0; - } - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else { - return ((int) ide_dma_off_quietly); + switch(mode) { + case 0x04: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_6; break; } + case 0x03: + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } + default: + return ((int) ide_dma_off_quietly); } (void) hpt3xx_tune_chipset(drive, speed); - rval = (int)( ((id->dma_ultra >> 11) & 7) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 14) & 3) ? ide_dma_on : + ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); - return rval; } int hpt3xx_quirkproc (ide_drive_t *drive) @@ -717,21 +946,22 @@ void hpt3xx_intrproc (ide_drive_t *drive) { - if (drive->quirk_list) { - /* drives in the quirk_list may not like intr setups/cleanups */ - } else { - OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); - } + if (drive->quirk_list) + return; + /* drives in the quirk_list may not like intr setups/cleanups */ + OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); } void hpt3xx_maskproc (ide_drive_t *drive, int mask) { + struct pci_dev *dev = HWIF(drive)->pci_dev; + if (drive->quirk_list) { - if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) { + if (hpt_minimum_revision(dev,3)) { byte reg5a = 0; - pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, ®5a); + pci_read_config_byte(dev, 0x5a, ®5a); if (((reg5a & 0x10) >> 4) != mask) - pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10)); + pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10)); } else { if (mask) { disable_irq(HWIF(drive)->irq); @@ -750,6 +980,8 @@ struct hd_driveid *id = drive->id; ide_dma_action_t dma_func = ide_dma_on; + drive->init_speed = 0; + if (id && (id->capability & 1) && HWIF(drive)->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { @@ -758,7 +990,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x002F) { + if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && @@ -789,7 +1021,7 @@ dma_func = ide_dma_off_quietly; no_dma_set: - config_chipset_for_pio(drive); + hpt3xx_tune_drive(drive, 5); } return HWIF(drive)->dmaproc(dma_func, drive); } @@ -802,60 +1034,71 @@ */ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { + struct pci_dev *dev = HWIF(drive)->pci_dev; + unsigned long dma_base = HWIF(drive)->dma_base; byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0; - unsigned long dma_base = HWIF(drive)->dma_base; switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); - case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ + case ide_dma_test_irq: + /* returns 1 if dma irq issued, 0 otherwise */ + dma_stat = IN_BYTE(dma_base+2); + /* return 1 if INTR asserted */ + return (dma_stat & 4) == 4; case ide_dma_lostirq: - pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); - pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, ®52h); - pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, ®5ah); - printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n", + pci_read_config_byte(dev, 0x50, ®50h); + pci_read_config_byte(dev, 0x52, ®52h); + pci_read_config_byte(dev, 0x5a, ®5ah); + printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x," + " reg5ah=0x%02x\n", drive->name, ide_dmafunc_verbose(func), reg50h, reg52h, reg5ah); if (reg5ah & 0x10) - pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10); - /* fall through to a reset */ + pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); #if 0 + /* how about we flush and reset, mmmkay? */ + pci_write_config_byte(dev, 0x51, 0x1F); + /* fall through to a reset */ case ide_dma_begin: case ide_dma_end: /* reset the chips state over and over.. */ - pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13); + pci_write_config_byte(dev, 0x51, 0x13); #endif break; case ide_dma_timeout: default: break; } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ + /* use standard DMA stuff */ + return ide_dmaproc(func, drive); } int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - unsigned long dma_base = hwif->dma_base; - byte regstate = hwif->channel ? 0x54 : 0x50; - byte reginfo = hwif->channel ? 0x56 : 0x52; + struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + byte regstate = hwif->channel ? 0x54 : 0x50; + byte reginfo = hwif->channel ? 0x56 : 0x52; byte dma_stat; switch (func) { case ide_dma_check: return config_drive_xfer_rate(drive); - case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ + case ide_dma_test_irq: + /* returns 1 if dma irq issued, 0 otherwise */ + dma_stat = IN_BYTE(dma_base+2); + /* return 1 if INTR asserted */ + return (dma_stat & 4) == 4; case ide_dma_end: - dma_stat = inb(dma_base + 2); + dma_stat = IN_BYTE(dma_base + 2); if (dma_stat & 0x01) { - udelay(20); /* wait a little */ - dma_stat = inb(dma_base + 2); + /* wait a little */ + udelay(20); + dma_stat = IN_BYTE(dma_base + 2); } if ((dma_stat & 0x01) == 0) break; @@ -865,29 +1108,70 @@ case ide_dma_timeout: case ide_dma_lostirq: - pci_read_config_byte(hwif->pci_dev, reginfo, - &dma_stat); + pci_read_config_byte(dev, reginfo, &dma_stat); printk("%s: %d bytes in FIFO\n", drive->name, dma_stat); - pci_write_config_byte(hwif->pci_dev, regstate, 0x37); + pci_write_config_byte(dev, regstate, 0x37); udelay(10); - dma_stat = inb(dma_base); - outb(dma_stat & ~0x1, dma_base); /* stop dma */ - dma_stat = inb(dma_base + 2); - outb(dma_stat | 0x6, dma_base+2); /* clear errors */ + dma_stat = IN_BYTE(dma_base); + /* stop dma */ + OUT_BYTE(dma_stat & ~0x1, dma_base); + dma_stat = IN_BYTE(dma_base + 2); + /* clear errors */ + OUT_BYTE(dma_stat | 0x6, dma_base+2); /* fallthrough */ #ifdef HPT_RESET_STATE_ENGINE case ide_dma_begin: #endif - pci_write_config_byte(hwif->pci_dev, regstate, 0x37); + pci_write_config_byte(dev, regstate, 0x37); udelay(10); break; default: break; } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ + /* use standard DMA stuff */ + return ide_dmaproc(func, drive); +} + +int hpt374_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + byte mscreg = hwif->channel ? 0x54 : 0x50; +// byte reginfo = hwif->channel ? 0x56 : 0x52; + byte dma_stat; + + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); + case ide_dma_test_irq: + /* returns 1 if dma irq issued, 0 otherwise */ + dma_stat = IN_BYTE(dma_base+2); +#if 0 /* do not set unless you know what you are doing */ + if (dma_stat & 4) { + byte stat = GET_STAT(); + OUT_BYTE(dma_base+2, dma_stat & 0xE4); + } +#endif + /* return 1 if INTR asserted */ + return (dma_stat & 4) == 4; + case ide_dma_end: + { + byte bwsr_mask = hwif->channel ? 0x02 : 0x01; + byte bwsr_stat, msc_stat; + pci_read_config_byte(dev, 0x6a, &bwsr_stat); + pci_read_config_byte(dev, mscreg, &msc_stat); + if ((bwsr_stat & bwsr_mask) == bwsr_mask) + pci_write_config_byte(dev, mscreg, msc_stat|0x30); + } + default: + break; + } + /* use standard DMA stuff */ + return ide_dmaproc(func, drive); } #endif /* CONFIG_BLK_DEV_IDEDMA */ @@ -949,7 +1233,8 @@ #define TRISTATE_BIT 0x8000 static int hpt370_busproc(ide_drive_t * drive, int state) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; byte tristate, resetmask, bus_reg; u16 tri_reg; @@ -969,8 +1254,8 @@ } /* grab status */ - pci_read_config_word(hwif->pci_dev, tristate, &tri_reg); - pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg); + pci_read_config_word(dev, tristate, &tri_reg); + pci_read_config_byte(dev, 0x59, &bus_reg); /* set the state. we don't set it if we don't need to do so. * make sure that the drive knows that it has failed if it's off */ @@ -1000,19 +1285,26 @@ bus_reg |= resetmask; break; } - pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg); - pci_write_config_word(hwif->pci_dev, tristate, tri_reg); + pci_write_config_byte(dev, 0x59, bus_reg); + pci_write_config_word(dev, tristate, tri_reg); return 0; } -static void __init init_hpt370(struct pci_dev *dev) +static void __init init_hpt37x(struct pci_dev *dev) { int adjust, i; u16 freq; u32 pll; byte reg5bh; +#if 1 + byte reg5ah = 0; + pci_read_config_byte(dev, 0x5a, ®5ah); + /* interrupt force enable */ + pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10)); +#endif + /* * default to pci clock. make sure MA15/16 are set to output * to prevent drives having problems with 40-pin cables. @@ -1027,18 +1319,39 @@ freq &= 0x1FF; if (freq < 0x9c) { pll = F_LOW_PCI_33; - dev->sysdata = (void *) thirty_three_base_hpt370; - printk("HPT370: using 33MHz PCI clock\n"); + if (hpt_minimum_revision(dev,8)) + dev->driver_data = (void *) thirty_three_base_hpt374; + else if (hpt_minimum_revision(dev,5)) + dev->driver_data = (void *) thirty_three_base_hpt372; + else if (hpt_minimum_revision(dev,4)) + dev->driver_data = (void *) thirty_three_base_hpt370a; + else + dev->driver_data = (void *) thirty_three_base_hpt370; + printk("HPT37X: using 33MHz PCI clock\n"); } else if (freq < 0xb0) { pll = F_LOW_PCI_40; } else if (freq < 0xc8) { pll = F_LOW_PCI_50; - dev->sysdata = (void *) fifty_base_hpt370; - printk("HPT370: using 50MHz PCI clock\n"); + if (hpt_minimum_revision(dev,8)) + BUG(); + else if (hpt_minimum_revision(dev,5)) + dev->driver_data = (void *) fifty_base_hpt372; + else if (hpt_minimum_revision(dev,4)) + dev->driver_data = (void *) fifty_base_hpt370a; + else + dev->driver_data = (void *) fifty_base_hpt370a; + printk("HPT37X: using 50MHz PCI clock\n"); } else { pll = F_LOW_PCI_66; - dev->sysdata = (void *) sixty_six_base_hpt370; - printk("HPT370: using 66MHz PCI clock\n"); + if (hpt_minimum_revision(dev,8)) + BUG(); + else if (hpt_minimum_revision(dev,5)) + dev->driver_data = (void *) sixty_six_base_hpt372; + else if (hpt_minimum_revision(dev,4)) + dev->driver_data = (void *) sixty_six_base_hpt370a; + else + dev->driver_data = (void *) sixty_six_base_hpt370; + printk("HPT37X: using 66MHz PCI clock\n"); } /* @@ -1048,8 +1361,8 @@ * don't like to use the PLL because it will cause glitches * on PRST/SRST when the HPT state engine gets reset. */ - if (dev->sysdata) - goto init_hpt370_done; + if (dev->driver_data) + goto init_hpt37X_done; /* * adjust PLL based upon PCI clock, enable it, and wait for @@ -1076,9 +1389,16 @@ pci_write_config_dword(dev, 0x5c, pll & ~0x100); pci_write_config_byte(dev, 0x5b, 0x21); - dev->sysdata = (void *) fifty_base_hpt370; - printk("HPT370: using 50MHz internal PLL\n"); - goto init_hpt370_done; + if (hpt_minimum_revision(dev,8)) + BUG(); + else if (hpt_minimum_revision(dev,5)) + dev->driver_data = (void *) fifty_base_hpt372; + else if (hpt_minimum_revision(dev,4)) + dev->driver_data = (void *) fifty_base_hpt370a; + else + dev->driver_data = (void *) fifty_base_hpt370a; + printk("HPT37X: using 50MHz internal PLL\n"); + goto init_hpt37X_done; } } pll_recal: @@ -1088,13 +1408,44 @@ pll += (adjust >> 1); } -init_hpt370_done: +init_hpt37X_done: /* reset state engine */ pci_write_config_byte(dev, 0x50, 0x37); pci_write_config_byte(dev, 0x54, 0x37); udelay(100); } +static void __init init_hpt366 (struct pci_dev *dev) +{ + unsigned int reg1 = 0; + byte drive_fast = 0; + + /* + * Disable the "fast interrupt" prediction. + */ + pci_read_config_byte(dev, 0x51, &drive_fast); + if (drive_fast & 0x80) + pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); + pci_read_config_dword(dev, 0x40, ®1); + + /* detect bus speed by looking at control reg timing: */ + switch((reg1 >> 8) & 7) { + case 5: + dev->driver_data = (void *) forty_base_hpt366; + break; + case 9: + dev->driver_data = (void *) twenty_five_base_hpt366; + break; + case 7: + default: + dev->driver_data = (void *) thirty_three_base_hpt366; + break; + } + + if (!dev->driver_data) + BUG(); +} + unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) { byte test = 0; @@ -1118,10 +1469,11 @@ if (test != 0x08) pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); - if (pci_rev_check_hpt3xx(dev)) { - init_hpt370(dev); + if (hpt_minimum_revision(dev, 3)) { + init_hpt37x(dev); hpt_devs[n_hpt_devs++] = dev; } else { + init_hpt366(dev); hpt_devs[n_hpt_devs++] = dev; } @@ -1137,7 +1489,7 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif) { - byte ata66 = 0; + byte ata66 = 0; byte regmask = (hwif->channel) ? 0x01 : 0x02; pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66); @@ -1151,13 +1503,12 @@ void __init ide_init_hpt366 (ide_hwif_t *hwif) { - int hpt_rev; - - hwif->tuneproc = &hpt3xx_tune_drive; - hwif->speedproc = &hpt3xx_tune_chipset; - hwif->quirkproc = &hpt3xx_quirkproc; - hwif->intrproc = &hpt3xx_intrproc; - hwif->maskproc = &hpt3xx_maskproc; + struct pci_dev *dev = hwif->pci_dev; + hwif->tuneproc = &hpt3xx_tune_drive; + hwif->speedproc = &hpt3xx_tune_chipset; + hwif->quirkproc = &hpt3xx_quirkproc; + hwif->intrproc = &hpt3xx_intrproc; + hwif->maskproc = &hpt3xx_maskproc; #ifdef HPT_SERIALIZE_IO /* serialize access to this device */ @@ -1165,59 +1516,58 @@ hwif->serialized = hwif->mate->serialized = 1; #endif - hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev); - if (hpt_rev) { - /* set up ioctl for power status. note: power affects both - * drives on each channel */ - hwif->busproc = &hpt370_busproc; - } - - if (pci_rev2_check_hpt3xx(hwif->pci_dev)) { - /* do nothing now but will split device types */ + if (hpt_minimum_revision(dev,3)) { + byte reg5ah = 0; + pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); + /* + * set up ioctl for power status. + * note: power affects both + * drives on each channel + */ + hwif->resetproc = &hpt3xx_reset; + hwif->busproc = &hpt370_busproc; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + } else if (hpt_minimum_revision(dev,2)) { + hwif->resetproc = &hpt3xx_reset; + hwif->busproc = &hpt3xx_tristate; + } else { hwif->resetproc = &hpt3xx_reset; -/* - * don't do until we can parse out the cobalt box argh ... - * hwif->busproc = &hpt3xx_tristate; - */ + hwif->busproc = &hpt3xx_tristate; } + if (!hwif->dma_base) + return; + #ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) { - if (hpt_rev) { - byte reg5ah = 0; - pci_read_config_byte(hwif->pci_dev, 0x5a, ®5ah); - if (reg5ah & 0x10) /* interrupt force enable */ - pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10); - hwif->dmaproc = &hpt370_dmaproc; - } else { - hwif->dmaproc = &hpt366_dmaproc; - } - if (!noautodma) - hwif->autodma = 1; - else - hwif->autodma = 0; - } else { - hwif->autodma = 0; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - } -#else /* !CONFIG_BLK_DEV_IDEDMA */ - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - hwif->autodma = 0; + if (hpt_minimum_revision(dev,8)) + hwif->dmaproc = &hpt374_dmaproc; + else if (hpt_minimum_revision(dev,5)) + hwif->dmaproc = &hpt374_dmaproc; + else if (hpt_minimum_revision(dev,3)) + hwif->dmaproc = &hpt370_dmaproc; + else if (hpt_minimum_revision(dev,2)) + hwif->dmaproc = &hpt366_dmaproc; + else + hwif->dmaproc = &hpt366_dmaproc; + + +#ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* CONFIG_BLK_DEV_IDEDMA */ } void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase) { byte masterdma = 0, slavedma = 0; - byte dma_new = 0, dma_old = inb(dmabase+2); + byte dma_new = 0, dma_old = IN_BYTE(dmabase+2); byte primary = hwif->channel ? 0x4b : 0x43; byte secondary = hwif->channel ? 0x4f : 0x47; unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); dma_new = dma_old; pci_read_config_byte(hwif->pci_dev, primary, &masterdma); @@ -1225,9 +1575,121 @@ if (masterdma & 0x30) dma_new |= 0x20; if (slavedma & 0x30) dma_new |= 0x40; - if (dma_new != dma_old) outb(dma_new, dmabase+2); + if (dma_new != dma_old) OUT_BYTE(dma_new, dmabase+2); - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); ide_setup_dma(hwif, dmabase, 8); } + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_hpt374 (struct pci_dev *dev, ide_pci_device_t *d) +{ + struct pci_dev *dev2 = NULL, *findev; + ide_pci_device_t *d2; + + if (PCI_FUNC(dev->devfn) & 1) + return; + + pci_for_each_dev(findev) { + if ((findev->vendor == dev->vendor) && + (findev->device == dev->device) && + ((findev->devfn - dev->devfn) == 1) && + (PCI_FUNC(findev->devfn) & 1)) { + dev2 = findev; + break; + } + } + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + if (!dev2) { + return; + } else { + byte irq = 0, irq2 = 0; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2); + if (irq != irq2) { + pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq); + dev2->irq = dev->irq; + printk("%s: pci-config space interrupt fixed.\n", + d->name); + } + } + d2 = d; + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d2->name, dev2->bus->number, dev2->devfn); + ide_setup_pci_device(dev2, d2); + +} + +void __init fixup_device_hpt366 (struct pci_dev *dev, ide_pci_device_t *d) +{ + struct pci_dev *dev2 = NULL, *findev; + ide_pci_device_t *d2; + unsigned char pin1 = 0, pin2 = 0; + unsigned int class_rev; + char *chipset_names[] = {"HPT366", "HPT366", "HPT368", + "HPT370", "HPT370A", "HPT372"}; + + if (PCI_FUNC(dev->devfn) & 1) + return; + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + + strcpy(d->name, chipset_names[class_rev]); + + switch(class_rev) { + case 5: + case 4: + case 3: printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + return; + default: break; + } + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); + pci_for_each_dev(findev) { + if ((findev->vendor == dev->vendor) && + (findev->device == dev->device) && + ((findev->devfn - dev->devfn) == 1) && + (PCI_FUNC(findev->devfn) & 1)) { + dev2 = findev; + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); + hpt363_shared_pin = (pin1 != pin2) ? 1 : 0; + hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0; + if (hpt363_shared_pin && hpt363_shared_irq) { + d->bootable = ON_BOARD; + printk("%s: onboard version of chipset, " + "pin1=%d pin2=%d\n", d->name, + pin1, pin2); +#if 0 + /* + * This is the third undocumented detection + * method and is generally required for the + * ABIT-BP6 boards. + */ + pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq); + printk("PCI: %s: Fixing interrupt %d pin %d " + "to ZERO \n", d->name, dev2->irq, pin2); + pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0); +#endif + } + break; + } + } + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + if (!dev2) + return; + d2 = d; + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d2->name, dev2->bus->number, dev2->devfn); + ide_setup_pci_device(dev2, d2); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ht6560b.c linux.20pre2-ac1/drivers/ide/ht6560b.c --- linux.20pre2/drivers/ide/ht6560b.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ht6560b.c 2002-08-06 15:42:11.000000000 +0100 @@ -134,8 +134,7 @@ static byte current_timing = 0; byte select, timing; - __save_flags (flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); select = HT_CONFIG(drive); timing = HT_TIMING(drive); @@ -145,21 +144,22 @@ current_timing = timing; if (drive->media != ide_disk || !drive->present) select |= HT_PREFETCH_MODE; - (void) inb(HT_CONFIG_PORT); - (void) inb(HT_CONFIG_PORT); - (void) inb(HT_CONFIG_PORT); - (void) inb(HT_CONFIG_PORT); - outb(select, HT_CONFIG_PORT); + (void) IN_BYTE(HT_CONFIG_PORT); + (void) IN_BYTE(HT_CONFIG_PORT); + (void) IN_BYTE(HT_CONFIG_PORT); + (void) IN_BYTE(HT_CONFIG_PORT); + OUT_BYTE(select, HT_CONFIG_PORT); /* * Set timing for this drive: */ - outb(timing, IDE_SELECT_REG); - (void) inb(IDE_STATUS_REG); + OUT_BYTE(timing, IDE_SELECT_REG); + (void) IN_BYTE(IDE_STATUS_REG); #ifdef DEBUG - printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing); + printk("ht6560b: %s: select=%#x timing=%#x\n", + drive->name, select, timing); #endif } - __restore_flags (flags); /* local CPU only */ + local_irq_restore(flags); } /* @@ -171,27 +171,27 @@ int i; /* Autodetect ht6560b */ - if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff) + if ((orig_value = IN_BYTE(HT_CONFIG_PORT)) == 0xff) return 0; for (i=3;i>0;i--) { - outb(0x00, HT_CONFIG_PORT); - if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) { - outb(orig_value, HT_CONFIG_PORT); + OUT_BYTE(0x00, HT_CONFIG_PORT); + if (!( (~IN_BYTE(HT_CONFIG_PORT)) & 0x3f )) { + OUT_BYTE(orig_value, HT_CONFIG_PORT); return 0; } } - outb(0x00, HT_CONFIG_PORT); - if ((~inb(HT_CONFIG_PORT))& 0x3f) { - outb(orig_value, HT_CONFIG_PORT); + OUT_BYTE(0x00, HT_CONFIG_PORT); + if ((~IN_BYTE(HT_CONFIG_PORT))& 0x3f) { + OUT_BYTE(orig_value, HT_CONFIG_PORT); return 0; } /* * Ht6560b autodetected */ - outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT); - outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */ - (void) inb(0x1f7); /* IDE_STATUS_REG */ + OUT_BYTE(HT_CONFIG_DEFAULT, HT_CONFIG_PORT); + OUT_BYTE(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */ + (void) IN_BYTE(0x1f7); /* IDE_STATUS_REG */ printk("\nht6560b " HT6560B_VERSION ": chipset detected and initialized" @@ -257,8 +257,7 @@ unsigned long flags; int t = HT_PREFETCH_MODE << 8; - save_flags (flags); /* all CPUs */ - cli(); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); /* * Prefetch mode and unmask irq seems to conflict @@ -272,7 +271,7 @@ drive->no_unmask = 0; } - restore_flags (flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); #ifdef DEBUG printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis")); @@ -293,13 +292,12 @@ timing = ht_pio2timings(drive, pio); - save_flags (flags); /* all CPUs */ - cli(); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); drive->drive_data &= 0xff00; drive->drive_data |= timing; - restore_flags (flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); #ifdef DEBUG printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/icside.c linux.20pre2-ac1/drivers/ide/icside.c --- linux.20pre2/drivers/ide/icside.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/icside.c 2002-08-06 15:42:11.000000000 +0100 @@ -26,8 +26,6 @@ #include #include -extern char *ide_xfer_verbose (byte xfer_rate); - /* * Maximum number of interfaces per card */ @@ -94,7 +92,7 @@ static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) { unsigned int memc_port = (unsigned int)ec->irq_data; - outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET); + OUT_BYTE(0, memc_port + ICS_ARCIN_V5_INTROFFSET); } /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) @@ -103,7 +101,7 @@ static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) { unsigned int memc_port = (unsigned int)ec->irq_data; - inb (memc_port + ICS_ARCIN_V5_INTROFFSET); + IN_BYTE(memc_port + ICS_ARCIN_V5_INTROFFSET); } static const expansioncard_ops_t icside_ops_arcin_v5 = { @@ -124,8 +122,8 @@ { unsigned int ide_base_port = (unsigned int)ec->irq_data; - outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); - outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); + OUT_BYTE(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); + OUT_BYTE(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); } /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) @@ -135,8 +133,8 @@ { unsigned int ide_base_port = (unsigned int)ec->irq_data; - inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); - inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); + IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); + IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); } /* Prototype: icside_irqprobe(struct expansion_card *ec) @@ -146,8 +144,8 @@ { unsigned int ide_base_port = (unsigned int)ec->irq_data; - return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || - inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; + return IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || + IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; } static const expansioncard_ops_t icside_ops_arcin_v6 = { @@ -173,10 +171,10 @@ addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET; - id = inb (addr) & 1; - id |= (inb (addr + 1) & 1) << 1; - id |= (inb (addr + 2) & 1) << 2; - id |= (inb (addr + 3) & 1) << 3; + id = IN_BYTE(addr) & 1; + id |= (IN_BYTE(addr + 1) & 1) << 1; + id |= (IN_BYTE(addr + 2) & 1) << 2; + id |= (IN_BYTE(addr + 3) & 1) << 3; switch (id) { case 0: /* A3IN */ @@ -334,14 +332,14 @@ rq = HWGROUP(drive)->rq; for (i = rq->nr_sectors; i > 0;) { i -= rq->current_nr_sectors; - ide_end_request(1, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 1); } return ide_stopped; } printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat); } - return ide_error(drive, "dma_intr", stat); + return DRIVER(drive)->error(drive, "dma_intr", stat); } /* @@ -493,6 +491,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); +// ide_task_t *args = HWGROUP(drive)->rq->special; int count, reading = 0; switch (func) { @@ -519,7 +518,7 @@ /* Route the DMA signals to * to the correct interface. */ - outb(hwif->select_data, hwif->config_data); + OUT_BYTE(hwif->select_data, hwif->config_data); /* Select the correct timing * for this drive @@ -534,10 +533,27 @@ if (drive->media != ide_disk) return 0; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL); - OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, - IDE_COMMAND_REG); - + /* + * FIX ME to use only ACB ide_task_t args Struct + */ +#if 0 + { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } +#else + if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } else if (drive->addressing == 1) + OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); + else + OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); +#endif + return HWIF(drive)->dmaproc(ide_dma_begin, drive); case ide_dma_begin: enable_dma(hwif->hw.dma); return 0; @@ -549,7 +565,7 @@ return get_dma_residue(hwif->hw.dma) != 0; case ide_dma_test_irq: - return inb((unsigned long)hwif->hw.priv) & 1; + return IN_BYTE((unsigned long)hwif->hw.priv) & 1; case ide_dma_bad_drive: case ide_dma_good_drive: @@ -660,7 +676,7 @@ /* * Be on the safe side - disable interrupts */ - inb(slot_port + ICS_ARCIN_V5_INTROFFSET); + IN_BYTE(slot_port + ICS_ARCIN_V5_INTROFFSET); hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq); @@ -681,7 +697,7 @@ else sel = 1 << 5; - outb(sel, slot_port); + OUT_BYTE(sel, slot_port); ec->irq_data = (void *)port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6; @@ -689,8 +705,8 @@ /* * Be on the safe side - disable interrupts */ - inb(port + ICS_ARCIN_V6_INTROFFSET_1); - inb(port + ICS_ARCIN_V6_INTROFFSET_2); + IN_BYTE(port + ICS_ARCIN_V6_INTROFFSET_1); + IN_BYTE(port + ICS_ARCIN_V6_INTROFFSET_2); hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq); mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide.c linux.20pre2-ac1/drivers/ide/ide.c --- linux.20pre2/drivers/ide/ide.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide.c 2002-08-13 14:23:01.000000000 +0100 @@ -163,16 +163,6 @@ #include #endif /* CONFIG_KMOD */ -#ifdef CONFIG_IDE_TASKFILE_IO -# define __TASKFILE__IO -#else /* CONFIG_IDE_TASKFILE_IO */ -# undef __TASKFILE__IO -#endif /* CONFIG_IDE_TASKFILE_IO */ - -#ifdef __TASKFILE__IO -#else /* !__TASKFILE__IO */ -#endif /* __TASKFILE__IO */ - /* default maximum number of failures */ #define IDE_DEFAULT_MAX_FAILURES 1 @@ -217,13 +207,12 @@ unsigned long t, flags; int i; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); - i |= inb(0x40) << 8; - __restore_flags(flags); /* local CPU only */ + i |= IN_BYTE(0x40) << 8; + local_irq_restore(flags); return (t - i); } #endif /* DISK_RECOVERY_TIME */ @@ -373,198 +362,17 @@ return system_bus_speed; } -#if SUPPORT_VLB_SYNC -/* - * Some localbus EIDE interfaces require a special access sequence - * when using 32-bit I/O instructions to transfer data. We call this - * the "vlb_sync" sequence, which consists of three successive reads - * of the sector count register location, with interrupts disabled - * to ensure that the reads all happen together. - */ -static inline void do_vlb_sync (ide_ioreg_t port) { - (void) inb (port); - (void) inb (port); - (void) inb (port); -} -#endif /* SUPPORT_VLB_SYNC */ - -/* - * This is used for most PIO data transfers *from* the IDE interface - */ -void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - byte io_32bit; - - /* first check if this controller has defined a special function - * for handling polled ide transfers - */ - - if(HWIF(drive)->ideproc) { - HWIF(drive)->ideproc(ideproc_ide_input_data, - drive, buffer, wcount); - return; - } - - io_32bit = drive->io_32bit; - - if (io_32bit) { -#if SUPPORT_VLB_SYNC - if (io_32bit & 2) { - unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - do_vlb_sync(IDE_NSECTOR_REG); - insl(IDE_DATA_REG, buffer, wcount); - __restore_flags(flags); /* local CPU only */ - } else -#endif /* SUPPORT_VLB_SYNC */ - insl(IDE_DATA_REG, buffer, wcount); - } else { -#if SUPPORT_SLOW_DATA_PORTS - if (drive->slow) { - unsigned short *ptr = (unsigned short *) buffer; - while (wcount--) { - *ptr++ = inw_p(IDE_DATA_REG); - *ptr++ = inw_p(IDE_DATA_REG); - } - } else -#endif /* SUPPORT_SLOW_DATA_PORTS */ - insw(IDE_DATA_REG, buffer, wcount<<1); - } -} - -/* - * This is used for most PIO data transfers *to* the IDE interface - */ -void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - byte io_32bit; - - if(HWIF(drive)->ideproc) { - HWIF(drive)->ideproc(ideproc_ide_output_data, - drive, buffer, wcount); - return; - } - - io_32bit = drive->io_32bit; - - if (io_32bit) { -#if SUPPORT_VLB_SYNC - if (io_32bit & 2) { - unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - do_vlb_sync(IDE_NSECTOR_REG); - outsl(IDE_DATA_REG, buffer, wcount); - __restore_flags(flags); /* local CPU only */ - } else -#endif /* SUPPORT_VLB_SYNC */ - outsl(IDE_DATA_REG, buffer, wcount); - } else { -#if SUPPORT_SLOW_DATA_PORTS - if (drive->slow) { - unsigned short *ptr = (unsigned short *) buffer; - while (wcount--) { - outw_p(*ptr++, IDE_DATA_REG); - outw_p(*ptr++, IDE_DATA_REG); - } - } else -#endif /* SUPPORT_SLOW_DATA_PORTS */ - outsw(IDE_DATA_REG, buffer, wcount<<1); - } -} - -/* - * The following routines are mainly used by the ATAPI drivers. - * - * These routines will round up any request for an odd number of bytes, - * so if an odd bytecount is specified, be sure that there's at least one - * extra byte allocated for the buffer. - */ -void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) -{ - if(HWIF(drive)->ideproc) { - HWIF(drive)->ideproc(ideproc_atapi_input_bytes, - drive, buffer, bytecount); - return; - } - - ++bytecount; -#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) - if (MACH_IS_ATARI || MACH_IS_Q40) { - /* Atari has a byte-swapped IDE interface */ - insw_swapw(IDE_DATA_REG, buffer, bytecount / 2); - return; - } -#endif /* CONFIG_ATARI */ - ide_input_data (drive, buffer, bytecount / 4); - if ((bytecount & 0x03) >= 2) - insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); -} - -void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) -{ - if(HWIF(drive)->ideproc) { - HWIF(drive)->ideproc(ideproc_atapi_output_bytes, - drive, buffer, bytecount); - return; - } - - ++bytecount; -#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) - if (MACH_IS_ATARI || MACH_IS_Q40) { - /* Atari has a byte-swapped IDE interface */ - outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2); - return; - } -#endif /* CONFIG_ATARI */ - ide_output_data (drive, buffer, bytecount / 4); - if ((bytecount & 0x03) >= 2) - outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); -} - -/* - * Needed for PCI irq sharing - */ -//static inline -int drive_is_ready (ide_drive_t *drive) -{ - byte stat = 0; - if (drive->waiting_for_dma) - return HWIF(drive)->dmaproc(ide_dma_test_irq, drive); -#if 0 - udelay(1); /* need to guarantee 400ns since last command was issued */ -#endif - -#ifdef CONFIG_IDEPCI_SHARE_IRQ - /* - * We do a passive status test under shared PCI interrupts on - * cards that truly share the ATA side interrupt, but may also share - * an interrupt with another pci card/device. We make no assumptions - * about possible isa-pnp and pci-pnp issues yet. - */ - if (IDE_CONTROL_REG) - stat = GET_ALTSTAT(); - else -#endif /* CONFIG_IDEPCI_SHARE_IRQ */ - stat = GET_STAT(); /* Note: this may clear a pending IRQ!! */ - - if (stat & BUSY_STAT) - return 0; /* drive busy: definitely not interrupting */ - return 1; /* drive ready: *might* be interrupting */ -} - /* * This is our end_request replacement function. */ -void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup) +int ide_end_request (ide_drive_t *drive, int uptodate) { struct request *rq; unsigned long flags; - ide_drive_t *drive = hwgroup->drive; + int ret = 1; spin_lock_irqsave(&io_request_lock, flags); - rq = hwgroup->rq; + rq = HWGROUP(drive)->rq; /* * decide whether to reenable DMA -- 3 is a random magic for now, @@ -572,16 +380,18 @@ */ if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { drive->state = 0; - hwgroup->hwif->dmaproc(ide_dma_on, drive); + HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive); } - if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) { + if (!end_that_request_first(rq, uptodate, drive->name)) { add_blkdev_randomness(MAJOR(rq->rq_dev)); blkdev_dequeue_request(rq); - hwgroup->rq = NULL; + HWGROUP(drive)->rq = NULL; end_that_request_last(rq); + ret = 0; } spin_unlock_irqrestore(&io_request_lock, flags); + return ret; } /* @@ -666,7 +476,9 @@ if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) { printk("%s: ATAPI reset complete\n", drive->name); } else { - if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { + if (time_before(jiffies, hwgroup->poll_timeout)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); return ide_started; /* continue polling */ } @@ -691,7 +503,9 @@ byte tmp; if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { - if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { + if (time_before(jiffies, hwgroup->poll_timeout)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); return ide_started; /* continue polling */ } @@ -784,8 +598,7 @@ ide_hwif_t *hwif = HWIF(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive); - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { @@ -794,8 +607,10 @@ udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); - __restore_flags (flags); /* local CPU only */ + local_irq_restore(flags); return ide_started; } @@ -808,7 +623,7 @@ #if OK_TO_RESET_CONTROLLER if (!IDE_CONTROL_REG) { - __restore_flags(flags); + local_irq_restore(flags); return ide_stopped; } /* @@ -828,6 +643,8 @@ } udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); /* @@ -840,7 +657,7 @@ #endif /* OK_TO_RESET_CONTROLLER */ - __restore_flags (flags); /* local CPU only */ + local_irq_restore(flags); return ide_started; } @@ -875,7 +692,9 @@ case IDE_DRIVE_CMD: { byte *args = (byte *) rq->buffer; - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (rq->errors == 0) + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args) { args[0] = stat; args[1] = err; @@ -886,7 +705,9 @@ case IDE_DRIVE_TASK: { byte *args = (byte *) rq->buffer; - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (rq->errors == 0) + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args) { args[0] = stat; args[1] = err; @@ -901,7 +722,9 @@ case IDE_DRIVE_TASKFILE: { ide_task_t *args = (ide_task_t *) rq->special; - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (rq->errors == 0) + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args) { if (args->tf_in_flags.b.data) { unsigned short data = IN_WORD(IDE_DATA_REG); @@ -947,8 +770,7 @@ unsigned long flags; byte err = 0; - __save_flags (flags); /* local CPU only */ - ide__sti(); /* local CPU only */ + local_irq_set(flags); printk("%s: %s: status=0x%02x", drive->name, msg, stat); #if FANCY_STATUS_DUMPS printk(" { "); @@ -1016,7 +838,7 @@ #endif /* FANCY_STATUS_DUMPS */ printk("\n"); } - __restore_flags (flags); /* local CPU only */ + local_irq_restore(flags); return err; } @@ -1037,11 +859,15 @@ u32 buffer[16]; unsigned int wcount = (i > 16) ? 16 : i; i -= wcount; - ide_input_data (drive, buffer, wcount); + ata_input_data (drive, buffer, wcount); } } /* + * FIXME Add an ATAPI error + */ + +/* * ide_error() takes action based on the error returned by the drive. */ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat) @@ -1068,6 +894,8 @@ if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { + +/* ide_disk */ if (drive->media == ide_disk && (stat & ERR_STAT)) { /* err has different meaning on cdrom and tape */ if (err == ABRT_ERR) { @@ -1080,17 +908,19 @@ else if (err & TRK0_ERR) /* help it find track zero */ rq->errors |= ERROR_RECAL; } +/* !ide_disk */ if ((stat & DRQ_STAT) && rq->cmd != WRITE) try_to_flush_leftover_data(drive); +/* !ide_disk */ } if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); /* force an abort */ if (rq->errors >= ERROR_MAX) { if (drive->driver != NULL) - DRIVER(drive)->end_request(0, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 0); else - ide_end_request(0, HWGROUP(drive)); + ide_end_request(drive, 0); } else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { ++rq->errors; @@ -1109,6 +939,8 @@ */ void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, handler, WAIT_CMD, NULL); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ @@ -1127,18 +959,18 @@ byte stat = GET_STAT(); int retries = 10; - ide__sti(); /* local CPU only */ + local_irq_enable(); if ((stat & DRQ_STAT) && args && args[3]) { byte io_32bit = drive->io_32bit; drive->io_32bit = 0; - ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS); + ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS); drive->io_32bit = io_32bit; while (((stat = GET_STAT()) & BUSY_STAT) && retries--) udelay(100); } if (!OK_STAT(stat, READY_STAT, BAD_STAT)) - return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ + return DRIVER(drive)->error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ ide_end_drive_cmd (drive, stat, GET_ERR()); return ide_stopped; } @@ -1155,10 +987,9 @@ printk("%s: do_special: 0x%02x\n", drive->name, s->all); #endif if (s->b.set_tune) { - ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; s->b.set_tune = 0; - if (tuneproc != NULL) - tuneproc(drive, drive->tune_req); + if (HWIF(drive)->tuneproc != NULL) + HWIF(drive)->tuneproc(drive, drive->tune_req); } else if (drive->driver != NULL) { return DRIVER(drive)->special(drive); } else if (s->all) { @@ -1169,58 +1000,6 @@ } /* - * This routine busy-waits for the drive status to be not "busy". - * It then checks the status for all of the "good" bits and none - * of the "bad" bits, and if all is okay it returns 0. All other - * cases return 1 after invoking ide_error() -- caller should just return. - * - * This routine should get fixed to not hog the cpu during extra long waits.. - * That could be done by busy-waiting for the first jiffy or two, and then - * setting a timer to wake up at half second intervals thereafter, - * until timeout is achieved, before timing out. - */ -int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) { - byte stat; - int i; - unsigned long flags; - - /* bail early if we've exceeded max_failures */ - if (drive->max_failures && (drive->failures > drive->max_failures)) { - *startstop = ide_stopped; - return 1; - } - - udelay(1); /* spec allows drive 400ns to assert "BUSY" */ - if ((stat = GET_STAT()) & BUSY_STAT) { - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only */ - timeout += jiffies; - while ((stat = GET_STAT()) & BUSY_STAT) { - if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(flags); /* local CPU only */ - *startstop = ide_error(drive, "status timeout", stat); - return 1; - } - } - __restore_flags(flags); /* local CPU only */ - } - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - * This fix courtesy of Matthew Faupel & Niccolo Rigacci. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = GET_STAT()), good, bad)) - return 0; - } - *startstop = ide_error(drive, "status error", stat); - return 1; -} - -/* * execute_drive_cmd() issues a special drive command, * usually initiated by ioctl() from the external hdparm program. */ @@ -1233,43 +1012,9 @@ if (!(args)) break; -#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG - { - printk(KERN_INFO "%s: ", drive->name); -// printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]); - printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]); - printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]); - printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]); - printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]); - printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]); - printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]); - printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]); - printk(KERN_INFO "%s: ", drive->name); -// printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]); - printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]); - printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]); - printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]); - printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]); - printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]); - printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]); - printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]); - } -#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ - -// if (args->tf_out_flags.all == 0) { - do_taskfile(drive, - (struct hd_drive_task_hdr *)&args->tfRegister, - (struct hd_drive_hob_hdr *)&args->hobRegister, - args->handler); -// } else { -// return flagged_taskfile(drive, args); -// } - - if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) || - (args->command_type == IDE_DRIVE_TASK_OUT)) && - args->prehandler && args->handler) - return args->prehandler(drive, rq); - return ide_started; + if (args->tf_out_flags.all != 0) + return flagged_taskfile(drive, args); + return do_rw_taskfile(drive, args); } case IDE_DRIVE_TASK: { @@ -1349,15 +1094,26 @@ ide_hwif_t *hwif = HWIF(drive); #ifdef DEBUG - printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); + printk("%s: start_request: current=0x%08lx\n", + hwif->name, (unsigned long) rq); #endif + /* bail early if we've exceeded max_failures */ if (drive->max_failures && (drive->failures > drive->max_failures)) { goto kill_rq; } + /* + * bail early if we've sent a device to sleep, however how to wake + * this needs to be a masked flag. FIXME for proper operations. + */ + if (drive->suspend_reset) { + goto kill_rq; + } + if (unit >= MAX_DRIVES) { - printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev)); + printk("%s: bad device number: %s\n", + hwif->name, kdevname(rq->rq_dev)); goto kill_rq; } #ifdef DEBUG @@ -1396,6 +1152,7 @@ switch(rq->cmd) { case IDE_DRIVE_CMD: case IDE_DRIVE_TASK: + return execute_drive_cmd(drive, rq); case IDE_DRIVE_TASKFILE: return execute_drive_cmd(drive, rq); default: @@ -1410,25 +1167,16 @@ return do_special(drive); kill_rq: if (drive->driver != NULL) - DRIVER(drive)->end_request(0, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 0); else - ide_end_request(0, HWGROUP(drive)); + ide_end_request(drive, 0); return ide_stopped; } -ide_startstop_t restart_request (ide_drive_t *drive) +int restart_request (ide_drive_t *drive, struct request *rq) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); - unsigned long flags; - struct request *rq; - - spin_lock_irqsave(&io_request_lock, flags); - hwgroup->handler = NULL; - del_timer(&hwgroup->timer); - rq = hwgroup->rq; - spin_unlock_irqrestore(&io_request_lock, flags); - - return start_request(drive, rq); + (void) start_request(drive, rq); + return 0; } /* @@ -1455,7 +1203,7 @@ best = NULL; drive = hwgroup->drive; do { - if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) { + if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) { if (!best || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) @@ -1468,10 +1216,10 @@ if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) { long t = (signed long)(WAKEUP(best) - jiffies); if (t >= WAIT_MIN_SLEEP) { - /* - * We *may* have some time to spare, but first let's see if - * someone can potentially benefit from our nice mood today.. - */ + /* + * We *may* have some time to spare, but first let's see if + * someone can potentially benefit from our nice mood today.. + */ drive = best->next; do { if (!drive->sleep @@ -1534,7 +1282,8 @@ ide_get_lock(&ide_lock, ide_intr, hwgroup); /* for atari only: POSSIBLY BROKEN HERE(?) */ - __cli(); /* necessary paranoia: ensure IRQs are masked on local CPU */ + local_irq_disable(); + /* necessary paranoia: ensure IRQs are masked on local CPU */ while (!hwgroup->busy) { hwgroup->busy = 1; @@ -1548,13 +1297,13 @@ sleep = drive->sleep; } while ((drive = drive->next) != hwgroup->drive); if (sleep) { - /* - * Take a short snooze, and then wake up this hwgroup again. - * This gives other hwgroups on the same a chance to - * play fairly with us, just in case there are big differences - * in relative throughputs.. don't want to hog the cpu too much. - */ - if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) + /* + * Take a short snooze, and then wake up this hwgroup again. + * This gives other hwgroups on the same a chance to + * play fairly with us, just in case there are big differences + * in relative throughputs.. don't want to hog the cpu too much. + */ + if (time_before(sleep, jiffies + WAIT_MIN_SLEEP)) sleep = jiffies + WAIT_MIN_SLEEP; #if 1 if (timer_pending(&hwgroup->timer)) @@ -1595,7 +1344,8 @@ if (masked_irq && hwif->irq != masked_irq) disable_irq_nosync(hwif->irq); spin_unlock(&io_request_lock); - ide__sti(); /* allow other IRQs while we start this request */ + local_irq_enable(); + /* allow other IRQs while we start this request */ startstop = start_request(drive, rq); spin_lock_irq(&io_request_lock); if (masked_irq && hwif->irq != masked_irq) @@ -1623,6 +1373,7 @@ ide_do_request(q->queuedata, 0); } +#ifndef __IDEDMA_TIMEOUT /* * un-busy the hwgroup etc, and clear any pending DMA status. we want to * retry the current request in pio mode instead of risking tossing it @@ -1663,8 +1414,17 @@ rq->errors = 0; rq->sector = rq->bh->b_rsector; rq->current_nr_sectors = rq->bh->b_size >> 9; + rq->hard_cur_sectors = rq->current_nr_sectors; rq->buffer = rq->bh->b_data; + + /* + * FIXME or DELETE ME + * + * so what do we do if the device is left in an invalid state + * and will not accept commands. SOFT RESET is the only chance. + */ } +#endif /* * ide_timer_expiry() is our timeout function for all drive operations. @@ -1700,7 +1460,7 @@ hwgroup->handler = NULL; } else { ide_hwif_t *hwif; - ide_startstop_t startstop; + ide_startstop_t startstop = ide_stopped; if (!hwgroup->busy) { hwgroup->busy = 1; /* paranoia */ printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name); @@ -1728,7 +1488,8 @@ #else disable_irq(hwif->irq); /* disable_irq_nosync ?? */ #endif /* DISABLE_IRQ_NOSYNC */ - __cli(); /* local CPU only, as if we were handling an interrupt */ + local_irq_disable(); + /* local CPU only, as if we were handling an interrupt */ if (hwgroup->poll_timeout != 0) { startstop = handler(drive); } else if (drive_is_ready(drive)) { @@ -1739,10 +1500,16 @@ startstop = handler(drive); } else { if (drive->waiting_for_dma) { +#ifndef __IDEDMA_TIMEOUT startstop = ide_stopped; ide_dma_timeout_retry(drive); +#else /* __IDEDMA_TIMEOUT */ + (void) hwgroup->hwif->dmaproc(ide_dma_end, drive); + printk("%s: timeout waiting for DMA\n", drive->name); + (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive); +#endif /* __IDEDMA_TIMEOUT */ } else - startstop = ide_error(drive, "irq timeout", GET_STAT()); + startstop = DRIVER(drive)->error(drive, "irq timeout", GET_STAT()); } set_recovery_timer(hwif); drive->service_time = jiffies - drive->service_start; @@ -1794,7 +1561,7 @@ /* Try to not flood the console with msgs */ static unsigned long last_msgtime, count; ++count; - if (0 < (signed long)(jiffies - (last_msgtime + HZ))) { + if (time_after(jiffies, last_msgtime + HZ)) { last_msgtime = jiffies; printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n", hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count); @@ -1849,7 +1616,8 @@ #ifdef CONFIG_BLK_DEV_IDEPCI } else { /* - * Whack the status register, just in case we have a leftover pending IRQ. + * Whack the status register, just in case + * we have a leftover pending IRQ. */ (void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); #endif /* CONFIG_BLK_DEV_IDEPCI */ @@ -1860,16 +1628,18 @@ drive = hwgroup->drive; if (!drive) { /* - * This should NEVER happen, and there isn't much we could do about it here. + * This should NEVER happen, and there isn't much + * we could do about it here. */ spin_unlock_irqrestore(&io_request_lock, flags); return; } if (!drive_is_ready(drive)) { /* - * This happens regularly when we share a PCI IRQ with another device. - * Unfortunately, it can also happen with some buggy drives that trigger - * the IRQ before their status register is up to date. Hopefully we have + * This happens regularly when we share a PCI IRQ with + * another device. Unfortunately, it can also happen + * with some buggy drives that trigger the IRQ before + * their status register is up to date. Hopefully we have * enough advance overhead that the latter isn't a problem. */ spin_unlock_irqrestore(&io_request_lock, flags); @@ -1884,7 +1654,7 @@ spin_unlock(&io_request_lock); if (drive->unmask) - ide__sti(); /* local CPU only */ + local_irq_enable(); startstop = handler(drive); /* service this interrupt, may set handler for next interrupt */ spin_lock_irq(&io_request_lock); @@ -2228,8 +1998,7 @@ if (index >= MAX_HWIFS) return; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; @@ -2247,7 +2016,7 @@ /* * All clear? Then blow away the buffer cache */ - sti(); + spin_unlock_irqrestore(&io_request_lock, flags); for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; if (!drive->present) @@ -2263,7 +2032,7 @@ destroy_proc_ide_drives(hwif); #endif } - cli(); + spin_lock_irqsave(&io_request_lock, flags); hwgroup = hwif->hwgroup; /* @@ -2276,7 +2045,7 @@ g = g->next; } while (g != hwgroup->hwif); if (irq_count == 1) - free_irq(hwif->irq, hwgroup); + ide_free_irq(hwif->irq, hwgroup); /* * Note that we only release the standard ports, @@ -2383,7 +2152,7 @@ hwif->straight8 = old_hwif.straight8; hwif->hwif_data = old_hwif.hwif_data; abort: - restore_flags(flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); } /* @@ -2595,14 +2364,13 @@ while (hwgroup->busy) { unsigned long lflags; spin_unlock_irq(&io_request_lock); - __save_flags(lflags); /* local CPU only */ - __sti(); /* local CPU only; needed for jiffies */ - if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(lflags); /* local CPU only */ + local_irq_set(lflags); + if (time_after(jiffies, timeout)) { + local_irq_restore(lflags); printk("%s: channel busy\n", drive->name); return -EBUSY; } - __restore_flags(lflags); /* local CPU only */ + local_irq_restore(lflags); spin_lock_irq(&io_request_lock); } return 0; @@ -2697,8 +2465,8 @@ ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL); ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma); ide_add_setting(drive, "ide_scsi", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, NULL); - ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 69, 1, 1, &drive->init_speed, NULL); - ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 69, 1, 1, &drive->current_speed, NULL); + 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, NULL); ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL); } @@ -2918,68 +2686,15 @@ #endif /* CONFIG_IDE_TASK_IOCTL */ case HDIO_DRIVE_CMD: - { - byte args[4], *argbuf = args; - byte xfer_rate = 0; - int argsize = 4; - ide_task_t tfargs; - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - if (NULL == (void *) arg) - return ide_do_drive_cmd(drive, &rq, ide_wait); - if (copy_from_user(args, (void *)arg, 4)) - return -EFAULT; + return ide_cmd_ioctl(drive, inode, file, cmd, arg); - tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2]; - tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3]; - tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1]; - tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00; - tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00; - tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00; - tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0]; - - if (args[3]) { - argsize = 4 + (SECTOR_WORDS * 4 * args[3]); - argbuf = kmalloc(argsize, GFP_KERNEL); - if (argbuf == NULL) - return -ENOMEM; - memcpy(argbuf, args, 4); - } - - if (set_transfer(drive, &tfargs)) { - xfer_rate = args[1]; - if (ide_ata66_check(drive, &tfargs)) - goto abort; - } - - err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); - - if (!err && xfer_rate) { - /* active-retuning-calls future */ - if ((HWIF(drive)->speedproc) != NULL) - HWIF(drive)->speedproc(drive, xfer_rate); - ide_driveid_update(drive); - } - abort: - if (copy_to_user((void *)arg, argbuf, argsize)) - err = -EFAULT; - if (argsize > 4) - kfree(argbuf); - return err; - } case HDIO_DRIVE_TASK: - { - byte args[7], *argbuf = args; - int argsize = 7; - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - if (copy_from_user(args, (void *)arg, 7)) - return -EFAULT; - err = ide_wait_cmd_task(drive, argbuf); - if (copy_to_user((void *)arg, argbuf, argsize)) - err = -EFAULT; - return err; - } + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ide_task_ioctl(drive, inode, file, cmd, arg); + case HDIO_SCAN_HWIF: { int args[3]; @@ -3011,18 +2726,15 @@ case HDIO_DRIVE_RESET: { unsigned long flags; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - if (!capable(CAP_SYS_ADMIN)) return -EACCES; #if 1 spin_lock_irqsave(&io_request_lock, flags); - if (hwgroup->handler != NULL) { - printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler); - (void) hwgroup->handler(drive); -// hwgroup->handler = NULL; -// hwgroup->expiry = NULL; - hwgroup->timer.expires = jiffies + 0;; - del_timer(&hwgroup->timer); + if ( HWGROUP(drive)->handler != NULL) { + printk("%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler); + (void) HWGROUP(drive)->handler(drive); +// HWGROUP(drive)->handler = NULL; + HWGROUP(drive)->expiry = NULL; + del_timer(&HWGROUP(drive)->timer); } spin_unlock_irqrestore(&io_request_lock, flags); @@ -3585,13 +3297,6 @@ { #ifdef CONFIG_BLK_DEV_IDEPCI ide_scan_pcibus(ide_scan_direction); -#else -#ifdef CONFIG_BLK_DEV_RZ1000 - { - extern void ide_probe_for_rz100x(void); - ide_probe_for_rz100x(); - } -#endif /* CONFIG_BLK_DEV_RZ1000 */ #endif /* CONFIG_BLK_DEV_IDEPCI */ } #endif /* CONFIG_PCI */ @@ -3740,22 +3445,42 @@ return 0; } +static int default_suspend (ide_drive_t *drive) +{ + return 0; +} + +static int default_resume (ide_drive_t *drive) +{ + return 0; +} + static int default_flushcache (ide_drive_t *drive) { return 0; } -static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) { - ide_end_request(0, HWGROUP(drive)); + ide_end_request(drive, 0); return ide_stopped; } - -static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup) + +static int default_end_request (ide_drive_t *drive, int uptodate) { - ide_end_request(uptodate, hwgroup); + return ide_end_request(drive, uptodate); } - + +static byte default_sense (ide_drive_t *drive, const char *msg, byte stat) +{ + return ide_dump_status(drive, msg, stat); +} + +static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, byte stat) +{ + return ide_error(drive, msg, stat); +} + static int default_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -3795,6 +3520,11 @@ return ide_stopped; } +static int default_init (void) +{ + return 0; +} + static int default_reinit (ide_drive_t *drive) { printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name); @@ -3808,9 +3538,13 @@ if (d->cleanup == NULL) d->cleanup = default_cleanup; if (d->standby == NULL) d->standby = default_standby; + if (d->suspend == NULL) d->suspend = default_suspend; + if (d->resume == NULL) d->resume = default_resume; if (d->flushcache == NULL) d->flushcache = default_flushcache; if (d->do_request == NULL) d->do_request = default_do_request; if (d->end_request == NULL) d->end_request = default_end_request; + if (d->sense == NULL) d->sense = default_sense; + if (d->error == NULL) d->error = default_error; if (d->ioctl == NULL) d->ioctl = default_ioctl; if (d->open == NULL) d->open = default_open; if (d->release == NULL) d->release = default_release; @@ -3818,6 +3552,7 @@ if (d->pre_reset == NULL) d->pre_reset = default_pre_reset; if (d->capacity == NULL) d->capacity = default_capacity; if (d->special == NULL) d->special = default_special; + if (d->init == NULL) d->init = default_init; if (d->reinit == NULL) d->reinit = default_reinit; } @@ -3845,15 +3580,15 @@ { unsigned long flags; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) { - restore_flags(flags); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); + if (version != IDE_SUBDRIVER_VERSION || !drive->present || + drive->driver != NULL || drive->busy || drive->usage) { + spin_unlock_irqrestore(&io_request_lock, flags); return 1; } drive->driver = driver; setup_driver_defaults(drive); - restore_flags(flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); if (drive->autotune != 2) { if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) { /* @@ -3881,10 +3616,10 @@ { unsigned long flags; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) { - restore_flags(flags); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); + if (drive->usage || drive->busy || + drive->driver == NULL || DRIVER(drive)->busy) { + spin_unlock_irqrestore(&io_request_lock, flags); return 1; } #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE) @@ -3896,7 +3631,7 @@ #endif auto_remove_settings(drive); drive->driver = NULL; - restore_flags(flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); return 0; } @@ -3959,16 +3694,10 @@ EXPORT_SYMBOL(ide_register_subdriver); EXPORT_SYMBOL(ide_unregister_subdriver); EXPORT_SYMBOL(ide_replace_subdriver); -EXPORT_SYMBOL(ide_input_data); -EXPORT_SYMBOL(ide_output_data); -EXPORT_SYMBOL(atapi_input_bytes); -EXPORT_SYMBOL(atapi_output_bytes); -EXPORT_SYMBOL(drive_is_ready); EXPORT_SYMBOL(ide_set_handler); EXPORT_SYMBOL(ide_dump_status); EXPORT_SYMBOL(ide_error); EXPORT_SYMBOL(ide_fixstring); -EXPORT_SYMBOL(ide_wait_stat); EXPORT_SYMBOL(ide_do_reset); EXPORT_SYMBOL(restart_request); EXPORT_SYMBOL(ide_init_drive_cmd); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-cd.c linux.20pre2-ac1/drivers/ide/ide-cd.c --- linux.20pre2/drivers/ide/ide-cd.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-cd.c 2002-08-06 15:42:11.000000000 +0100 @@ -540,7 +540,113 @@ } -static void cdrom_end_request (int uptodate, ide_drive_t *drive) +/* + * This is our end_request replacement function. + */ +static int ide_cdrom_end_request (ide_drive_t *drive, int uptodate) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&io_request_lock, flags); + rq = HWGROUP(drive)->rq; + + /* + * 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->dmaproc(ide_dma_on, drive); + } + + if (!end_that_request_first(rq, uptodate, drive->name)) { + add_blkdev_randomness(MAJOR(rq->rq_dev)); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&io_request_lock, flags); + return ret; +} + +/* + * Error reporting, in human readable form (luxurious, but a memory hog). + */ +byte ide_cdrom_dump_status (ide_drive_t *drive, const char *msg, byte stat) +{ + unsigned long flags; + byte err = 0; + + local_irq_set(flags); + printk("%s: %s: status=0x%02x", drive->name, msg, stat); +#if FANCY_STATUS_DUMPS + printk(" { "); + if (stat & BUSY_STAT) + printk("Busy "); + else { + if (stat & READY_STAT) printk("DriveReady "); + if (stat & WRERR_STAT) printk("DeviceFault "); + if (stat & SEEK_STAT) printk("SeekComplete "); + if (stat & DRQ_STAT) printk("DataRequest "); + if (stat & ECC_STAT) printk("CorrectedError "); + if (stat & INDEX_STAT) printk("Index "); + if (stat & ERR_STAT) printk("Error "); + } + printk("}"); +#endif /* FANCY_STATUS_DUMPS */ + printk("\n"); + if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { + err = GET_ERR(); + printk("%s: %s: error=0x%02x", drive->name, msg, err); +#if FANCY_STATUS_DUMPS +#endif /* FANCY_STATUS_DUMPS */ + printk("\n"); + } + local_irq_restore(flags); + return err; +} + +/* + * ide_error() takes action based on the error returned by the drive. + */ +ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat) +{ + struct request *rq; + byte err; + + err = ide_cdrom_dump_status(drive, msg, stat); + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + return ide_stopped; + /* retry only "normal" I/O: */ + if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) { + rq->errors = 1; + ide_end_drive_cmd(drive, stat, err); + return ide_stopped; + } + + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { + /* other bits are useless when BUSY */ + rq->errors |= ERROR_RESET; + } + if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) + /* force an abort */ + OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + if (rq->errors >= ERROR_MAX) { + DRIVER(drive)->end_request(drive, 0); + } else { + if ((rq->errors & ERROR_RESET) == ERROR_RESET) { + ++rq->errors; + return ide_do_reset(drive); + } + ++rq->errors; + } + return ide_stopped; +} + +static void cdrom_end_request (ide_drive_t *drive, int uptodate) { struct request *rq = HWGROUP(drive)->rq; @@ -554,7 +660,7 @@ if (!rq->current_nr_sectors) uptodate = 1; - ide_end_request (uptodate, HWGROUP(drive)); + ide_cdrom_end_request(drive, uptodate); } @@ -591,8 +697,8 @@ pc = (struct packet_command *) rq->buffer; pc->stat = 1; - cdrom_end_request (1, drive); - *startstop = ide_error (drive, "request sense failure", stat); + cdrom_end_request(drive, 1); + *startstop = DRIVER(drive)->error(drive, "request sense failure", stat); return 1; } else if (rq->cmd == PACKET_COMMAND) { @@ -628,7 +734,7 @@ } pc->stat = 1; - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); if ((stat & ERR_STAT) != 0) cdrom_queue_request_sense(drive, wait, pc->sense, pc); @@ -641,7 +747,7 @@ /* Fail the request. */ printk ("%s: tray open\n", drive->name); - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); } else if (sense_key == UNIT_ATTENTION) { /* Media change. */ cdrom_saw_media_change (drive); @@ -650,21 +756,21 @@ But be sure to give up if we've retried too many times. */ if (++rq->errors > ERROR_MAX) - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); } else if (sense_key == ILLEGAL_REQUEST || sense_key == DATA_PROTECT) { /* No point in retrying after an illegal request or data protect error.*/ ide_dump_status (drive, "command error", stat); - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); } else if ((err & ~ABRT_ERR) != 0) { /* Go to the default handler for other errors. */ - *startstop = ide_error (drive, "cdrom_decode_status", stat); + *startstop = DRIVER(drive)->error(drive, "cdrom_decode_status", stat); return 1; } else if ((++rq->errors > ERROR_MAX)) { /* We've racked up too many retries. Abort. */ - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); } /* If we got a CHECK_CONDITION status, @@ -732,24 +838,26 @@ } /* Set up the controller registers. */ - OUT_BYTE (info->dma, IDE_FEATURE_REG); - OUT_BYTE (0, IDE_NSECTOR_REG); - OUT_BYTE (0, IDE_SECTOR_REG); + OUT_BYTE(info->dma, IDE_FEATURE_REG); + OUT_BYTE(0, IDE_NSECTOR_REG); + OUT_BYTE(0, IDE_SECTOR_REG); - OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG); - OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG); + OUT_BYTE(xferlen & 0xff, IDE_LCYL_REG); + OUT_BYTE(xferlen >> 8 , IDE_HCYL_REG); if (IDE_CONTROL_REG) - OUT_BYTE (drive->ctl, IDE_CONTROL_REG); + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); if (info->dma) (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); - OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ return ide_started; } else { - OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ return (*handler) (drive); } } @@ -786,6 +894,9 @@ return startstop; } + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + /* Arm the interrupt handler. */ ide_set_handler (drive, handler, timeout, cdrom_timer_expiry); @@ -879,7 +990,7 @@ drive->name, ireason); } - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); return -1; } @@ -910,16 +1021,16 @@ if (!dma_error) { for (i = rq->nr_sectors; i > 0;) { i -= rq->current_nr_sectors; - ide_end_request(1, HWGROUP(drive)); + ide_cdrom_end_request(drive, 1); } return ide_stopped; } else - return ide_error (drive, "dma error", stat); + return DRIVER(drive)->error(drive, "dma error", stat); } /* Read the interrupt reason and the transfer length. */ - ireason = IN_BYTE (IDE_NSECTOR_REG); - len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG); + ireason = IN_BYTE(IDE_NSECTOR_REG); + len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG); /* If DRQ is clear, the command has completed. */ if ((stat & DRQ_STAT) == 0) { @@ -928,9 +1039,9 @@ if (rq->current_nr_sectors > 0) { printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n", drive->name, rq->current_nr_sectors); - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); } else - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); return ide_stopped; } @@ -950,7 +1061,7 @@ printk (" Trying to limit transfer sizes\n"); CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1; } - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); return ide_stopped; } @@ -979,7 +1090,7 @@ /* If we've filled the present buffer but there's another chained buffer after it, move on. */ if (rq->current_nr_sectors == 0 && rq->nr_sectors) - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); /* If the buffers are full, cache the rest of the data in our internal buffer. */ @@ -1007,8 +1118,10 @@ } } - /* Done moving data! - Wait for another interrupt. */ + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + + /* Done moving data! Wait for another interrupt. */ ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); return ide_started; } @@ -1031,7 +1144,7 @@ rq->sector >= info->sector_buffered && rq->sector < info->sector_buffered + info->nsectors_buffered) { if (rq->current_nr_sectors == 0) - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); memcpy (rq->buffer, info->buffer + @@ -1046,13 +1159,13 @@ /* If we've satisfied the current request, terminate it successfully. */ if (rq->nr_sectors == 0) { - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); return -1; } /* Move on to the next buffer if needed. */ if (rq->current_nr_sectors == 0) - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); /* If this condition does not hold, then the kluge i use to represent the number of sectors to skip at the start of a transfer @@ -1062,7 +1175,7 @@ (rq->sector % SECTORS_PER_FRAME) != 0) { printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n", drive->name, rq->sector); - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); return -1; } @@ -1101,7 +1214,7 @@ (rq->sector % CD_FRAMESIZE != 0)) { printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n", drive->name, rq->current_nr_sectors); - cdrom_end_request (0, drive); + cdrom_end_request(drive, 0); return ide_stopped; } sector -= nskip; @@ -1147,7 +1260,7 @@ return startstop; CDROM_CONFIG_FLAGS(drive)->seeking = 1; - if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) { + if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) { if (--retry == 0) { /* * this condition is far too common, to bother @@ -1337,7 +1450,7 @@ } if (pc->buflen == 0) - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); else { /* Comment this out, because this always happens right after a reset occurs, and it is annoying to @@ -1347,7 +1460,7 @@ drive->name, pc->buflen); */ pc->stat = 1; - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); } return ide_stopped; } @@ -1398,6 +1511,9 @@ pc->stat = 1; } + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + /* Now we wait for another interrupt. */ ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); return ide_started; @@ -1522,7 +1638,7 @@ drive->name, ireason); } - cdrom_end_request(0, drive); + cdrom_end_request(drive, 0); return 1; } @@ -1554,12 +1670,12 @@ */ if (dma) { if (dma_error) - return ide_error(drive, "dma error", stat); + return DRIVER(drive)->error(drive, "dma error", stat); rq = HWGROUP(drive)->rq; for (i = rq->nr_sectors; i > 0;) { i -= rq->current_nr_sectors; - ide_end_request(1, HWGROUP(drive)); + ide_cdrom_end_request(drive, 1); } return ide_stopped; } @@ -1579,7 +1695,7 @@ drive->name, rq->current_nr_sectors); uptodate = 0; } - cdrom_end_request(uptodate, drive); + cdrom_end_request(drive, uptodate); return ide_stopped; } @@ -1620,9 +1736,12 @@ * current buffer complete, move on */ if (rq->current_nr_sectors == 0 && rq->nr_sectors) - cdrom_end_request (1, drive); + cdrom_end_request(drive, 1); } + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + /* re-arm handler */ ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL); return ide_started; @@ -1662,7 +1781,7 @@ * writes *must* be 2kB frame aligned */ if ((rq->nr_sectors & 3) || (rq->sector & 3)) { - cdrom_end_request(0, drive); + cdrom_end_request(drive, 0); return ide_stopped; } @@ -1698,11 +1817,10 @@ case WRITE: case READ: { if (CDROM_CONFIG_FLAGS(drive)->seeking) { - unsigned long elpased = jiffies - info->start_seek; int stat = GET_STAT(); if ((stat & SEEK_STAT) != SEEK_STAT) { - if (elpased < IDECD_SEEK_TIMEOUT) { + if (time_before(jiffies, info->start_seek + IDECD_SEEK_TIMEOUT)) { ide_stall_queue(drive, IDECD_SEEK_TIMER); return ide_stopped; } @@ -1728,13 +1846,13 @@ } case RESET_DRIVE_COMMAND: { - cdrom_end_request(1, drive); + cdrom_end_request(drive, 1); return ide_do_reset(drive); } default: { printk("ide-cd: bad cmd %d\n", rq->cmd); - cdrom_end_request(0, drive); + cdrom_end_request(drive, 0); return ide_stopped; } } @@ -2963,6 +3081,7 @@ return 0; } +int ide_cdrom_init(void); int ide_cdrom_reinit (ide_drive_t *drive); static ide_driver_t ide_cdrom_driver = { @@ -2970,13 +3089,21 @@ version: IDECD_VERSION, media: ide_cdrom, busy: 0, +#ifdef CONFIG_IDEDMA_ONLYDISK + supports_dma: 0, +#else supports_dma: 1, +#endif supports_dsc_overlap: 1, cleanup: ide_cdrom_cleanup, standby: NULL, + suspend: NULL, + resume: NULL, flushcache: NULL, do_request: ide_do_rw_cdrom, - end_request: NULL, + end_request: ide_cdrom_end_request, + sense: ide_cdrom_dump_status, + error: ide_cdrom_error, ioctl: ide_cdrom_ioctl, open: ide_cdrom_open, release: ide_cdrom_release, @@ -2986,12 +3113,12 @@ capacity: ide_cdrom_capacity, special: NULL, proc: NULL, + init: ide_cdrom_init, reinit: ide_cdrom_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, }; -int ide_cdrom_init(void); static ide_module_t ide_cdrom_module = { IDE_DRIVER_MODULE, ide_cdrom_init, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-cs.c linux.20pre2-ac1/drivers/ide/ide-cs.c --- linux.20pre2/drivers/ide/ide-cs.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-cs.c 2002-08-06 15:42:11.000000000 +0100 @@ -340,12 +340,12 @@ /* retry registration in case device is still spinning up */ for (i = 0; i < 10; i++) { if (ctl_base) - outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */ + OUT_BYTE(0x02, ctl_base); /* Set nIEN = disable device interrupts */ hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ); if (hd >= 0) break; if (link->io.NumPorts1 == 0x20) { if (ctl_base) - outb(0x02, ctl_base+0x10); + OUT_BYTE(0x02, ctl_base+0x10); hd = idecs_register(io_base+0x10, ctl_base+0x10, link->irq.AssignedIRQ); if (hd >= 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-disk.c linux.20pre2-ac1/drivers/ide/ide-disk.c --- linux.20pre2/drivers/ide/ide-disk.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-disk.c 2002-08-06 15:42:11.000000000 +0100 @@ -1,5 +1,9 @@ /* - * linux/drivers/ide/ide-disk.c Version 1.10 June 9, 2000 + * linux/drivers/ide/ide-disk.c Version 1.16 April 7, 2002 + * + * Copyright (C) 1998-2002 Linux ATA Developemt + * Andre Hedrick + * * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -29,10 +33,14 @@ * Version 1.10 request queue changes, Ultra DMA 100 * Version 1.11 added 48-bit lba * Version 1.12 adding taskfile io access method - * Highmem I/O support, Jens Axboe + * Version 1.13 added standby and flush-cache for notifier + * Version 1.14 added acoustic-wcache + * Version 1.15 convert all calls to ide_raw_taskfile + * since args will return register content. + * Version 1.16 added suspend-resume-checkpower */ -#define IDEDISK_VERSION "1.12" +#define IDEDISK_VERSION "1.16" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -62,42 +70,16 @@ #define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */ #endif -#ifdef CONFIG_IDE_TASKFILE_IO -# undef __TASKFILE__IO /* define __TASKFILE__IO */ -#else /* CONFIG_IDE_TASKFILE_IO */ -# undef __TASKFILE__IO -#endif /* CONFIG_IDE_TASKFILE_IO */ - -#ifndef __TASKFILE__IO - -static void idedisk_bswap_data (void *buffer, int wcount) -{ - u16 *p = buffer; - - while (wcount--) { - *p = *p << 8 | *p >> 8; p++; - *p = *p << 8 | *p >> 8; p++; - } -} - -static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - ide_input_data(drive, buffer, wcount); - if (drive->bswap) - idedisk_bswap_data(buffer, wcount); -} +static int driver_blocked; -static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +static inline u32 idedisk_read_24 (ide_drive_t *drive) { - if (drive->bswap) { - idedisk_bswap_data(buffer, wcount); - ide_output_data(drive, buffer, wcount); - idedisk_bswap_data(buffer, wcount); - } else - ide_output_data(drive, buffer, wcount); + return (IN_BYTE(IDE_HCYL_REG)<<16) | + (IN_BYTE(IDE_LCYL_REG)<<8) | + IN_BYTE(IDE_SECTOR_REG); } -#endif /* __TASKFILE__IO */ +static int idedisk_end_request(ide_drive_t *drive, int uptodate); /* * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity" @@ -149,7 +131,7 @@ return 0; /* lba_capacity value may be bad */ } -#ifndef __TASKFILE__IO +#ifndef CONFIG_IDE_TASKFILE_IO /* * read_intr() is the handler for disk read/multread interrupts @@ -159,21 +141,21 @@ byte stat; int i; unsigned int msect, nsect; - unsigned long flags; struct request *rq; - char *to; /* new way for dealing with premature shared PCI interrupts */ if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { - return ide_error(drive, "read_intr", stat); + return DRIVER(drive)->error(drive, "read_intr", stat); } /* no data yet, so wait for another interrupt */ + if (HWGROUP(drive)->handler != NULL) + BUG(); ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); return ide_started; } - msect = drive->mult_count; + read_next: rq = HWGROUP(drive)->rq; if (msect) { @@ -182,23 +164,29 @@ msect -= nsect; } else nsect = 1; - to = ide_map_buffer(rq, &flags); - idedisk_input_data(drive, to, nsect * SECTOR_WORDS); + taskfile_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); #ifdef DEBUG printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", drive->name, rq->sector, rq->sector+nsect-1, (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect); #endif - ide_unmap_buffer(to, &flags); rq->sector += nsect; + rq->buffer += nsect<<9; rq->errors = 0; i = (rq->nr_sectors -= nsect); if (((long)(rq->current_nr_sectors -= nsect)) <= 0) - ide_end_request(1, HWGROUP(drive)); + idedisk_end_request(drive, 1); + /* + * Another BH Page walker and DATA INTERGRITY Questioned on ERROR. + * If passed back up on multimode read, BAD DATA could be ACKED + * to FILE SYSTEMS above ... + */ if (i > 0) { if (msect) goto read_next; - ide_set_handler (drive, &read_intr, WAIT_CMD, NULL); + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); return ide_started; } return ide_stopped; @@ -224,24 +212,24 @@ #endif if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) { rq->sector++; + rq->buffer += 512; rq->errors = 0; i = --rq->nr_sectors; --rq->current_nr_sectors; if (((long)rq->current_nr_sectors) <= 0) - ide_end_request(1, hwgroup); + idedisk_end_request(drive, 1); if (i > 0) { - unsigned long flags; - char *to = ide_map_buffer(rq, &flags); - idedisk_output_data (drive, to, SECTOR_WORDS); - ide_unmap_buffer(to, &flags); - ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); + taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, &write_intr, WAIT_CMD, NULL); return ide_started; } return ide_stopped; } return ide_stopped; /* the original code did this here (?) */ } - return ide_error(drive, "write_intr", stat); + return DRIVER(drive)->error(drive, "write_intr", stat); } /* @@ -254,6 +242,11 @@ * and IRQ context. The IRQ can happen any time after we've output the * full "mcount" number of sectors, so we must make sure we update the * state _before_ we output the final part of the data! + * + * The update and return to BH is a BLOCK Layer Fakey to get more data + * to satisfy the hardware atomic segment. If the hardware atomic segment + * is shorter or smaller than the BH segment then we should be OKAY. + * This is only valid if we can rewind the rq->current_nr_sectors counter. */ int ide_multwrite (ide_drive_t *drive, unsigned int mcount) { @@ -263,14 +256,14 @@ do { char *buffer; int nsect = rq->current_nr_sectors; - unsigned long flags; - + if (nsect > mcount) nsect = mcount; mcount -= nsect; + buffer = rq->buffer; - buffer = ide_map_buffer(rq, &flags); rq->sector += nsect; + rq->buffer += nsect << 9; rq->nr_sectors -= nsect; rq->current_nr_sectors -= nsect; @@ -284,7 +277,7 @@ } else { rq->bh = bh; rq->current_nr_sectors = bh->b_size >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; + rq->buffer = bh->b_data; } } @@ -292,8 +285,7 @@ * Ok, we're all setup for the interrupt * re-entering us on the last transfer. */ - idedisk_output_data(drive, buffer, nsect<<7); - ide_unmap_buffer(buffer, &flags); + taskfile_output_data(drive, buffer, nsect<<7); } while (mcount); return 0; @@ -318,7 +310,9 @@ if (rq->nr_sectors) { if (ide_multwrite(drive, drive->mult_count)) return ide_stopped; - ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL); return ide_started; } } else { @@ -330,18 +324,18 @@ rq = hwgroup->rq; for (i = rq->nr_sectors; i > 0;){ i -= rq->current_nr_sectors; - ide_end_request(1, hwgroup); + idedisk_end_request(drive, 1); } return ide_stopped; } } return ide_stopped; /* the original code did this here (?) */ } - return ide_error(drive, "multwrite_intr", stat); + return DRIVER(drive)->error(drive, "multwrite_intr", stat); } -#endif /* __TASKFILE__IO */ +#endif /* CONFIG_IDE_TASKFILE_IO */ -#ifdef __TASKFILE__IO +#ifdef CONFIG_IDE_TASKFILE_IO static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); @@ -360,7 +354,7 @@ goto good_command; printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); - ide_end_request(0, HWGROUP(drive)); + idedisk_end_request(drive, 0); return ide_stopped; good_command: @@ -372,7 +366,8 @@ } #endif /* CONFIG_BLK_DEV_PDC4030 */ - if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) /* 48-bit LBA */ + if ((drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) /* 48-bit LBA */ return lba_48_rw_disk(drive, rq, (unsigned long long) block); if (drive->select.b.lba) /* 28-bit LBA */ return lba_28_rw_disk(drive, rq, (unsigned long) block); @@ -386,7 +381,7 @@ int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0; #if 1 - lba48bit = drive->addressing; + lba48bit = (drive->addressing == 1) ? 1 : 0; #endif if ((cmd == READ) && (drive->using_dma)) @@ -407,88 +402,63 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - ide_task_t args; - + ide_task_t args; + int sectors; task_ioreg_t command = get_command(drive, rq->cmd); unsigned int track = (block / drive->sect); unsigned int sect = (block % drive->sect) + 1; unsigned int head = (track % drive->head); unsigned int cyl = (track / drive->head); - memset(&taskfile, 0, sizeof(task_struct_t)); - memset(&hobfile, 0, sizeof(hob_struct_t)); - - taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors; - taskfile.sector_number = sect; - taskfile.low_cylinder = cyl; - taskfile.high_cylinder = (cyl>>8); - taskfile.device_head = head; - taskfile.device_head |= drive->select.all; - taskfile.command = command; - #ifdef DEBUG printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); - if (lba) printk("LBAsect=%lld, ", block); - else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("CHS=%d/%d/%d, ", cyl, head, sect); printk("sectors=%ld, ", rq->nr_sectors); printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); #endif - memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); - memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); - args.command_type = ide_cmd_type_parser(&args); - args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); - args.handler = ide_handler_parser(&taskfile, &hobfile); - args.posthandler = NULL; - args.rq = (struct request *) rq; - args.block = block; - rq->special = NULL; - rq->special = (ide_task_t *)&args; + memset(&args, 0, sizeof(ide_task_t)); + sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors; + args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; + args.tfRegister[IDE_SECTOR_OFFSET] = sect; + args.tfRegister[IDE_LCYL_OFFSET] = cyl; + args.tfRegister[IDE_HCYL_OFFSET] = (cyl>>8); + args.tfRegister[IDE_SELECT_OFFSET] = head; + args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; + args.tfRegister[IDE_COMMAND_OFFSET] = command; + args.command_type = ide_cmd_type_parser(&args); + args.rq = (struct request *) rq; + rq->special = (ide_task_t *)&args; return do_rw_taskfile(drive, &args); } static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - ide_task_t args; - + ide_task_t args; + int sectors; task_ioreg_t command = get_command(drive, rq->cmd); - memset(&taskfile, 0, sizeof(task_struct_t)); - memset(&hobfile, 0, sizeof(hob_struct_t)); - - taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors; - taskfile.sector_number = block; - taskfile.low_cylinder = (block>>=8); - taskfile.high_cylinder = (block>>=8); - taskfile.device_head = ((block>>8)&0x0f); - taskfile.device_head |= drive->select.all; - taskfile.command = command; - - #ifdef DEBUG printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); - if (lba) printk("LBAsect=%lld, ", block); - else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("LBAsect=%lld, ", block); printk("sectors=%ld, ", rq->nr_sectors); printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); #endif - memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); - memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); - args.command_type = ide_cmd_type_parser(&args); - args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); - args.handler = ide_handler_parser(&taskfile, &hobfile); - args.posthandler = NULL; - args.rq = (struct request *) rq; - args.block = block; - rq->special = NULL; - rq->special = (ide_task_t *)&args; + memset(&args, 0, sizeof(ide_task_t)); + sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors; + args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; + args.tfRegister[IDE_SECTOR_OFFSET] = block; + args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); + args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); + args.tfRegister[IDE_SELECT_OFFSET] = ((block>>8)&0x0f); + args.tfRegister[IDE_SELECT_OFFSET] |= drive->select.all; + args.tfRegister[IDE_COMMAND_OFFSET] = command; + args.command_type = ide_cmd_type_parser(&args); + args.rq = (struct request *) rq; + rq->special = (ide_task_t *)&args; return do_rw_taskfile(drive, &args); } @@ -500,57 +470,40 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - ide_task_t args; - + ide_task_t args; + int sectors; task_ioreg_t command = get_command(drive, rq->cmd); - memset(&taskfile, 0, sizeof(task_struct_t)); - memset(&hobfile, 0, sizeof(hob_struct_t)); - - taskfile.sector_count = rq->nr_sectors; - hobfile.sector_count = (rq->nr_sectors>>8); - - if (rq->nr_sectors == 65536) { - taskfile.sector_count = 0x00; - hobfile.sector_count = 0x00; - } - - taskfile.sector_number = block; /* low lba */ - taskfile.low_cylinder = (block>>=8); /* mid lba */ - taskfile.high_cylinder = (block>>=8); /* hi lba */ - hobfile.sector_number = (block>>=8); /* low lba */ - hobfile.low_cylinder = (block>>=8); /* mid lba */ - hobfile.high_cylinder = (block>>=8); /* hi lba */ - taskfile.device_head = drive->select.all; - hobfile.device_head = taskfile.device_head; - hobfile.control = (drive->ctl|0x80); - taskfile.command = command; - #ifdef DEBUG printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ"); - if (lba) printk("LBAsect=%lld, ", block); - else printk("CHS=%d/%d/%d, ", cyl, head, sect); + printk("LBAsect=%lld, ", block); printk("sectors=%ld, ", rq->nr_sectors); printk("buffer=0x%08lx\n", (unsigned long) rq->buffer); #endif - memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); - memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr)); - args.command_type = ide_cmd_type_parser(&args); - args.prehandler = ide_pre_handler_parser(&taskfile, &hobfile); - args.handler = ide_handler_parser(&taskfile, &hobfile); - args.posthandler = NULL; - args.rq = (struct request *) rq; - args.block = block; - rq->special = NULL; - rq->special = (ide_task_t *)&args; + memset(&args, 0, sizeof(ide_task_t)); + sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors; + args.tfRegister[IDE_NSECTOR_OFFSET] = sectors; + args.tfRegister[IDE_SECTOR_OFFSET] = block; /* low lba */ + args.tfRegister[IDE_LCYL_OFFSET] = (block>>=8); /* mid lba */ + args.tfRegister[IDE_HCYL_OFFSET] = (block>>=8); /* hi lba */ + args.tfRegister[IDE_SELECT_OFFSET] = drive->select.all; + args.tfRegister[IDE_COMMAND_OFFSET] = command; + args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8; + args.hobRegister[IDE_SECTOR_OFFSET_HOB] = (block>>=8); /* low lba */ + args.hobRegister[IDE_LCYL_OFFSET_HOB] = (block>>=8); /* mid lba */ + args.hobRegister[IDE_HCYL_OFFSET_HOB] = (block>>=8); /* hi lba */ + args.hobRegister[IDE_SELECT_OFFSET_HOB] = drive->select.all; + args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); + args.command_type = ide_cmd_type_parser(&args); + args.rq = (struct request *) rq; + rq->special = (ide_task_t *)&args; return do_rw_taskfile(drive, &args); } -#else /* !__TASKFILE__IO */ +#else /* !CONFIG_IDE_TASKFILE_IO */ + /* * do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. @@ -558,6 +511,8 @@ */ static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { + if (driver_blocked) + panic("Request while ide driver is blocked?"); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); @@ -567,7 +522,8 @@ if (drive->select.b.lba) { #endif /* CONFIG_BLK_DEV_PDC4030 */ - if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + if ((drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { task_ioreg_t tasklets[10]; tasklets[0] = 0; @@ -654,8 +610,11 @@ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) return ide_started; #endif /* CONFIG_BLK_DEV_IDEDMA */ + if (HWGROUP(drive)->handler != NULL) + BUG(); ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); - if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + if ((drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG); } else { OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); @@ -668,7 +627,8 @@ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive))) return ide_started; #endif /* CONFIG_BLK_DEV_IDEDMA */ - if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) { + if ((drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG); } else { OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG); @@ -679,7 +639,7 @@ return startstop; } if (!drive->unmask) - __cli(); /* local CPU only */ + local_irq_disable(); if (drive->mult_count) { ide_hwgroup_t *hwgroup = HWGROUP(drive); /* @@ -690,8 +650,12 @@ * before returning. Fortunately, this NEVER happens (right?). * * Except when you get an error it seems... + * + * MAJOR DATA INTEGRITY BUG !!! only if we error */ hwgroup->wrq = *rq; /* scratchpad */ + if (HWGROUP(drive)->handler != NULL) + BUG(); ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL); if (ide_multwrite(drive, drive->mult_count)) { unsigned long flags; @@ -702,37 +666,35 @@ return ide_stopped; } } else { - unsigned long flags; - char *buffer = ide_map_buffer(rq, &flags); - ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); - idedisk_output_data(drive, buffer, SECTOR_WORDS); - ide_unmap_buffer(buffer, &flags); + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, &write_intr, WAIT_CMD, NULL); + taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); } return ide_started; } printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); - ide_end_request(0, HWGROUP(drive)); + idedisk_end_request(drive, 0); return ide_stopped; } -#endif /* __TASKFILE__IO */ +#endif /* CONFIG_IDE_TASKFILE_IO */ static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive) { MOD_INC_USE_COUNT; if (drive->removable && drive->usage == 1) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.command = WIN_DOORLOCK; + ide_task_t args; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK; + args.command_type = ide_cmd_type_parser(&args); check_disk_change(inode->i_rdev); /* * Ignore the return code from door_lock, * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ - if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL)) + if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) drive->doorlocking = 0; } return 0; @@ -743,13 +705,12 @@ static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive) { if (drive->removable && !drive->usage) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.command = WIN_DOORUNLOCK; + ide_task_t args; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK; + args.command_type = ide_cmd_type_parser(&args); invalidate_bdev(inode->i_bdev, 0); - if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL)) + if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) drive->doorlocking = 0; } if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) @@ -771,6 +732,190 @@ current_capacity(drive)); } +static int idedisk_end_request (ide_drive_t *drive, int uptodate) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&io_request_lock, flags); + rq = HWGROUP(drive)->rq; + + /* + * 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->dmaproc(ide_dma_on, drive); + } + + if (!end_that_request_first(rq, uptodate, drive->name)) { + add_blkdev_randomness(MAJOR(rq->rq_dev)); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&io_request_lock, flags); + return ret; +} + +static byte idedisk_dump_status (ide_drive_t *drive, const char *msg, byte stat) +{ + unsigned long flags; + byte err = 0; + + local_irq_set(flags); + printk("%s: %s: status=0x%02x", drive->name, msg, stat); +#if FANCY_STATUS_DUMPS + printk(" { "); + if (stat & BUSY_STAT) + printk("Busy "); + else { + if (stat & READY_STAT) printk("DriveReady "); + if (stat & WRERR_STAT) printk("DeviceFault "); + if (stat & SEEK_STAT) printk("SeekComplete "); + if (stat & DRQ_STAT) printk("DataRequest "); + if (stat & ECC_STAT) printk("CorrectedError "); + if (stat & INDEX_STAT) printk("Index "); + if (stat & ERR_STAT) printk("Error "); + } + printk("}"); +#endif /* FANCY_STATUS_DUMPS */ + printk("\n"); + if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { + err = GET_ERR(); + printk("%s: %s: error=0x%02x", drive->name, msg, err); +#if FANCY_STATUS_DUMPS + printk(" { "); + if (err & ABRT_ERR) printk("DriveStatusError "); + if (err & ICRC_ERR) printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector "); + if (err & ECC_ERR) printk("UncorrectableError "); + if (err & ID_ERR) printk("SectorIdNotFound "); + if (err & TRK0_ERR) printk("TrackZeroNotFound "); + if (err & MARK_ERR) printk("AddrMarkNotFound "); + printk("}"); + if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) { + if ((drive->id->command_set_2 & 0x0400) && + (drive->id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + __u64 sectors = 0; + u32 low = 0, high = 0; + low = idedisk_read_24(drive); + OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG); + high = idedisk_read_24(drive); + sectors = ((__u64)high << 24) | low; + printk(", LBAsect=%llu, high=%d, low=%d", + (unsigned long long) sectors, + high, low); + } else { + byte cur = IN_BYTE(IDE_SELECT_REG); + if (cur & 0x40) { /* using LBA? */ + printk(", LBAsect=%ld", (unsigned long) + ((cur&0xf)<<24) + |(IN_BYTE(IDE_HCYL_REG)<<16) + |(IN_BYTE(IDE_LCYL_REG)<<8) + | IN_BYTE(IDE_SECTOR_REG)); + } else { + printk(", CHS=%d/%d/%d", + (IN_BYTE(IDE_HCYL_REG)<<8) + + IN_BYTE(IDE_LCYL_REG), + cur & 0xf, + IN_BYTE(IDE_SECTOR_REG)); + } + } + if (HWGROUP(drive) && HWGROUP(drive)->rq) + printk(", sector=%ld", HWGROUP(drive)->rq->sector); + } + } +#endif /* FANCY_STATUS_DUMPS */ + printk("\n"); + local_irq_restore(flags); + return err; +} + +ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, byte stat) +{ + struct request *rq; + byte err; + int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; + + err = idedisk_dump_status(drive, msg, stat); + + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + return ide_stopped; + /* retry only "normal" I/O: */ + switch (rq->cmd) { + case IDE_DRIVE_CMD: + case IDE_DRIVE_TASK: + case IDE_DRIVE_TASKFILE: + rq->errors = 1; + ide_end_drive_cmd(drive, stat, err); + return ide_stopped; +#if 0 + case IDE_DRIVE_TASKFILE: + rq->errors = 1; + ide_end_taskfile(drive, stat, err); + return ide_stopped; +#endif + default: + break; + } + + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { + /* other bits are useless when BUSY */ + rq->errors |= ERROR_RESET; + } else if (stat & ERR_STAT) { + /* err has different meaning on cdrom and tape */ + if (err == ABRT_ERR) { + if (drive->select.b.lba && + /* some newer drives don't support WIN_SPECIFY */ + IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY) + return ide_stopped; + } else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) { + /* UDMA crc error, just retry the operation */ + drive->crc_count++; + } else if (err & (BBD_ERR | ECC_ERR)) + /* retries won't help these */ + rq->errors = ERROR_MAX; + else if (err & TRK0_ERR) + /* help it find track zero */ + rq->errors |= ERROR_RECAL; + } + if ((stat & DRQ_STAT) && rq->cmd != WRITE) { + /* + * try_to_flush_leftover_data() is invoked in response to + * a drive unexpectedly having its DRQ_STAT bit set. As + * an alternative to resetting the drive, this routine + * tries to clear the condition by read a sector's worth + * of data from the drive. Of course, this may not help + * if the drive is *waiting* for data from *us*. + */ + while (i > 0) { + u32 buffer[16]; + unsigned int wcount = (i > 16) ? 16 : i; + i -= wcount; + ata_input_data(drive, buffer, wcount); + } + } + if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) + /* force an abort */ + OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + if (rq->errors >= ERROR_MAX) + DRIVER(drive)->end_request(drive, 0); + else { + if ((rq->errors & ERROR_RESET) == ERROR_RESET) { + ++rq->errors; + return ide_do_reset(drive); + } + if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) + drive->special.b.recalibrate = 1; + ++rq->errors; + } + return ide_stopped; +} + /* * Queries for true maximum capacity of the drive. * Returns maximum LBA address (> 0) of the drive, 0 if failed. @@ -780,16 +925,17 @@ ide_task_t args; unsigned long addr = 0; +#if 0 if (!(drive->id->command_set_1 & 0x0400) && !(drive->id->cfs_enable_2 & 0x0100)) return addr; +#endif /* Create IDE/ATA command request structure */ memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_SELECT_OFFSET] = 0x40; args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX; - args.handler = task_no_data_intr; - + args.command_type = ide_cmd_type_parser(&args); /* submit command request */ ide_raw_taskfile(drive, &args, NULL); @@ -814,8 +960,7 @@ args.tfRegister[IDE_SELECT_OFFSET] = 0x40; args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT; - args.handler = task_no_data_intr; - + args.command_type = ide_cmd_type_parser(&args); /* submit command request */ ide_raw_taskfile(drive, &args, NULL); @@ -851,7 +996,7 @@ args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff); args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40; args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX; - args.handler = task_no_data_intr; + args.command_type = ide_cmd_type_parser(&args); /* submit command request */ ide_raw_taskfile(drive, &args, NULL); /* if OK, read new maximum address value */ @@ -883,7 +1028,7 @@ args.hobRegister[IDE_HCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff); args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40; args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); - args.handler = task_no_data_intr; + args.command_type = ide_cmd_type_parser(&args); /* submit command request */ ide_raw_taskfile(drive, &args, NULL); /* if OK, compute maximum address value */ @@ -899,6 +1044,8 @@ return addr_set; } +#endif /* CONFIG_IDEDISK_STROKE */ + /* * Tests if the drive supports Host Protected Area feature. * Returns true if supported, false otherwise. @@ -906,12 +1053,11 @@ static inline int idedisk_supports_host_protected_area(ide_drive_t *drive) { int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0; - printk("%s: host protected area => %d\n", drive->name, flag); + if (flag) + printk("%s: host protected area => %d\n", drive->name, flag); return flag; } -#endif /* CONFIG_IDEDISK_STROKE */ - /* * Compute drive->capacity, the full capacity of the drive * Called with drive->id != NULL. @@ -937,6 +1083,8 @@ drive->capacity48 = 0; drive->select.b.lba = 0; + (void) idedisk_supports_host_protected_area(drive); + if (id->cfs_enable_2 & 0x0400) { capacity_2 = id->lba_capacity_2; drive->head = drive->bios_head = 255; @@ -959,6 +1107,7 @@ drive->name, set_max_ext, capacity_2); #endif /* CONFIG_IDEDISK_STROKE */ } + drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect); drive->bios_cyl = drive->cyl; drive->capacity48 = capacity_2; drive->capacity = (unsigned long) capacity_2; @@ -989,7 +1138,7 @@ drive->capacity = capacity; if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) { - drive->capacity48 = id->lba_capacity_2; + drive->capacity48 = id->lba_capacity_2; drive->head = 255; drive->sect = 63; drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect); @@ -1008,47 +1157,40 @@ special_t *s = &drive->special; if (s->b.set_geometry) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - ide_handler_t *handler = NULL; - - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - s->b.set_geometry = 0; - taskfile.sector_number = drive->sect; - taskfile.low_cylinder = drive->cyl; - taskfile.high_cylinder = drive->cyl>>8; - taskfile.device_head = ((drive->head-1)|drive->select.all)&0xBF; if (!IS_PDC4030_DRIVE) { - taskfile.sector_count = drive->sect; - taskfile.command = WIN_SPECIFY; - handler = ide_handler_parser(&taskfile, &hobfile); + ide_task_t args; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; + args.tfRegister[IDE_SECTOR_OFFSET] = drive->sect; + args.tfRegister[IDE_LCYL_OFFSET] = drive->cyl; + args.tfRegister[IDE_HCYL_OFFSET] = drive->cyl>>8; + args.tfRegister[IDE_SELECT_OFFSET] = ((drive->head-1)|drive->select.all)&0xBF; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY; + args.command_type = ide_cmd_type_parser(&args); + do_rw_taskfile(drive, &args); } - do_taskfile(drive, &taskfile, &hobfile, handler); } else if (s->b.recalibrate) { s->b.recalibrate = 0; if (!IS_PDC4030_DRIVE) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.sector_count = drive->sect; - taskfile.command = WIN_RESTORE; - do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); + ide_task_t args; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE; + args.command_type = ide_cmd_type_parser(&args); + do_rw_taskfile(drive, &args); } } else if (s->b.set_multmode) { s->b.set_multmode = 0; if (drive->id && drive->mult_req > drive->id->max_multsect) drive->mult_req = drive->id->max_multsect; if (!IS_PDC4030_DRIVE) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.sector_count = drive->mult_req; - taskfile.command = WIN_SETMULT; - do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile)); + ide_task_t args; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT; + args.command_type = ide_cmd_type_parser(&args); + do_rw_taskfile(drive, &args); } } else if (s->all) { int special = s->all; @@ -1078,45 +1220,44 @@ static int smart_enable(ide_drive_t *drive) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.feature = SMART_ENABLE; - taskfile.low_cylinder = SMART_LCYL_PASS; - taskfile.high_cylinder = SMART_HCYL_PASS; - taskfile.command = WIN_SMART; - return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + ide_task_t args; + + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_FEATURE_OFFSET] = SMART_ENABLE; + args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; + args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; + args.command_type = ide_cmd_type_parser(&args); + return ide_raw_taskfile(drive, &args, NULL); } static int get_smart_values(ide_drive_t *drive, byte *buf) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.feature = SMART_READ_VALUES; - taskfile.sector_count = 0x01; - taskfile.low_cylinder = SMART_LCYL_PASS; - taskfile.high_cylinder = SMART_HCYL_PASS; - taskfile.command = WIN_SMART; + ide_task_t args; + + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_FEATURE_OFFSET] = SMART_READ_VALUES; + args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01; + args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; + args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; + args.command_type = ide_cmd_type_parser(&args); (void) smart_enable(drive); - return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); + return ide_raw_taskfile(drive, &args, buf); } static int get_smart_thresholds(ide_drive_t *drive, byte *buf) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.feature = SMART_READ_THRESHOLDS; - taskfile.sector_count = 0x01; - taskfile.low_cylinder = SMART_LCYL_PASS; - taskfile.high_cylinder = SMART_HCYL_PASS; - taskfile.command = WIN_SMART; + ide_task_t args; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_FEATURE_OFFSET] = SMART_READ_THRESHOLDS; + args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01; + args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; + args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; + args.command_type = ide_cmd_type_parser(&args); (void) smart_enable(drive); - return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); + return ide_raw_taskfile(drive, &args, buf); } static int proc_idedisk_read_cache @@ -1185,23 +1326,12 @@ #endif /* CONFIG_PROC_FS */ +/* + * This is tightly woven into the driver->do_special can not touch. + * DON'T do it again until a total personality rewrite is committed. + */ static int set_multcount(ide_drive_t *drive, int arg) { -#ifdef __TASKFILE__IO - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - - if (drive->special.b.set_multmode) - return -EBUSY; - - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.sector_count = drive->mult_req; - taskfile.command = WIN_SETMULT; - drive->mult_req = arg; - drive->special.b.set_multmode = 1; - ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); -#else /* !__TASKFILE__IO */ struct request rq; if (drive->special.b.set_multmode) @@ -1211,7 +1341,6 @@ drive->mult_req = arg; drive->special.b.set_multmode = 1; (void) ide_do_drive_cmd (drive, &rq, ide_wait); -#endif /* __TASKFILE__IO */ return (drive->mult_count == arg) ? 0 : -EIO; } @@ -1227,57 +1356,112 @@ static int write_cache (ide_drive_t *drive, int arg) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.feature = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE; - taskfile.command = WIN_SETFEATURES; + ide_task_t args; if (!(drive->id->cfs_enable_2 & 0x3000)) return 1; - (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? + SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; + args.command_type = ide_cmd_type_parser(&args); + (void) ide_raw_taskfile(drive, &args, NULL); + drive->wcache = arg; return 0; } +static int call_idedisk_standby (ide_drive_t *drive, int arg) +{ + ide_task_t args; + byte standby = (arg) ? WIN_STANDBYNOW2 : WIN_STANDBYNOW1; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_COMMAND_OFFSET] = standby; + args.command_type = ide_cmd_type_parser(&args); + return ide_raw_taskfile(drive, &args, NULL); +} + static int do_idedisk_standby (ide_drive_t *drive) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - taskfile.command = WIN_STANDBYNOW1; - return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + return call_idedisk_standby(drive, 0); +} + +static int call_idedisk_suspend (ide_drive_t *drive, int arg) +{ + ide_task_t args; + byte suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_COMMAND_OFFSET] = suspend; + args.command_type = ide_cmd_type_parser(&args); + return ide_raw_taskfile(drive, &args, NULL); +} + +static int do_idedisk_suspend (ide_drive_t *drive) +{ + if (drive->suspend_reset) + return 1; + + return call_idedisk_suspend(drive, 0); +} + +#if 0 +static int call_idedisk_checkpower (ide_drive_t *drive, int arg) +{ + ide_task_t args; + byte ckpw = (arg) ? WIN_CHECKPOWERMODE2 : WIN_CHECKPOWERMODE1; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_COMMAND_OFFSET] = ckpw; + args.command_type = ide_cmd_type_parser(&args); + ide_raw_taskfile(drive, &args, NULL); +#if 0 +if (errno != EIO || args[0] != 0 || args[1] != 0) + state = "unknown"; +else + state = "sleeping"; +} else { + state = (args[2] == 255) ? "active/idle" : "standby"; +#endif + return 0; +} + +static int do_idedisk_checkpower (ide_drive_t *drive) +{ + return call_idedisk_checkpower(drive, 0); +} +#endif + +static int do_idedisk_resume (ide_drive_t *drive) +{ + if (!drive->suspend_reset) + return 1; + return 0; } static int do_idedisk_flushcache (ide_drive_t *drive) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - if (drive->id->cfs_enable_2 & 0x2400) { - taskfile.command = WIN_FLUSH_CACHE_EXT; - } else { - taskfile.command = WIN_FLUSH_CACHE; - } - return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + ide_task_t args; + + memset(&args, 0, sizeof(ide_task_t)); + if (drive->id->cfs_enable_2 & 0x2400) + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT; + else + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE; + args.command_type = ide_cmd_type_parser(&args); + return ide_raw_taskfile(drive, &args, NULL); } static int set_acoustic (ide_drive_t *drive, int arg) { - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - - taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM; - taskfile.sector_count = arg; + ide_task_t args; - taskfile.command = WIN_SETFEATURES; - (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL); + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? SETFEATURES_EN_AAM : + SETFEATURES_DIS_AAM; + args.tfRegister[IDE_NSECTOR_OFFSET] = arg; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; + args.command_type = ide_cmd_type_parser(&args); + ide_raw_taskfile(drive, &args, NULL); drive->acoustic = arg; return 0; } @@ -1286,9 +1470,11 @@ { drive->addressing = 0; + if (HWIF(drive)->addressing) + return 0; + if (!(drive->id->cfs_enable_2 & 0x0400)) return -EIO; - drive->addressing = arg; return 0; } @@ -1355,6 +1541,14 @@ break; } +#if 1 + (void) probe_lba_addressing(drive, 1); +#else + /* if using 48-bit addressing bump the request size up */ + if (probe_lba_addressing(drive, 1)) + blk_queue_max_sectors(&drive->queue, 2048); +#endif + /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { drive->cyl = drive->bios_cyl = id->cyls; @@ -1424,7 +1618,6 @@ drive->no_io_32bit = id->dword_io ? 1 : 0; if (drive->id->cfs_enable_2 & 0x3000) write_cache(drive, (id->cfs_enable_2 & 0x3000)); - (void) probe_lba_addressing(drive, 1); } static int idedisk_cleanup (ide_drive_t *drive) @@ -1436,6 +1629,7 @@ return ide_unregister_subdriver(drive); } +int idedisk_init (void); int idedisk_reinit(ide_drive_t *drive); /* @@ -1450,9 +1644,13 @@ supports_dsc_overlap: 0, cleanup: idedisk_cleanup, standby: do_idedisk_standby, + suspend: do_idedisk_suspend, + resume: do_idedisk_resume, flushcache: do_idedisk_flushcache, do_request: do_rw_disk, - end_request: NULL, + end_request: idedisk_end_request, + sense: idedisk_dump_status, + error: idedisk_error, ioctl: NULL, open: idedisk_open, release: idedisk_release, @@ -1462,12 +1660,12 @@ capacity: idedisk_capacity, special: idedisk_special, proc: idedisk_proc, + init: idedisk_init, reinit: idedisk_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, }; -int idedisk_init (void); static ide_module_t idedisk_module = { IDE_DRIVER_MODULE, idedisk_init, @@ -1490,7 +1688,8 @@ DRIVER(drive)->busy++; idedisk_setup(drive); if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { - printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); + printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", + drive->name, drive->head); (void) idedisk_cleanup(drive); DRIVER(drive)->busy--; return 1; @@ -1550,6 +1749,78 @@ return 0; } +ide_startstop_t panic_box(ide_drive_t *drive) +{ +#if 0 + panic("%s: Attempted to corrupt something: ide operation " +#else + printk(KERN_ERR "%s: Attempted to corrupt something: ide operation " +#endif + "was pending accross suspend/resume.\n", drive->name); + return ide_stopped; +} + +int ide_disks_busy(void) +{ + int i; + for (i=0; ihandler) && (hwgroup->handler != panic_box)) + return 1; + } + return 0; +} + +void ide_disk_suspend(void) +{ + int i; + while (ide_disks_busy()) { + printk("*"); + schedule(); + } + for (i=0; ihandler_save = hwgroup->handler; + hwgroup->handler = panic_box; + } + driver_blocked = 1; + if (ide_disks_busy()) + panic("How did you get that request through?!"); +} + +/* unsuspend and resume should be equal in the ideal world */ + +void ide_disk_unsuspend(void) +{ + int i; + for (i=0; ihandler = NULL; /* hwgroup->handler_save; */ + hwgroup->handler_save = NULL; + } + driver_blocked = 0; +} + +void ide_disk_resume(void) +{ + int i; + for (i=0; ihandler != panic_box) + panic("Handler was not set to panic?"); + hwgroup->handler_save = NULL; + hwgroup->handler = NULL; + } + driver_blocked = 0; +} + module_init(idedisk_init); module_exit(idedisk_exit); MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-dma.c linux.20pre2-ac1/drivers/ide/ide-dma.c --- linux.20pre2/drivers/ide/ide-dma.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-dma.c 2002-08-06 15:42:11.000000000 +0100 @@ -101,8 +101,6 @@ #define DEFAULT_BMCRBA 0xcc00 /* VIA's default value */ #define DEFAULT_BMALIBA 0xd400 /* ALI's default value */ -extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); - #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS struct drive_list_entry { @@ -123,7 +121,6 @@ { "WDC AC11000H" , "ALL" }, { "WDC AC22100H" , "ALL" }, - { "WDC AC31000H" , "ALL" }, { "WDC AC32500H" , "ALL" }, { "WDC AC33100H" , "ALL" }, { "WDC AC31600H" , "ALL" }, @@ -238,67 +235,47 @@ rq = HWGROUP(drive)->rq; for (i = rq->nr_sectors; i > 0;) { i -= rq->current_nr_sectors; - ide_end_request(1, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 1); } return ide_stopped; } printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat); } - return ide_error(drive, "dma_intr", stat); + return DRIVER(drive)->error(drive, "dma_intr", stat); } static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq) { struct buffer_head *bh; struct scatterlist *sg = hwif->sg_table; - unsigned long lastdataend = ~0UL; int nents = 0; if (hwif->sg_dma_active) BUG(); - + if (rq->cmd == READ) hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; else hwif->sg_dma_direction = PCI_DMA_TODEVICE; - bh = rq->bh; do { - struct scatterlist *sge; - - /* - * continue segment from before? - */ - if (bh_phys(bh) == lastdataend) { - sg[nents - 1].length += bh->b_size; - lastdataend += bh->b_size; - continue; - } + unsigned char *virt_addr = bh->b_data; + unsigned int size = bh->b_size; - /* - * start new segment - */ if (nents >= PRD_ENTRIES) return 0; - sge = &sg[nents]; - memset(sge, 0, sizeof(*sge)); - - if (bh->b_page) { - sge->page = bh->b_page; - sge->offset = bh_offset(bh); - } else { - if (((unsigned long) bh->b_data) < PAGE_SIZE) - BUG(); - - sge->address = bh->b_data; + while ((bh = bh->b_reqnext) != NULL) { + if ((virt_addr + size) != (unsigned char *) bh->b_data) + break; + size += bh->b_size; } - - sge->length = bh->b_size; - lastdataend = bh_phys(bh) + bh->b_size; + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = size; nents++; - } while ((bh = bh->b_reqnext) != NULL); + } while (bh != NULL); return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); } @@ -311,13 +288,11 @@ unsigned char *virt_addr = rq->buffer; int sector_count = rq->nr_sectors; -// if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) || -// (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT)) if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) hwif->sg_dma_direction = PCI_DMA_TODEVICE; else hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; - +#if 1 if (sector_count > 128) { memset(&sg[nents], 0, sizeof(*sg)); sg[nents].address = virt_addr; @@ -330,7 +305,20 @@ sg[nents].address = virt_addr; sg[nents].length = sector_count * SECTOR_SIZE; nents++; - +#else + while (sector_count > 128) { + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = 128 * SECTOR_SIZE; + nents++; + virt_addr = virt_addr + (128 * SECTOR_SIZE); + sector_count -= 128; + }; + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = sector_count * SECTOR_SIZE; + nents++; +#endif return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); } @@ -360,7 +348,7 @@ return 0; sg = HWIF(drive)->sg_table; - while (i) { + while (i && sg_dma_len(sg)) { u32 cur_addr; u32 cur_len; @@ -374,35 +362,36 @@ */ while (cur_len) { - u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); - - if (count++ >= PRD_ENTRIES) - BUG(); - - if (bcount > cur_len) - bcount = cur_len; - *table++ = cpu_to_le32(cur_addr); - xcount = bcount & 0xffff; - if (is_trm290_chipset) - xcount = ((xcount >> 2) - 1) << 16; - if (xcount == 0x0000) { - /* - * Most chipsets correctly interpret a length - * of 0x0000 as 64KB, but at least one - * (e.g. CS5530) misinterprets it as zero (!). - * So here we break the 64KB entry into two - * 32KB entries instead. - */ - if (count++ >= PRD_ENTRIES) - goto use_pio_instead; + if (count++ >= PRD_ENTRIES) { + printk("%s: DMA table too small\n", drive->name); + goto use_pio_instead; + } else { + u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); - *table++ = cpu_to_le32(0x8000); - *table++ = cpu_to_le32(cur_addr + 0x8000); - xcount = 0x8000; + if (bcount > cur_len) + bcount = cur_len; + *table++ = cpu_to_le32(cur_addr); + xcount = bcount & 0xffff; + if (is_trm290_chipset) + xcount = ((xcount >> 2) - 1) << 16; + if (xcount == 0x0000) { + /* + * Most chipsets correctly interpret a length of 0x0000 as 64KB, + * but at least one (e.g. CS5530) misinterprets it as zero (!). + * So here we break the 64KB entry into two 32KB entries instead. + */ + if (count++ >= PRD_ENTRIES) { + printk("%s: DMA table too small\n", drive->name); + goto use_pio_instead; + } + *table++ = cpu_to_le32(0x8000); + *table++ = cpu_to_le32(cur_addr + 0x8000); + xcount = 0x8000; + } + *table++ = cpu_to_le32(xcount); + cur_addr += bcount; + cur_len -= bcount; } - *table++ = cpu_to_le32(xcount); - cur_addr += bcount; - cur_len -= bcount; } sg++; @@ -517,16 +506,10 @@ static int config_drive_for_dma (ide_drive_t *drive) { - int config_allows_dma = 1; struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); -#ifdef CONFIG_IDEDMA_ONLYDISK - if (drive->media != ide_disk) - config_allows_dma = 0; -#endif - - if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) { + if (id && (id->capability & 1) && hwif->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) return hwif->dmaproc(ide_dma_off, drive); @@ -554,13 +537,13 @@ return hwif->dmaproc(ide_dma_off_quietly, drive); } -#ifndef CONFIG_BLK_DEV_IDEDMA_TIMEOUT +#ifndef __IDEDMA_TIMEOUT /* * 1 dmaing, 2 error, 4 intr */ static int dma_timer_expiry (ide_drive_t *drive) { - byte dma_stat = inb(HWIF(drive)->dma_base+2); + byte dma_stat = IN_BYTE(HWIF(drive)->dma_base+2); #ifdef DEBUG printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat); @@ -572,53 +555,52 @@ if (dma_stat & 2) { /* ERROR */ byte stat = GET_STAT(); - return ide_error(drive, "dma_timer_expiry", stat); + return DRIVER(drive)->error(drive, "dma_timer_expiry", stat); } if (dma_stat & 1) /* DMAing */ return WAIT_CMD; return 0; } -#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ -static ide_startstop_t ide_dma_timeout_revovery (ide_drive_t *drive) +#else /* __IDEDMA_TIMEOUT */ +static int ide_dma_timeout_recovery (ide_drive_t *drive) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); - ide_hwif_t *hwif = HWIF(drive); + struct request *rq = HWGROUP(drive)->rq; int enable_dma = drive->using_dma; + int speed = drive->current_speed; unsigned long flags; - ide_startstop_t startstop; spin_lock_irqsave(&io_request_lock, flags); - hwgroup->handler = NULL; - del_timer(&hwgroup->timer); + HWGROUP(drive)->handler = NULL; + del_timer(&HWGROUP(drive)->timer); + HWGROUP(drive)->expiry = NULL; + HWGROUP(drive)->rq = NULL; spin_unlock_irqrestore(&io_request_lock, flags); + (void) HWIF(drive)->dmaproc(ide_dma_off, drive); drive->waiting_for_dma = 0; - startstop = ide_do_reset(drive); - - if ((enable_dma) && !(drive->using_dma)) - (void) hwif->dmaproc(ide_dma_on, drive); - - return startstop; -} -#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ - -static inline void ide_toggle_bounce(ide_drive_t *drive, int on) -{ - dma64_addr_t addr = BLK_BOUNCE_HIGH; + (void) ide_do_reset(drive); - if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL) - return; + if (!(drive_is_ready(drive))) { + /* FIXME: Replace hard-coded 100, error handling? */ + int i; + for (i=0; i<100; i++) { + if (drive_is_ready(drive)) + break; + } + } - if (on && drive->media == ide_disk) { - if (!PCI_DMA_BUS_IS_PHYS) - addr = BLK_BOUNCE_ANY; - else - addr = HWIF(drive)->pci_dev->dma_mask; + if ((HWIF(drive)->speedproc) != NULL) { + HWIF(drive)->speedproc(drive, speed); + drive->current_speed = speed; } - blk_queue_bounce_limit(&drive->queue, addr); + if ((enable_dma) && !(drive->using_dma)) + (void) HWIF(drive)->dmaproc(ide_dma_on, drive); + + return restart_request(drive, rq); } +#endif /* __IDEDMA_TIMEOUT */ /* * ide_dmaproc() initiates/aborts DMA read/write operations on a drive. @@ -638,24 +620,28 @@ */ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { -// ide_hwgroup_t *hwgroup = HWGROUP(drive); ide_hwif_t *hwif = HWIF(drive); +// ide_task_t *args = HWGROUP(drive)->rq->special; unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); - unsigned int count, reading = 0, set_high = 1; + unsigned int count, reading = 0; byte dma_stat; switch (func) { case ide_dma_off: printk("%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: - set_high = 0; - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + case ide_dma_host_off: + OUT_BYTE(IN_BYTE(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + if (func == ide_dma_host_off) + return 0; case ide_dma_on: drive->using_dma = (func == ide_dma_on); + if (!drive->using_dma) + return 0; + case ide_dma_host_on: if (drive->using_dma) - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - ide_toggle_bounce(drive, set_high); + OUT_BYTE(IN_BYTE(dma_base+2)|(1<<(5+unit)), dma_base+2); return 0; case ide_dma_check: return config_drive_for_dma (drive); @@ -664,27 +650,43 @@ case ide_dma_write: SELECT_READ_WRITE(hwif,drive,func); if (!(count = ide_build_dmatable(drive, func))) - return 1; /* try PIO instead of DMA */ - outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */ - outb(reading, dma_base); /* specify r/w */ - outb(inb(dma_base+2)|6, dma_base+2); /* clear INTR & ERROR flags */ + /* try PIO instead of DMA */ + return 1; + /* PRD table */ + outl(hwif->dmatable_dma, dma_base + 4); + /* specify r/w */ + OUT_BYTE(reading, dma_base); + /* clear INTR & ERROR flags */ + OUT_BYTE(IN_BYTE(dma_base+2)|6, dma_base+2); drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; -#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT - ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL); /* issue cmd to drive */ -#else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */ -#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ - if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) && - (drive->addressing == 1)) { + /* paranoia check */ + if (HWGROUP(drive)->handler != NULL) + BUG(); +#ifndef __IDEDMA_TIMEOUT + ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry); +#else /* __IDEDMA_TIMEOUT */ + ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL); +#endif /* __IDEDMA_TIMEOUT */ + /* issue cmd to drive */ + /* + * FIX ME to use only ACB ide_task_t args Struct + */ +#if 0 + { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } +#else + if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) { ide_task_t *args = HWGROUP(drive)->rq->special; OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); - } else if (drive->addressing) { + } else if (drive->addressing == 1) OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); - } else { + else OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - } +#endif return HWIF(drive)->dmaproc(ide_dma_begin, drive); case ide_dma_begin: /* Note that this is done *after* the cmd has @@ -692,71 +694,83 @@ * The Promise Ultra33 doesn't work correctly when * we do this part before issuing the drive cmd. */ - outb(inb(dma_base)|1, dma_base); /* start DMA */ + /* start DMA */ + OUT_BYTE(IN_BYTE(dma_base)|1, dma_base); return 0; case ide_dma_end: /* returns 1 on error, 0 otherwise */ drive->waiting_for_dma = 0; - outb(inb(dma_base)&~1, dma_base); /* stop DMA */ - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */ + /* stop DMA */ + OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base); + /* get DMA status */ + dma_stat = IN_BYTE(dma_base+2); + /* clear the INTR & ERROR bits */ + OUT_BYTE(dma_stat|6, dma_base+2); + /* purge DMA mappings */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ - dma_stat = inb(dma_base+2); + dma_stat = IN_BYTE(dma_base+2); #if 0 /* do not set unless you know what you are doing */ if (dma_stat & 4) { byte stat = GET_STAT(); - outb(dma_base+2, dma_stat & 0xE4); + OUT_BYTE(dma_base+2, dma_stat & 0xE4); } #endif - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ + /* return 1 if INTR asserted */ + return (dma_stat & 4) == 4; case ide_dma_bad_drive: case ide_dma_good_drive: return check_drive_lists(drive, (func == ide_dma_good_drive)); case ide_dma_verbose: return report_drive_dmaing(drive); case ide_dma_timeout: - // FIXME: Many IDE chipsets do not permit command file register access - // FIXME: while the bus-master function is still active. - // FIXME: To prevent deadlock with those chipsets, we must be extremely - // FIXME: careful here (and in ide_intr() as well) to NOT access any - // FIXME: registers from the 0x1Fx/0x17x sets before terminating the - // FIXME: bus-master operation via the bus-master control reg. - // FIXME: Otherwise, chipset deadlock will occur, and some systems will - // FIXME: lock up completely!! -#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT + // FIXME: Many IDE chipsets do not permit command file register access + // FIXME: while the bus-master function is still active. + // FIXME: To prevent deadlock with those chipsets, we must be extremely + // FIXME: careful here (and in ide_intr() as well) to NOT access any + // FIXME: registers from the 0x1Fx/0x17x sets before terminating the + // FIXME: bus-master operation via the bus-master control reg. + // FIXME: Otherwise, chipset deadlock will occur, and some systems will + // FIXME: lock up completely!! +#ifdef __IDEDMA_TIMEOUT /* * Have to issue an abort and requeue the request * DMA engine got turned off by a goofy ASIC, and * we have to clean up the mess, and here is as good * as any. Do it globally for all chipsets. */ - outb(0x00, dma_base); /* stop DMA */ - dma_stat = inb(dma_base+2); /* get DMA status */ - outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */ +#if 0 + dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive); +#else + drive->waiting_for_dma = 0; + /* stop DMA */ + OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base); +// OUT_BYTE(0x00, dma_base); + /* get DMA status */ + dma_stat = IN_BYTE(dma_base+2); + /* clear the INTR & ERROR bits */ + OUT_BYTE(dma_stat|6, dma_base+2); + /* purge DMA mappings */ + ide_destroy_dmatable(drive); +#endif printk("%s: %s: Lets do it again!" \ "stat = 0x%02x, dma_stat = 0x%02x\n", drive->name, ide_dmafunc_verbose(func), GET_STAT(), dma_stat); if (dma_stat & 0xF0) - return ide_dma_timeout_revovery(drive); - - printk("%s: %s: (restart_request) Lets do it again!" \ - "stat = 0x%02x, dma_stat = 0x%02x\n", - drive->name, ide_dmafunc_verbose(func), - GET_STAT(), dma_stat); - - return restart_request(drive); // BUG: return types do not match!! -//#else -// return HWGROUP(drive)->handler(drive); -#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ + return ide_dma_timeout_recovery(drive); +#endif /* __IDEDMA_TIMEOUT */ case ide_dma_retune: case ide_dma_lostirq: - printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); + printk("ide_dmaproc: chipset supported %s " + "func only: %d\n", + ide_dmafunc_verbose(func), func); return 1; default: - printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func); + printk("ide_dmaproc: unsupported %s func: %d\n", + ide_dmafunc_verbose(func), func); return 1; } } @@ -784,7 +798,7 @@ } /* - * This can be called for a dynamically installed interface. Don't __init it + * This can be called for a dynamically installed interface. Don't __init it */ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports) @@ -797,8 +811,8 @@ request_region(dma_base, num_ports, hwif->name); hwif->dma_base = dma_base; hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev, - PRD_ENTRIES * PRD_BYTES, - &hwif->dmatable_dma); + PRD_ENTRIES * PRD_BYTES, + &hwif->dmatable_dma); if (hwif->dmatable_cpu == NULL) goto dma_alloc_failure; @@ -813,7 +827,7 @@ hwif->dmaproc = &ide_dmaproc; if (hwif->chipset != ide_trm290) { - byte dma_stat = inb(dma_base+2); + byte dma_stat = IN_BYTE(dma_base+2); printk(", BIOS settings: %s:%s, %s:%s", hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio", hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); @@ -878,8 +892,9 @@ case PCI_DEVICE_ID_AL_M5219: case PCI_DEVICE_ID_AMD_VIPER_7409: case PCI_DEVICE_ID_CMD_643: - outb(inb(dma_base+2) & 0x60, dma_base+2); - if (inb(dma_base+2) & 0x80) { + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + OUT_BYTE(IN_BYTE(dma_base+2) & 0x60, dma_base+2); + if (IN_BYTE(dma_base+2) & 0x80) { printk("%s: simplex device: DMA forced\n", name); } break; @@ -891,7 +906,7 @@ * So we should enable DMA only on one of the * two interfaces. */ - if ((inb(dma_base+2) & 0x80)) { /* simplex device? */ + if ((IN_BYTE(dma_base+2) & 0x80)) { /* simplex device? */ if ((!hwif->drives[0].present && !hwif->drives[1].present) || (hwif->mate && hwif->mate->dma_base)) { printk("%s: simplex device: DMA disabled\n", name); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-features.c linux.20pre2-ac1/drivers/ide/ide-features.c --- linux.20pre2/drivers/ide/ide-features.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-features.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,385 +0,0 @@ -/* - * linux/drivers/block/ide-features.c Version 0.04 June 9, 2000 - * - * Copyright (C) 1999-2000 Linus Torvalds & authors (see below) - * - * Copyright (C) 1999-2000 Andre Hedrick - * - * Extracts if ide.c to address the evolving transfer rate code for - * the SETFEATURES_XFER callouts. Various parts of any given function - * are credited to previous ATA-IDE maintainers. - * - * Auto-CRC downgrade for Ultra DMA(ing) - * - * May be copied or modified under the terms of the GNU General Public License - */ - -#include -#define __NO_VERSION__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * A Verbose noise maker for debugging on the attempted transfer rates. - */ -char *ide_xfer_verbose (byte xfer_rate) -{ - switch(xfer_rate) { - case XFER_UDMA_7: return("UDMA 7"); - case XFER_UDMA_6: return("UDMA 6"); - case XFER_UDMA_5: return("UDMA 5"); - case XFER_UDMA_4: return("UDMA 4"); - case XFER_UDMA_3: return("UDMA 3"); - case XFER_UDMA_2: return("UDMA 2"); - case XFER_UDMA_1: return("UDMA 1"); - case XFER_UDMA_0: return("UDMA 0"); - case XFER_MW_DMA_2: return("MW DMA 2"); - case XFER_MW_DMA_1: return("MW DMA 1"); - case XFER_MW_DMA_0: return("MW DMA 0"); - case XFER_SW_DMA_2: return("SW DMA 2"); - case XFER_SW_DMA_1: return("SW DMA 1"); - case XFER_SW_DMA_0: return("SW DMA 0"); - case XFER_PIO_4: return("PIO 4"); - case XFER_PIO_3: return("PIO 3"); - case XFER_PIO_2: return("PIO 2"); - case XFER_PIO_1: return("PIO 1"); - case XFER_PIO_0: return("PIO 0"); - case XFER_PIO_SLOW: return("PIO SLOW"); - default: return("XFER ERROR"); - } -} - -/* - * - */ -char *ide_media_verbose (ide_drive_t *drive) -{ - switch (drive->media) { - case ide_scsi: return("scsi "); - case ide_disk: return("disk "); - case ide_optical: return("optical"); - case ide_cdrom: return("cdrom "); - case ide_tape: return("tape "); - case ide_floppy: return("floppy "); - default: return("???????"); - } -} - -/* - * A Verbose noise maker for debugging on the attempted dmaing calls. - */ -char *ide_dmafunc_verbose (ide_dma_action_t dmafunc) -{ - switch (dmafunc) { - case ide_dma_read: return("ide_dma_read"); - case ide_dma_write: return("ide_dma_write"); - case ide_dma_begin: return("ide_dma_begin"); - case ide_dma_end: return("ide_dma_end:"); - case ide_dma_check: return("ide_dma_check"); - case ide_dma_on: return("ide_dma_on"); - case ide_dma_off: return("ide_dma_off"); - case ide_dma_off_quietly: return("ide_dma_off_quietly"); - case ide_dma_test_irq: return("ide_dma_test_irq"); - case ide_dma_bad_drive: return("ide_dma_bad_drive"); - case ide_dma_good_drive: return("ide_dma_good_drive"); - case ide_dma_verbose: return("ide_dma_verbose"); - case ide_dma_retune: return("ide_dma_retune"); - case ide_dma_lostirq: return("ide_dma_lostirq"); - case ide_dma_timeout: return("ide_dma_timeout"); - default: return("unknown"); - } -} - -/* - * - */ -byte ide_auto_reduce_xfer (ide_drive_t *drive) -{ - if (!drive->crc_count) - return drive->current_speed; - drive->crc_count = 0; - - switch(drive->current_speed) { - case XFER_UDMA_7: return XFER_UDMA_6; - case XFER_UDMA_6: return XFER_UDMA_5; - case XFER_UDMA_5: return XFER_UDMA_4; - case XFER_UDMA_4: return XFER_UDMA_3; - case XFER_UDMA_3: return XFER_UDMA_2; - case XFER_UDMA_2: return XFER_UDMA_1; - case XFER_UDMA_1: return XFER_UDMA_0; - /* - * OOPS we do not goto non Ultra DMA modes - * without iCRC's available we force - * the system to PIO and make the user - * invoke the ATA-1 ATA-2 DMA modes. - */ - case XFER_UDMA_0: - default: return XFER_PIO_4; - } -} - -/* - * Update the - */ -int ide_driveid_update (ide_drive_t *drive) -{ - /* - * Re-read drive->id for possible DMA mode - * change (copied from ide-probe.c) - */ - struct hd_driveid *id; - unsigned long timeout, flags; - - SELECT_MASK(HWIF(drive), drive, 1); - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl,IDE_CONTROL_REG); - ide_delay_50ms(); - OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG); - timeout = jiffies + WAIT_WORSTCASE; - do { - if (0 < (signed long)(jiffies - timeout)) { - SELECT_MASK(HWIF(drive), drive, 0); - return 0; /* drive timed-out */ - } - ide_delay_50ms(); /* give drive a breather */ - } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT); - ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ - if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { - SELECT_MASK(HWIF(drive), drive, 0); - printk("%s: CHECK for good STATUS\n", drive->name); - return 0; - } - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only; some systems need this */ - SELECT_MASK(HWIF(drive), drive, 0); - id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); - if (!id) { - __restore_flags(flags); /* local CPU only */ - return 0; - } - ide_input_data(drive, id, SECTOR_WORDS); - (void) GET_STAT(); /* clear drive IRQ */ - ide__sti(); /* local CPU only */ - __restore_flags(flags); /* local CPU only */ - ide_fix_driveid(id); - if (id) { - drive->id->dma_ultra = id->dma_ultra; - drive->id->dma_mword = id->dma_mword; - drive->id->dma_1word = id->dma_1word; - /* anything more ? */ - kfree(id); - } - - return 1; -} - -/* - * Verify that we are doing an approved SETFEATURES_XFER with respect - * to the hardware being able to support request. Since some hardware - * can improperly report capabilties, we check to see if the host adapter - * in combination with the device (usually a disk) properly detect - * and acknowledge each end of the ribbon. - */ -int ide_ata66_check (ide_drive_t *drive, ide_task_t *args) -{ - if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && - (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) && - (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) { - if (!HWIF(drive)->udma_four) { - printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name); - return 1; - } -#ifndef CONFIG_IDEDMA_IVB - if ((drive->id->hw_config & 0x6000) == 0) { -#else /* !CONFIG_IDEDMA_IVB */ - if (((drive->id->hw_config & 0x2000) == 0) || - ((drive->id->hw_config & 0x4000) == 0)) { -#endif /* CONFIG_IDEDMA_IVB */ - printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name); - return 1; - } - } - return 0; -} - -/* - * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER. - * 1 : Safe to update drive->id DMA registers. - * 0 : OOPs not allowed. - */ -int set_transfer (ide_drive_t *drive, ide_task_t *args) -{ - if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && - (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) && - (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) && - (drive->id->dma_ultra || - drive->id->dma_mword || - drive->id->dma_1word)) - return 1; - - return 0; -} - -#ifdef CONFIG_BLK_DEV_IDEDMA -/* - * All hosts that use the 80c ribbon mus use! - */ -byte eighty_ninty_three (ide_drive_t *drive) -{ -#ifdef CONFIG_BLK_DEV_IDEPCI - if (HWIF(drive)->pci_devid.vid==0x105a) - return(HWIF(drive)->udma_four); -#endif - /* PDC202XX: that's because some HDD will return wrong info */ - return ((byte) ((HWIF(drive)->udma_four) && -#ifndef CONFIG_IDEDMA_IVB - (drive->id->hw_config & 0x4000) && -#endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); -} -#endif // CONFIG_BLK_DEV_IDEDMA - -/* - * Similar to ide_wait_stat(), except it never calls ide_error internally. - * This is a kludge to handle the new ide_config_drive_speed() function, - * and should not otherwise be used anywhere. Eventually, the tuneproc's - * should be updated to return ide_startstop_t, in which case we can get - * rid of this abomination again. :) -ml - * - * It is gone.......... - * - * const char *msg == consider adding for verbose errors. - */ -int ide_config_drive_speed (ide_drive_t *drive, byte speed) -{ - ide_hwif_t *hwif = HWIF(drive); - int i, error = 1; - byte stat; - -#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) - byte unit = (drive->select.b.unit & 0x01); - outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); -#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ - - /* - * 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 - */ - disable_irq(hwif->irq); /* disable_irq_nosync ?? */ - udelay(1); - SELECT_DRIVE(HWIF(drive), drive); - SELECT_MASK(HWIF(drive), drive, 0); - udelay(1); - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); - OUT_BYTE(speed, IDE_NSECTOR_REG); - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); - OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - if ((IDE_CONTROL_REG) && (drive->quirk_list == 2)) - OUT_BYTE(drive->ctl, IDE_CONTROL_REG); - udelay(1); - /* - * Wait for drive to become non-BUSY - */ - if ((stat = GET_STAT()) & BUSY_STAT) { - unsigned long flags, timeout; - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only -- for jiffies */ - timeout = jiffies + WAIT_CMD; - while ((stat = GET_STAT()) & BUSY_STAT) { - if (0 < (signed long)(jiffies - timeout)) - break; - } - __restore_flags(flags); /* local CPU only */ - } - - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - * This fix courtesy of Matthew Faupel & Niccolo Rigacci. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { - error = 0; - break; - } - } - - SELECT_MASK(HWIF(drive), drive, 0); - - enable_irq(hwif->irq); - - if (error) { - (void) ide_dump_status(drive, "set_drive_speed_status", stat); - return error; - } - - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - -#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) - if (speed > XFER_PIO_4) { - outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); - } else { - outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); - } -#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ - - switch(speed) { - case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break; - case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break; - case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break; - case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; - case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; - case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break; - case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break; - case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break; - case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break; - case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break; - case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break; - case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break; - case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; - default: break; - } - return error; -} - -EXPORT_SYMBOL(ide_auto_reduce_xfer); -EXPORT_SYMBOL(ide_driveid_update); -EXPORT_SYMBOL(ide_ata66_check); -EXPORT_SYMBOL(set_transfer); -#ifdef CONFIG_BLK_DEV_IDEDMA -EXPORT_SYMBOL(eighty_ninty_three); -#endif // CONFIG_BLK_DEV_IDEDMA -EXPORT_SYMBOL(ide_config_drive_speed); - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-floppy.c linux.20pre2-ac1/drivers/ide/ide-floppy.c --- linux.20pre2/drivers/ide/ide-floppy.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-floppy.c 2002-08-06 15:42:11.000000000 +0100 @@ -668,28 +668,57 @@ static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount) { while (bcount--) - IN_BYTE (IDE_DATA_REG); + IN_BYTE(IDE_DATA_REG); } #if IDEFLOPPY_DEBUG_BUGS static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount) { while (bcount--) - OUT_BYTE (0, IDE_DATA_REG); + OUT_BYTE(0, IDE_DATA_REG); } #endif /* IDEFLOPPY_DEBUG_BUGS */ + +static int idefloppy_end_request (ide_drive_t *drive, int uptodate) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&io_request_lock, flags); + rq = HWGROUP(drive)->rq; + + /* + * 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->dmaproc(ide_dma_on, drive); + } + + if (!end_that_request_first(rq, uptodate, drive->name)) { + add_blkdev_randomness(MAJOR(rq->rq_dev)); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&io_request_lock, flags); + return ret; +} + /* - * idefloppy_end_request is used to finish servicing a request. + * idefloppy_do_end_request is used to finish servicing a request. * * For read/write requests, we will call ide_end_request to pass to the * next buffer. */ -static void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup) +static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate) { - ide_drive_t *drive = hwgroup->drive; idefloppy_floppy_t *floppy = drive->driver_data; - struct request *rq = hwgroup->rq; + struct request *rq = HWGROUP(drive)->rq; int error; #if IDEFLOPPY_DEBUG_LOG @@ -705,13 +734,16 @@ floppy->failed_pc = NULL; /* Why does this happen? */ if (!rq) - return; + return 0; if (!IDEFLOPPY_RQ_CMD (rq->cmd)) { - ide_end_request (uptodate, hwgroup); - return; + /* our real local end request function */ + idefloppy_end_request(drive, uptodate); + return 0; } rq->errors = error; + /* fixme: need to move this local also */ ide_end_drive_cmd (drive, 0, 0); + return 0; } static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount) @@ -724,7 +756,7 @@ if (pc->b_count == bh->b_size) { rq->sector += rq->current_nr_sectors; rq->nr_sectors -= rq->current_nr_sectors; - idefloppy_end_request (1, HWGROUP(drive)); + idefloppy_do_end_request(drive, 1); if ((bh = rq->bh) != NULL) pc->b_count = 0; } @@ -749,7 +781,7 @@ if (!pc->b_count) { rq->sector += rq->current_nr_sectors; rq->nr_sectors -= rq->current_nr_sectors; - idefloppy_end_request (1, HWGROUP(drive)); + idefloppy_do_end_request(drive, 1); if ((bh = rq->bh) != NULL) { pc->b_data = bh->b_data; pc->b_count = bh->b_size; @@ -773,7 +805,7 @@ struct buffer_head *bh = rq->bh; while ((bh = rq->bh) != NULL) - idefloppy_end_request (1, HWGROUP(drive)); + idefloppy_do_end_request(drive, 1); } #endif /* CONFIG_BLK_DEV_IDEDMA */ @@ -836,10 +868,10 @@ #endif /* IDEFLOPPY_DEBUG_LOG */ if (!floppy->pc->error) { idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer); - idefloppy_end_request (1,HWGROUP (drive)); + idefloppy_do_end_request(drive, 1); } else { printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n"); - idefloppy_end_request (0,HWGROUP (drive)); + idefloppy_do_end_request(drive, 0); } } @@ -854,7 +886,7 @@ printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n"); #endif /* IDEFLOPPY_DEBUG_LOG */ - idefloppy_end_request (floppy->pc->error ? 0:1, HWGROUP(drive)); + idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1); } /* @@ -939,7 +971,7 @@ #endif /* IDEFLOPPY_DEBUG_LOG */ clear_bit (PC_DMA_IN_PROGRESS, &pc->flags); - ide__sti(); /* local CPU only */ + local_irq_enable(); if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDEFLOPPY_DEBUG_LOG @@ -985,7 +1017,9 @@ if (temp > pc->buffer_size) { printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n"); idefloppy_discard_data (drive,bcount.all); - ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); return ide_started; } #if IDEFLOPPY_DEBUG_LOG @@ -1007,7 +1041,9 @@ pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; - ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ return ide_started; } @@ -1023,15 +1059,19 @@ idefloppy_ireason_reg_t ireason; if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { - printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n"); + printk(KERN_ERR "ide-floppy: Strange, packet command " + "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason.all=IN_BYTE (IDE_IREASON_REG); + ireason.all = IN_BYTE(IDE_IREASON_REG); if (!ireason.b.cod || ireason.b.io) { - printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n"); + printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while " + "issuing a packet command\n"); return ide_do_reset (drive); } - ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */ + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ return ide_started; } @@ -1053,8 +1093,8 @@ { idefloppy_floppy_t *floppy = drive->driver_data; - atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ - return IDEFLOPPY_WAIT_CMD; /* Timeout for the packet command */ + atapi_output_bytes(drive, floppy->pc->c, 12); /* Send the actual packet */ + return IDEFLOPPY_WAIT_CMD; /* Timeout for the packet command */ } static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive) @@ -1064,12 +1104,14 @@ idefloppy_ireason_reg_t ireason; if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { - printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n"); + printk(KERN_ERR "ide-floppy: Strange, packet command " + "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason.all=IN_BYTE (IDE_IREASON_REG); + ireason.all = IN_BYTE(IDE_IREASON_REG); if (!ireason.b.cod || ireason.b.io) { - printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n"); + printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) " + "while issuing a packet command\n"); return ide_do_reset (drive); } /* @@ -1079,9 +1121,11 @@ * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will * not be actually used until after the packet is moved in about 50 msec. */ - ide_set_handler (drive, + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, &idefloppy_pc_intr, /* service routine for packet command */ - floppy->ticks, /* wait this long before "failing" */ + floppy->ticks, /* wait this long before "failing" */ &idefloppy_transfer_pc2); /* fail == transfer_pc2 */ return ide_started; } @@ -1114,10 +1158,15 @@ if (!test_bit (PC_ABORT, &pc->flags)) { if (!test_bit (PC_SUPPRESS_ERROR, &pc->flags)) { ; - printk( KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n", - drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq); + printk(KERN_ERR "ide-floppy: %s: I/O error, " + "pc = %2x, key = %2x, " + "asc = %2x, ascq = %2x\n", + drive->name, pc->c[0], + floppy->sense_key, + floppy->asc, floppy->ascq); } - pc->error = IDEFLOPPY_ERROR_GENERAL; /* Giving up */ + /* Giving up */ + pc->error = IDEFLOPPY_ERROR_GENERAL; } floppy->failed_pc=NULL; pc->callback(drive); @@ -1128,7 +1177,7 @@ #endif /* IDEFLOPPY_DEBUG_LOG */ pc->retries++; - pc->actually_transferred=0; /* We haven't transferred any data yet */ + pc->actually_transferred=0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024); @@ -1141,14 +1190,14 @@ #endif /* CONFIG_BLK_DEV_IDEDMA */ if (IDE_CONTROL_REG) - OUT_BYTE (drive->ctl,IDE_CONTROL_REG); - OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */ - OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG); - OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG); - OUT_BYTE (drive->select.all,IDE_SELECT_REG); + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + OUT_BYTE(dma_ok ? 1:0,IDE_FEATURE_REG); /* Use PIO/DMA */ + OUT_BYTE(bcount.b.high,IDE_BCOUNTH_REG); + OUT_BYTE(bcount.b.low,IDE_BCOUNTL_REG); + OUT_BYTE(drive->select.all,IDE_SELECT_REG); #ifdef CONFIG_BLK_DEV_IDEDMA - if (dma_ok) { /* Begin DMA, if necessary */ + if (dma_ok) { /* Begin DMA, if necessary */ set_bit (PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } @@ -1162,11 +1211,13 @@ } if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { - ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL); - OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL); + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ return ide_started; } else { - OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); return (*pkt_xfer_routine) (drive); } } @@ -1177,7 +1228,7 @@ printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n"); #endif /* IDEFLOPPY_DEBUG_LOG */ - idefloppy_end_request(1, HWGROUP(drive)); + idefloppy_do_end_request(drive, 1); return; } @@ -1300,25 +1351,33 @@ idefloppy_pc_t *pc; #if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); - printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); + printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n", + rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors); + printk(KERN_INFO "sector: %ld, nr_sectors: %ld, " + "current_nr_sectors: %ld\n", rq->sector, + rq->nr_sectors, rq->current_nr_sectors); #endif /* IDEFLOPPY_DEBUG_LOG */ if (rq->errors >= ERROR_MAX) { if (floppy->failed_pc != NULL) - printk (KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n", - drive->name, floppy->failed_pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq); + printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x," + " key = %2x, asc = %2x, ascq = %2x\n", + drive->name, floppy->failed_pc->c[0], + floppy->sense_key, floppy->asc, floppy->ascq); else - printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name); - idefloppy_end_request (0, HWGROUP(drive)); + printk(KERN_ERR "ide-floppy: %s: I/O error\n", + drive->name); + idefloppy_do_end_request(drive, 0); return ide_stopped; } switch (rq->cmd) { case READ: case WRITE: - if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) { - printk ("%s: unsupported r/w request size\n", drive->name); - idefloppy_end_request (0, HWGROUP(drive)); + if (rq->sector % floppy->bs_factor || + rq->nr_sectors % floppy->bs_factor) { + printk("%s: unsupported r/w request size\n", + drive->name); + idefloppy_do_end_request(drive, 0); return ide_stopped; } pc = idefloppy_next_pc_storage (drive); @@ -1328,8 +1387,9 @@ pc = (idefloppy_pc_t *) rq->buffer; break; default: - printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd); - idefloppy_end_request (0,HWGROUP (drive)); + printk(KERN_ERR "ide-floppy: unsupported command %x" + " in request queue\n", rq->cmd); + idefloppy_do_end_request(drive, 0); return ide_stopped; } pc->rq = rq; @@ -1377,8 +1437,10 @@ page->rpm = ntohs (page->rpm); capacity = page->cyls * page->heads * page->sectors * page->sector_size; if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t))) - printk (KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, %d sector size, %d rpm\n", - drive->name, capacity / 1024, page->cyls, page->heads, page->sectors, + printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, " + "%d sector size, %d rpm\n", + drive->name, capacity / 1024, page->cyls, + page->heads, page->sectors, page->transfer_rate / 8, page->sector_size, page->rpm); floppy->flexible_disk_page = *page; @@ -1387,8 +1449,8 @@ drive->bios_sect = page->sectors; lba_capacity = floppy->blocks * floppy->block_size; if (capacity < lba_capacity) { - printk (KERN_NOTICE "%s: The disk reports a capacity of %d bytes, " - "but the drive only handles %d\n", + printk(KERN_NOTICE "%s: The disk reports a capacity of %d " + "bytes, but the drive only handles %d\n", drive->name, lba_capacity, capacity); floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0; } @@ -1483,8 +1545,7 @@ } /* Clik! disk does not support get_flexible_disk_page */ - if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) - { + if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { (void) idefloppy_get_flexible_disk_page (drive); } @@ -1659,10 +1720,9 @@ idefloppy_status_reg_t status; unsigned long flags; - __save_flags(flags); - __cli(); + local_irq_save(flags); status.all=GET_STAT(); - __restore_flags(flags); + local_irq_restore(flags); progress_indication= !status.b.dsc ? 0:0x10000; } @@ -2089,6 +2149,7 @@ #endif /* CONFIG_PROC_FS */ +int idefloppy_init (void); int idefloppy_reinit(ide_drive_t *drive); /* @@ -2099,13 +2160,21 @@ version: IDEFLOPPY_VERSION, media: ide_floppy, busy: 0, +#ifdef CONFIG_IDEDMA_ONLYDISK + supports_dma: 0, +#else supports_dma: 1, +#endif supports_dsc_overlap: 0, cleanup: idefloppy_cleanup, standby: NULL, + suspend: NULL, + resume: NULL, flushcache: NULL, do_request: idefloppy_do_request, - end_request: idefloppy_end_request, + end_request: idefloppy_do_end_request, + sense: NULL, + error: NULL, ioctl: idefloppy_ioctl, open: idefloppy_open, release: idefloppy_release, @@ -2115,12 +2184,12 @@ capacity: idefloppy_capacity, special: NULL, proc: idefloppy_proc, + init: idefloppy_init, reinit: idefloppy_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, }; -int idefloppy_init (void); static ide_module_t idefloppy_module = { IDE_DRIVER_MODULE, idefloppy_init, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-pci.c linux.20pre2-ac1/drivers/ide/ide-pci.c --- linux.20pre2/drivers/ide/ide-pci.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-pci.c 2002-08-06 18:03:51.000000000 +0100 @@ -12,6 +12,13 @@ * configuration of all PCI IDE interfaces present in a system. */ +/* + * Chipsets that are on the IDE_IGNORE list because of problems of not being + * set at compile time. + * + * CONFIG_BLK_DEV_PDC202XX + */ + #include #include #include @@ -30,29 +37,32 @@ #define DEVID_MPIIX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX}) #define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1}) #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) -#define DEVID_ICH0 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1}) +#define DEVID_PIIX4E ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1}) #define DEVID_PIIX4E2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1}) -#define DEVID_ICH ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) +#define DEVID_PIIX4U ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) #define DEVID_PIIX4U2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1}) #define DEVID_PIIX4NX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX}) -#define DEVID_ICH2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9}) -#define DEVID_ICH2M ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8}) -#define DEVID_ICH3M ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10}) -#define DEVID_ICH3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11}) -#define DEVID_ICH4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11}) -#define DEVID_CICH ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11}) +#define DEVID_PIIX4U3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9}) +#define DEVID_PIIX4U4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8}) +#define DEVID_PIIX4U5 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10}) +#define DEVID_PIIX4U6 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11}) +#define DEVID_PIIX4U7 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11}) +#define DEVID_PIIX4U8 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11}) #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) #define DEVID_MR_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) #define DEVID_PDC20262 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262}) +#define DEVID_PDC20263 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263}) #define DEVID_PDC20265 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265}) #define DEVID_PDC20267 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267}) #define DEVID_PDC20268 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268}) -#define DEVID_PDC20270 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270}) +#define DEVID_PDC20270 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270}) #define DEVID_PDC20269 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269}) +#define DEVID_PDC20271 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271}) #define DEVID_PDC20275 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275}) #define DEVID_PDC20276 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276}) +#define DEVID_PDC20277 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277}) #define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000}) #define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001}) #define DEVID_SAMURAI ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE}) @@ -73,12 +83,18 @@ #define DEVID_AEC6210 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF}) #define DEVID_AEC6260 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860}) #define DEVID_AEC6260R ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R}) +#define DEVID_AEC6280 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865}) +#define DEVID_AEC6880 ((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R}) #define DEVID_W82C105 ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105}) #define DEVID_UM8673F ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F}) #define DEVID_UM8886A ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A}) #define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF}) #define DEVID_HPT34X ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343}) #define DEVID_HPT366 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366}) +#define DEVID_HPT372 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372}) +#define DEVID_HPT302 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302}) +#define DEVID_HPT371 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371}) +#define DEVID_HPT374 ((ide_pci_devid_t){PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374}) #define DEVID_ALI15X3 ((ide_pci_devid_t){PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229}) #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) #define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) @@ -91,21 +107,25 @@ #define DEVID_SLC90E66 ((ide_pci_devid_t){PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1}) #define DEVID_OSB4 ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE}) #define DEVID_CSB5 ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE}) +#define DEVID_CSB6 ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE}) #define DEVID_ITE8172G ((ide_pci_devid_t){PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G}) #define IDE_IGNORE ((void *)-1) #define IDE_NO_DRIVER ((void *)-2) #ifdef CONFIG_BLK_DEV_AEC62XX +extern void fixup_device_aec6x80(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *); extern unsigned int ata66_aec62xx(ide_hwif_t *); extern void ide_init_aec62xx(ide_hwif_t *); extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long); +#define FIXUP_AEC62XX &fixup_device_aec6x80 #define PCI_AEC62XX &pci_init_aec62xx #define ATA66_AEC62XX &ata66_aec62xx #define INIT_AEC62XX &ide_init_aec62xx #define DMA_AEC62XX &ide_dmacapable_aec62xx #else +#define FIXUP_AEC62XX NULL #define PCI_AEC62XX NULL #define ATA66_AEC62XX NULL #define INIT_AEC62XX IDE_NO_DRIVER @@ -113,15 +133,18 @@ #endif #ifdef CONFIG_BLK_DEV_ALI15X3 +extern void fixup_device_ali15x3(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *); extern unsigned int ata66_ali15x3(ide_hwif_t *); extern void ide_init_ali15x3(ide_hwif_t *); extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long); +#define FIXUP_ALI15X3 &fixup_device_ali15x3 #define PCI_ALI15X3 &pci_init_ali15x3 #define ATA66_ALI15X3 &ata66_ali15x3 #define INIT_ALI15X3 &ide_init_ali15x3 #define DMA_ALI15X3 &ide_dmacapable_ali15x3 #else +#define FIXUP_ALI15X3 NULL #define PCI_ALI15X3 NULL #define ATA66_ALI15X3 NULL #define INIT_ALI15X3 IDE_NO_DRIVER @@ -129,15 +152,18 @@ #endif #ifdef CONFIG_BLK_DEV_AMD74XX +extern void fixup_device_amd74xx(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_amd74xx(struct pci_dev *, const char *); extern unsigned int ata66_amd74xx(ide_hwif_t *); extern void ide_init_amd74xx(ide_hwif_t *); extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long); +#define FIXUP_AMD74XX &fixup_device_amd74xx #define PCI_AMD74XX &pci_init_amd74xx #define ATA66_AMD74XX &ata66_amd74xx #define INIT_AMD74XX &ide_init_amd74xx #define DMA_AMD74XX &ide_dmacapable_amd74xx #else +#define FIXUP_AMD74XX NULL #define PCI_AMD74XX NULL #define ATA66_AMD74XX NULL #define INIT_AMD74XX IDE_NO_DRIVER @@ -163,11 +189,14 @@ #endif #ifdef CONFIG_BLK_DEV_CY82C693 +extern void fixup_device_cy82c693(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *); extern void ide_init_cy82c693(ide_hwif_t *); +#define FIXUP_CY82C693 &fixup_device_cy82c693 #define PCI_CY82C693 &pci_init_cy82c693 #define INIT_CY82C693 &ide_init_cy82c693 #else +#define FIXUP_CY82C693 NULL #define PCI_CY82C693 NULL #define INIT_CY82C693 IDE_NO_DRIVER #endif @@ -183,29 +212,34 @@ #endif #ifdef CONFIG_BLK_DEV_HPT34X +extern void fixup_device_hpt343(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *); extern void ide_init_hpt34x(ide_hwif_t *); +#define FIXUP_HPT34X &fixup_device_hpt343 #define PCI_HPT34X &pci_init_hpt34x #define INIT_HPT34X &ide_init_hpt34x #else +#define FIXUP_HPT34X NULL #define PCI_HPT34X NULL #define INIT_HPT34X IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_HPT366 -extern byte hpt363_shared_irq; -extern byte hpt363_shared_pin; +extern void fixup_device_hpt366(struct pci_dev *, ide_pci_device_t *); +extern void fixup_device_hpt374(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_hpt366(struct pci_dev *, const char *); extern unsigned int ata66_hpt366(ide_hwif_t *); extern void ide_init_hpt366(ide_hwif_t *); extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long); +#define FIXUP_HPT366 &fixup_device_hpt366 +#define FIXUP_HPT374 &fixup_device_hpt374 #define PCI_HPT366 &pci_init_hpt366 #define ATA66_HPT366 &ata66_hpt366 #define INIT_HPT366 &ide_init_hpt366 #define DMA_HPT366 &ide_dmacapable_hpt366 #else -static byte hpt363_shared_irq; -static byte hpt363_shared_pin; +#define FIXUP_HPT366 NULL +#define FIXUP_HPT374 NULL #define PCI_HPT366 NULL #define ATA66_HPT366 NULL #define INIT_HPT366 IDE_NO_DRIVER @@ -220,9 +254,12 @@ #endif #ifdef CONFIG_BLK_DEV_OPTI621 +extern void fixup_device_opti621(struct pci_dev *, ide_pci_device_t *); extern void ide_init_opti621(ide_hwif_t *); +#define FIXUP_OPTI621 &fixup_device_opti621 #define INIT_OPTI621 &ide_init_opti621 #else +#define FIXUP_OPTI621 NULL #define INIT_OPTI621 IDE_NO_DRIVER #endif @@ -243,41 +280,54 @@ #endif #ifdef CONFIG_BLK_DEV_PDC202XX +extern void fixup_device_pdc20265(struct pci_dev *, ide_pci_device_t *); +extern void fixup_device_pdc20270(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *); extern unsigned int ata66_pdc202xx(ide_hwif_t *); extern void ide_init_pdc202xx(ide_hwif_t *); +#define FIXUP_PDC20265 &fixup_device_pdc20265 +#define FIXUP_PDC20270 &fixup_device_pdc20270 #define PCI_PDC202XX &pci_init_pdc202xx #define ATA66_PDC202XX &ata66_pdc202xx #define INIT_PDC202XX &ide_init_pdc202xx #else -#define PCI_PDC202XX NULL -#define ATA66_PDC202XX NULL -#define INIT_PDC202XX NULL +#define FIXUP_PDC20265 IDE_IGNORE +#define FIXUP_PDC20270 IDE_IGNORE +#define PCI_PDC202XX IDE_IGNORE +#define ATA66_PDC202XX IDE_IGNORE +#define INIT_PDC202XX IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_PIIX +extern void fixup_device_piix(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_piix(struct pci_dev *, const char *); extern unsigned int ata66_piix(ide_hwif_t *); extern void ide_init_piix(ide_hwif_t *); +#define FIXUP_PIIX &fixup_device_piix #define PCI_PIIX &pci_init_piix #define ATA66_PIIX &ata66_piix #define INIT_PIIX &ide_init_piix #else +#define FIXUP_PIIX NULL #define PCI_PIIX NULL #define ATA66_PIIX NULL #define INIT_PIIX IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_IT8172 +extern void fixup_device_it8172(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_it8172(struct pci_dev *, const char *); extern unsigned int ata66_it8172(ide_hwif_t *); extern void ide_init_it8172(ide_hwif_t *); +#define FIXUP_IT8172 &fixup_device_it8172 #define PCI_IT8172 &pci_init_it8172 +#define ATA66_IT8172 &ata66_it8172 #define INIT_IT8172 &ide_init_it8172 #else +#define FIXUP_IT8172 NULL #define PCI_IT8172 NULL #define ATA66_IT8172 NULL -#define INIT_IT8172 NULL +#define INIT_IT8172 IDE_NO_DRIVER #endif #ifdef CONFIG_BLK_DEV_RZ1000 @@ -290,26 +340,35 @@ #define INIT_SAMURAI NULL #ifdef CONFIG_BLK_DEV_SVWKS +extern void fixup_device_csb6(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_svwks(struct pci_dev *, const char *); extern unsigned int ata66_svwks(ide_hwif_t *); extern void ide_init_svwks(ide_hwif_t *); +extern void ide_dmacapable_svwks(ide_hwif_t *, unsigned long); +#define FIXUP_CSB6 &fixup_device_csb6 #define PCI_SVWKS &pci_init_svwks #define ATA66_SVWKS &ata66_svwks #define INIT_SVWKS &ide_init_svwks +#define DMA_SVWKS &ide_dmacapable_svwks #else +#define FIXUP_CSB6 NULL #define PCI_SVWKS NULL #define ATA66_SVWKS NULL #define INIT_SVWKS IDE_NO_DRIVER +#define DMA_SVWKS NULL #endif #ifdef CONFIG_BLK_DEV_SIS5513 +extern void fixup_device_sis5513(struct pci_dev *, ide_pci_device_t *); extern unsigned int pci_init_sis5513(struct pci_dev *, const char *); extern unsigned int ata66_sis5513(ide_hwif_t *); extern void ide_init_sis5513(ide_hwif_t *); +#define FIXUP_SIS5513 &fixup_device_sis5513 #define PCI_SIS5513 &pci_init_sis5513 #define ATA66_SIS5513 &ata66_sis5513 #define INIT_SIS5513 &ide_init_sis5513 #else +#define FIXUP_SIS5513 NULL #define PCI_SIS5513 NULL #define ATA66_SIS5513 NULL #define INIT_SIS5513 IDE_NO_DRIVER @@ -364,106 +423,98 @@ #define DMA_VIA82CXXX NULL #endif -typedef struct ide_pci_enablebit_s { - byte reg; /* byte pci reg holding the enable-bit */ - byte mask; /* mask to isolate the enable-bit */ - byte val; /* value of masked reg when "enabled" */ -} ide_pci_enablebit_t; - -typedef struct ide_pci_device_s { - ide_pci_devid_t devid; - char *name; - unsigned int (*init_chipset)(struct pci_dev *dev, const char *name); - unsigned int (*ata66_check)(ide_hwif_t *hwif); - void (*init_hwif)(ide_hwif_t *hwif); - void (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase); - ide_pci_enablebit_t enablebits[2]; - byte bootable; - unsigned int extra; -} ide_pci_device_t; - static ide_pci_device_t ide_pci_chipsets[] __initdata = { - {DEVID_PIIXa, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIXb, "PIIX", NULL, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_MPIIX, "MPIIX", NULL, NULL, INIT_PIIX, NULL, {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX3, "PIIX3", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH0, "ICH0", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4E2, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH, "ICH", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4U2, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_PIIX4NX, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH2, "ICH2", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH2M, "ICH2M", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH3M, "ICH3M", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH3, "ICH3", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_ICH4, "ICH4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_CICH, "C-ICH", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_MR_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, - {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, -#ifndef CONFIG_PDC202XX_FORCE - {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 }, - {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, - {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48 }, - {DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, + {DEVID_PIIXa, "PIIX", FIXUP_PIIX, PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIXb, "PIIX", FIXUP_PIIX, PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_MPIIX, "MPIIX", FIXUP_PIIX, NULL, NULL, INIT_PIIX, NULL, {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX3, "PIIX3", FIXUP_PIIX, PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4, "PIIX4", FIXUP_PIIX, PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4E, "PIIX4", FIXUP_PIIX, PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4E2, "PIIX4", FIXUP_PIIX, PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U, "PIIX4", FIXUP_PIIX, PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U2, "PIIX4", FIXUP_PIIX, PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4NX, "PIIX4", FIXUP_PIIX, PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U3, "PIIX4", FIXUP_PIIX, PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U4, "PIIX4", FIXUP_PIIX, PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U5, "PIIX4", FIXUP_PIIX, PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U6, "PIIX4", FIXUP_PIIX, PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U7, "PIIX4", FIXUP_PIIX, PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U8, "PIIX4", FIXUP_PIIX, PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_MR_IDE, "VP_IDE", NULL, PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, + {DEVID_VP_IDE, "VP_IDE", NULL, PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, +#ifdef CONFIG_PDC202XX_FORCE + {DEVID_PDC20246,"PDC20246", NULL, PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 }, + {DEVID_PDC20262,"PDC20262", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, + {DEVID_PDC20263,"PDC20263", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, + {DEVID_PDC20265,"PDC20265", FIXUP_PDC20265, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48 }, + {DEVID_PDC20267,"PDC20267", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48 }, #else /* !CONFIG_PDC202XX_FORCE */ - {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, - {DEVID_PDC20262,"PDC20262", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, - {DEVID_PDC20265,"PDC20265", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, - {DEVID_PDC20267,"PDC20267", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, -#endif - {DEVID_PDC20268,"PDC20268", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - /* Promise used a different PCI ident for the raid card apparently to try and - prevent Linux detecting it and using our own raid code. We want to detect - it for the ataraid drivers, so we have to list both here.. */ - {DEVID_PDC20270,"PDC20270", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_PDC20269,"PDC20269", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_PDC20275,"PDC20275", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_PDC20276,"PDC20276", PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_RZ1000, "RZ1000", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_RZ1001, "RZ1001", NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_SAMURAI, "SAMURAI", NULL, NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD640, "CMD640", NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87410, "NS87410", NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, - {DEVID_SIS5513, "SIS5513", PCI_SIS5513, ATA66_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, - {DEVID_CMD643, "CMD643", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD646, "CMD646", PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_CMD648, "CMD648", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CMD649, "CMD649", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, -#ifndef CONFIG_BLK_DEV_CMD680 - {DEVID_CMD680, "CMD680", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, -#else /* CONFIG_BLK_DEV_CMD680 */ - {DEVID_CMD680, "CMD680", PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, -#endif /* !CONFIG_BLK_DEV_CMD680 */ - {DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621, "OPTI621", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_OPTI621X,"OPTI621X", NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, - {DEVID_TRM290, "TRM290", NULL, NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_NS87415, "NS87415", NULL, NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AEC6210, "AEC6210", PCI_AEC62XX, NULL, INIT_AEC62XX, DMA_AEC62XX, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, - {DEVID_AEC6260, "AEC6260", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0 }, - {DEVID_AEC6260R,"AEC6260R", PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, - {DEVID_W82C105, "W82C105", PCI_W82C105, NULL, INIT_W82C105, DMA_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, - {DEVID_UM8673F, "UM8673F", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HPT34X, "HPT34X", PCI_HPT34X, NULL, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, - {DEVID_HPT366, "HPT366", PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 240 }, - {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, ATA66_ALI15X3, INIT_ALI15X3, DMA_ALI15X3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AMD7401, "AMD7401", NULL, NULL, NULL, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, - {DEVID_AMD7409, "AMD7409", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, - {DEVID_AMD7411, "AMD7411", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, - {DEVID_AMD7441, "AMD7441", PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, - {DEVID_PDCADMA, "PDCADMA", PCI_PDCADMA, ATA66_PDCADMA, INIT_PDCADMA, DMA_PDCADMA, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, - {DEVID_SLC90E66,"SLC90E66", PCI_SLC90E66, ATA66_SLC90E66, INIT_SLC90E66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, - {DEVID_OSB4, "ServerWorks OSB4", PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CSB5, "ServerWorks CSB5", PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_ITE8172G,"IT8172G", PCI_IT8172, NULL, INIT_IT8172, NULL, {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, ON_BOARD, 0 }, - {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; + {DEVID_PDC20246,"PDC20246", NULL, PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, + {DEVID_PDC20262,"PDC20262", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, + {DEVID_PDC20263,"PDC20263", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, + {DEVID_PDC20265,"PDC20265", FIXUP_PDC20265, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, + {DEVID_PDC20267,"PDC20267", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48 }, +#endif + {DEVID_PDC20268,"PDC20268", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + /* + * Promise used a different PCI ident for the raid card apparently + * to try and prevent Linux detecting it and using our own raid code. + * We want to detect it for the ataraid drivers, so we have to list + * both here.. + */ + {DEVID_PDC20270,"PDC20270", FIXUP_PDC20270, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_PDC20269,"PDC20269", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_PDC20271,"PDC20271", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_PDC20275,"PDC20275", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_PDC20276,"PDC20276", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_PDC20277,"PDC20277", NULL, PCI_PDC202XX, ATA66_PDC202XX, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_RZ1000, "RZ1000", NULL, NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_RZ1001, "RZ1001", NULL, NULL, NULL, INIT_RZ1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_SAMURAI, "SAMURAI", NULL, NULL, NULL, INIT_SAMURAI, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD640, "CMD640", NULL, NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_NS87410, "NS87410", NULL, NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0 }, + {DEVID_SIS5513, "SIS5513", FIXUP_SIS5513, PCI_SIS5513, ATA66_SIS5513, INIT_SIS5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0 }, + {DEVID_CMD643, "CMD643", NULL, PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD646, "CMD646", NULL, PCI_CMD64X, NULL, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_CMD648, "CMD648", NULL, PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD649, "CMD649", NULL, PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CMD680, "CMD680", NULL, PCI_CMD64X, ATA66_CMD64X, INIT_CMD64X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_HT6565, "HT6565", NULL, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_OPTI621, "OPTI621", FIXUP_OPTI621, NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, + {DEVID_OPTI621X,"OPTI621X", FIXUP_OPTI621, NULL, NULL, INIT_OPTI621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0 }, + {DEVID_TRM290, "TRM290", NULL, NULL, NULL, INIT_TRM290, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_NS87415, "NS87415", NULL, NULL, NULL, INIT_NS87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_AEC6210, "AEC6210", NULL, PCI_AEC62XX, NULL, INIT_AEC62XX, DMA_AEC62XX, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, + {DEVID_AEC6260, "AEC6260", NULL, PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0 }, + {DEVID_AEC6260R,"AEC6260R", NULL, PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, + {DEVID_AEC6280, "AEC6X80", FIXUP_AEC62XX, PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0 }, + {DEVID_AEC6880, "AEC6X80R", FIXUP_AEC62XX, PCI_AEC62XX, ATA66_AEC62XX, INIT_AEC62XX, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0 }, + {DEVID_W82C105, "W82C105", NULL, PCI_W82C105, NULL, INIT_W82C105, DMA_W82C105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0 }, + {DEVID_UM8673F, "UM8673F", NULL, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_UM8886A, "UM8886A", NULL, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_UM8886BF,"UM8886BF", NULL, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_HPT34X, "HPT34X", FIXUP_HPT34X, PCI_HPT34X, NULL, INIT_HPT34X, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16 }, + {DEVID_HPT366, "HPT366", FIXUP_HPT366, PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 240 }, + {DEVID_HPT372, "HPT372A", NULL, PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_HPT302, "HPT302", NULL, PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_HPT371, "HPT371", NULL, PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_HPT374, "HPT374", FIXUP_HPT374, PCI_HPT366, ATA66_HPT366, INIT_HPT366, DMA_HPT366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_ALI15X3, "ALI15X3", FIXUP_ALI15X3, PCI_ALI15X3, ATA66_ALI15X3, INIT_ALI15X3, DMA_ALI15X3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CY82C693,"CY82C693", FIXUP_CY82C693, PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CS5530, "CS5530", NULL, PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_AMD7401, "AMD7401", FIXUP_AMD74XX, NULL, NULL, NULL, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, + {DEVID_AMD7409, "AMD7409", FIXUP_AMD74XX, PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, + {DEVID_AMD7411, "AMD7411", FIXUP_AMD74XX, PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, + {DEVID_AMD7441, "AMD7441", FIXUP_AMD74XX, PCI_AMD74XX, ATA66_AMD74XX, INIT_AMD74XX, DMA_AMD74XX, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, + {DEVID_PDCADMA, "PDCADMA", NULL, PCI_PDCADMA, ATA66_PDCADMA, INIT_PDCADMA, DMA_PDCADMA, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0 }, + {DEVID_SLC90E66,"SLC90E66", NULL, PCI_SLC90E66, ATA66_SLC90E66, INIT_SLC90E66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_OSB4, "SvrWks OSB4", NULL, PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CSB5, "SvrWks CSB5", NULL, PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, DMA_SVWKS, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CSB6, "SvrWks CSB6", FIXUP_CSB6, PCI_SVWKS, ATA66_SVWKS, INIT_SVWKS, DMA_SVWKS, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_ITE8172G,"IT8172G", FIXUP_IT8172, PCI_IT8172, NULL, INIT_IT8172, NULL, {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, ON_BOARD, 0 }, + {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* * This allows offboard ide-pci cards the enable a BIOS, verify interrupt @@ -474,18 +525,33 @@ { switch(dev->device) { case PCI_DEVICE_ID_TTI_HPT366: + case PCI_DEVICE_ID_TTI_HPT372: + case PCI_DEVICE_ID_TTI_HPT302: + case PCI_DEVICE_ID_TTI_HPT371: + case PCI_DEVICE_ID_TTI_HPT374: case PCI_DEVICE_ID_PROMISE_20246: case PCI_DEVICE_ID_PROMISE_20262: + case PCI_DEVICE_ID_PROMISE_20263: case PCI_DEVICE_ID_PROMISE_20265: case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20268: case PCI_DEVICE_ID_PROMISE_20270: case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20275: case PCI_DEVICE_ID_PROMISE_20276: - case PCI_DEVICE_ID_ARTOP_ATP850UF: - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: + case PCI_DEVICE_ID_PROMISE_20277: + /* + * case PCI_DEVICE_ID_ARTOP_ATP850UF: + * same device ID value as PCI_DEVICE_ID_TTI_HPT372 + * case PCI_DEVICE_ID_ARTOP_ATP860: + * same device ID value as PCI_DEVICE_ID_TTI_HPT302 + * case PCI_DEVICE_ID_ARTOP_ATP860R: + * same device ID value as PCI_DEVICE_ID_TTI_HPT371 + * case PCI_DEVICE_ID_ARTOP_ATP865: + * same device ID value as PCI_DEVICE_ID_TTI_HPT374 + */ + case PCI_DEVICE_ID_ARTOP_ATP865R: return dev->irq; default: break; @@ -523,7 +589,8 @@ if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) { if (hwif->chipset == ide_unknown) return hwif; /* match */ - printk("%s: port 0x%04lx already claimed by %s\n", name, io_base, hwif->name); + printk("%s: port 0x%04lx already claimed by %s\n", + name, io_base, hwif->name); return NULL; /* already claimed */ } } @@ -566,9 +633,11 @@ /* * Place both IDE interfaces into PCI "native" mode: */ - if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) { + if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || + (progif & 5) != 5) { if ((progif & 0xa) != 0xa) { - printk("%s: device not capable of full native PCI mode\n", name); + printk("%s: device not capable of full " + "native PCI mode\n", name); return 1; } printk("%s: placing both ports into native PCI mode\n", name); @@ -603,7 +672,7 @@ * we "know" about, this information is in the ide_pci_device_t struct; * for all other chipsets, we just assume both interfaces are enabled. */ -static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d) +void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d) { unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0; unsigned short pcicmd = 0, tried_config = 0; @@ -618,13 +687,20 @@ #endif if (d->init_hwif == IDE_NO_DRIVER) { - printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name); + printk(KERN_WARNING "%s: detected chipset, " + "but driver not compiled in!\n", d->name); d->init_hwif = NULL; } if (pci_enable_device(dev)) { - printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name); - return; + if (pci_enable_device_bars(dev, 1 << 4)) + { + printk(KERN_WARNING "%s: (ide_setup_pci_device:) " + "Could not enable device.\n", d->name); + return; + } + else + printk(KERN_WARNING "%s: Not fully BIOS configured!\n", d->name); } check_if_enabled: @@ -654,14 +730,6 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { - /* see comments in hpt34x.c on why..... */ - char *chipset_names[] = {"HPT343", "HPT345"}; - strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]); - d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; - } - printk("%s: chipset revision %d\n", d->name, class_rev); /* @@ -669,20 +737,27 @@ */ pciirq = dev->irq; -#ifdef CONFIG_PDC202XX_FORCE - if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) { - /* - * By rights we want to ignore Promise FastTrak and SuperTrak - * series here, those use own driver. - */ - if (dev->vendor == PCI_VENDOR_ID_PROMISE) { - printk(KERN_INFO "ide: Skipping Promise RAID controller.\n"); - return; + if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) + { + /* By rights we want to ignore these, but the Promise Fastrak + people have some strange ideas about proprietary so we have + to act otherwise on those. The supertrak however we need + to skip */ + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276)) + { + if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL && + (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960 || dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM)) + { + printk(KERN_INFO "ide: Skipping Promise IDE controller attached to I2O RAID controller.\n"); + return; + } } + /* Its attached to something else, just a random bridge. + Suspect a fastrak and fall through */ } -#endif /* CONFIG_PDC202XX_FORCE */ if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) { - printk("%s: not 100%% native mode: will probe irqs later\n", d->name); + printk("%s: not 100%% native mode: " + "will probe irqs later\n", d->name); /* * This allows offboard ide-pci cards the enable a BIOS, * verify interrupt settings of split-mirror pci-config @@ -715,34 +790,52 @@ ide_pci_enablebit_t *e = &(d->enablebits[port]); /* - * If this is a Promise FakeRaid controller, the 2nd controller will be marked as - * disabled while it is actually there and enabled by the bios for raid purposes. + * If this is a Promise FakeRaid controller, + * the 2nd controller will be marked as + * disabled while it is actually there and enabled + * by the bios for raid purposes. * Skip the normal "is it enabled" test for those. */ - if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) && (secondpdc++==1) && (port==1) ) + if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) && + (secondpdc++==1) && (port==1)) goto controller_ok; - if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) && (secondpdc++==1) && (port==1) ) + if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) && + (secondpdc++==1) && (port==1)) goto controller_ok; - if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) + if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || + (tmp & e->mask) != e->val)) continue; /* port not enabled */ controller_ok: - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev < 0x03)) + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && + (port) && (class_rev < 0x03)) + return; + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT302) && (port)) return; - if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) { + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) && + (port) && (!(PCI_FUNC(dev->devfn) & 1))) + return; + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || + (dev->class & (port ? 4 : 1)) != 0) { ctl = dev->resource[(2*port)+1].start; base = dev->resource[2*port].start; if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) || !(base & PCI_BASE_ADDRESS_IO_MASK)) { - printk("%s: IO baseregs (BIOS) are reported as MEM, report to .\n", d->name); + printk("%s: IO baseregs (BIOS) are reported " + "as MEM, report to " + ".\n", d->name); #if 0 - /* FIXME! This really should check that it really gets the IO/MEM part right! */ + /* + * FIXME! This really should check that + * it really gets the IO/MEM part right! + */ continue; #endif } } if ((ctl && !base) || (base && !ctl)) { - printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port); + printk("%s: inconsistent baseregs (BIOS) " + "for port %d, skipping\n", d->name, port); continue; } if (!ctl) @@ -781,7 +874,8 @@ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA)) goto bypass_legacy_dma; if (hwif->udma_four) { - printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name); + printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", + d->name); } else { hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0; } @@ -799,18 +893,27 @@ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20263) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20270) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20271) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20277) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6280) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6880) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT372) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT302) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT371) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT374) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) || @@ -855,102 +958,6 @@ printk("%s: neither IDE port enabled (BIOS)\n", d->name); } -static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) -{ - struct pci_dev *dev2 = NULL, *findev; - ide_pci_device_t *d2; - - if ((dev->bus->self && - dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && - (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) { - if (PCI_SLOT(dev->devfn) & 2) { - return; - } - d->extra = 0; - pci_for_each_dev(findev) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - (PCI_SLOT(findev->devfn) & 2)) { - byte irq = 0, irq2 = 0; - dev2 = findev; - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); - pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2); - if (irq != irq2) { - dev2->irq = dev->irq; - pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq); - } - - } - } - } - - printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); - ide_setup_pci_device(dev, d); - if (!dev2) - return; - d2 = d; - printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); - ide_setup_pci_device(dev2, d2); -} - -static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d) -{ - struct pci_dev *dev2 = NULL, *findev; - ide_pci_device_t *d2; - unsigned char pin1 = 0, pin2 = 0; - unsigned int class_rev; - char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A", "HPT372"}; - - if (PCI_FUNC(dev->devfn) & 1) - return; - - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - if (class_rev > 5) - class_rev = 5; - - strcpy(d->name, chipset_names[class_rev]); - - switch(class_rev) { - case 4: - case 3: printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); - ide_setup_pci_device(dev, d); - return; - default: break; - } - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - pci_for_each_dev(findev) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - ((findev->devfn - dev->devfn) == 1) && - (PCI_FUNC(findev->devfn) & 1)) { - dev2 = findev; - pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); - hpt363_shared_pin = (pin1 != pin2) ? 1 : 0; - hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0; - if (hpt363_shared_pin && hpt363_shared_irq) { - d->bootable = ON_BOARD; - printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2); -#if 0 - /* I forgot why I did this once, but it fixed something. */ - pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq); - printk("PCI: %s: Fixing interrupt %d pin %d to ZERO \n", d->name, dev2->irq, pin2); - pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0); -#endif - } - break; - } - } - printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); - ide_setup_pci_device(dev, d); - if (!dev2) - return; - d2 = d; - printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); - ide_setup_pci_device(dev2, d2); -} - /* * ide_scan_pcibus() gets invoked at boot time from ide.c. * It finds all PCI IDE controllers and calls ide_setup_pci_device for them. @@ -962,27 +969,32 @@ devid.vid = dev->vendor; devid.did = dev->device; - for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d); + for (d = ide_pci_chipsets; + d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d); + if (d->init_hwif == IDE_IGNORE) - printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name); - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1)) + printk("%s: ignored by ide_scan_pci_device() " + "(uses own driver)\n", d->name); + else if (d->fixup_device) + d->fixup_device(dev, d); +#if 0 + else if (((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) && + (!(PCI_FUNC(dev->devfn) & 1))) return; - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) - return; /* CY82C693 is more than only a IDE controller */ - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))) - return; /* IT8172G is also more than only an IDE controller */ - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1)) +#endif + else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && + (!(PCI_FUNC(dev->devfn) & 1))) return; /* UM8886A/BF pair */ - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366)) - hpt366_device_order_fixup(dev, d); - else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20270)) - pdc20270_device_order_fixup(dev, d); - else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || + (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL)) - printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n", - d->name, dev->bus->number, dev->devfn, devid.vid, devid.did); + printk("%s: unknown IDE controller on PCI bus " + "%02x device %02x, VID=%04x, DID=%04x\n", + d->name, dev->bus->number, dev->devfn, + devid.vid, devid.did); else - printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn); + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); ide_setup_pci_device(dev, d); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-pmac.c linux.20pre2-ac1/drivers/ide/ide-pmac.c --- linux.20pre2/drivers/ide/ide-pmac.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-pmac.c 2002-08-06 15:42:11.000000000 +0100 @@ -44,7 +44,6 @@ #endif #include "ide_modes.h" -extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq); #define IDE_PMAC_DEBUG @@ -362,41 +361,6 @@ } -/* Note: We don't use the generic routine here because for some - * yet unexplained reasons, it cause some media-bay CD-ROMs to - * lockup the bus. Strangely, this new version of the code is - * almost identical to the generic one and works, I've not yet - * managed to figure out what bit is causing the lockup in the - * generic code, possibly a timing issue... - * - * --BenH - */ -static int __pmac -wait_for_ready(ide_drive_t *drive) -{ - /* Timeout bumped for some powerbooks */ - int timeout = 2000; - byte stat; - - while(--timeout) { - stat = GET_STAT(); - if(!(stat & BUSY_STAT)) { - if (drive->ready_stat == 0) - break; - else if((stat & drive->ready_stat) || (stat & ERR_STAT)) - break; - } - mdelay(1); - } - if((stat & ERR_STAT) || timeout <= 0) { - if (stat & ERR_STAT) { - printk(KERN_ERR "ide_pmac: wait_for_ready, error status: %x\n", stat); - } - return 1; - } - return 0; -} - static int __pmac pmac_ide_do_setfeature(ide_drive_t *drive, byte command) { @@ -410,7 +374,7 @@ SELECT_MASK(HWIF(drive), drive, 0); udelay(1); (void)GET_STAT(); /* Get rid of pending error state */ - if(wait_for_ready(drive)) { + if(wait_for_ready(drive, 2000)) { /* Timeout bumped for some powerbooks */ printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); goto out; } @@ -420,10 +384,9 @@ OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); udelay(1); - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only -- for jiffies */ - result = wait_for_ready(drive); - __restore_flags(flags); /* local CPU only */ + local_irq_set(flags); + result = wait_for_ready(drive, 2000); /* Timeout bumped for some powerbooks */ + local_irq_restore(flags); OUT_BYTE(drive->ctl, IDE_CONTROL_REG); if (result) printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); @@ -1074,8 +1037,6 @@ unsigned char *virt_addr = rq->buffer; int sector_count = rq->nr_sectors; -// if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) || -// (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT)) if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) pmif->sg_dma_direction = PCI_DMA_TODEVICE; else @@ -1333,6 +1294,7 @@ static int __pmac pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { +// ide_task_t *args = HWGROUP(drive)->rq->special; int ix, dstat; volatile struct dbdma_regs *dma; byte unit = (drive->select.b.unit & 0x01); @@ -1375,16 +1337,23 @@ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); - if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) && - (drive->addressing == 1)) { +#if 0 + { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } +#else + if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) { ide_task_t *args = HWGROUP(drive)->rq->special; OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); - } else if (drive->addressing) { + } else if (drive->addressing == 1) OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); - } else { + else OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - } +#endif case ide_dma_begin: out_le32(&dma->control, (RUN << 16) | RUN); /* Make sure it gets to the controller right now */ @@ -1469,19 +1438,19 @@ switch (drive->media) { case ide_disk: /* Spin down the drive */ - outb(drive->select.all, base+0x60); - (void)inb(base+0x60); + OUT_BYTE(drive->select.all, base+0x60); + (void) IN_BYTE(base+0x60); udelay(100); - outb(0x0, base+0x30); - outb(0x0, base+0x20); - outb(0x0, base+0x40); - outb(0x0, base+0x50); - outb(0xe0, base+0x70); - outb(0x2, base+0x160); + OUT_BYTE(0x0, base+0x30); + OUT_BYTE(0x0, base+0x20); + OUT_BYTE(0x0, base+0x40); + OUT_BYTE(0x0, base+0x50); + OUT_BYTE(0xe0, base+0x70); + OUT_BYTE(0x2, base+0x160); for (j = 0; j < 10; j++) { int status; mdelay(100); - status = inb(base+0x70); + status = IN_BYTE(base+0x70); if (!(status & BUSY_STAT) && (status & DRQ_STAT)) break; } @@ -1594,10 +1563,10 @@ for (j = 0; j < 200; j++) { int status; mdelay(100); - outb(drive->select.all, base + 0x60); - if (inb(base + 0x60) != drive->select.all) + OUT_BYTE(drive->select.all, base + 0x60); + if (IN_BYTE(base + 0x60) != drive->select.all) continue; - status = inb(base + 0x70); + status = IN_BYTE(base + 0x70); if (!(status & BUSY_STAT)) break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-probe.c linux.20pre2-ac1/drivers/ide/ide-probe.c --- linux.20pre2/drivers/ide/ide-probe.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-probe.c 2002-08-06 16:04:56.000000000 +0100 @@ -54,6 +54,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) { + ide_hwif_t *hwif = HWIF(drive); int bswap = 1; struct hd_driveid *id; @@ -62,13 +63,24 @@ printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n"); goto err_kmalloc; } - - ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ - ide__sti(); /* local CPU only */ + /* read 512 bytes of id info */ +#if 1 + ata_input_data(drive, id, SECTOR_WORDS); +#else + { + unsigned long *ptr = (unsigned long *)id ; + unsigned long lcount = 256/2 ; + // printk("IDE_DATA_REG = %#lx",IDE_DATA_REG); + while( lcount-- ) + *ptr++ = inl(IDE_DATA_REG); + } +#endif + local_irq_enable(); ide_fix_driveid(id); if (id->word156 == 0x4d42) { - printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156); + printk("%s: drive->id->word156 == 0x%04x \n", + drive->name, drive->id->word156); } if (!drive->forced_lun) @@ -113,7 +125,7 @@ byte type = (id->config >> 8) & 0x1f; printk("ATAPI "); #ifdef CONFIG_BLK_DEV_PDC4030 - if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) { + if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) { printk(" -- not supported on 2nd Promise port\n"); goto err_misc; } @@ -121,7 +133,9 @@ switch (type) { case ide_floppy: if (!strstr(id->model, "CD-ROM")) { - if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP")) + if (!strstr(id->model, "oppy") && + !strstr(id->model, "poyp") && + !strstr(id->model, "ZIP")) printk("cdrom or floppy?, assuming "); if (drive->media != ide_cdrom) { printk ("FLOPPY"); @@ -133,7 +147,8 @@ drive->removable = 1; #ifdef CONFIG_PPC /* kludge for Apple PowerBook internal zip */ - if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) { + if (!strstr(id->model, "CD-ROM") && + strstr(id->model, "ZIP")) { printk ("FLOPPY"); type = ide_floppy; break; @@ -164,10 +179,11 @@ drive->removable = 1; /* * Prevent long system lockup probing later for non-existant - * slave drive if the hwif is actually a flash memory card of some variety: + * slave drive if the hwif is actually a flash memory card of + * some variety: */ if (drive_is_flashcard(drive)) { - ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit]; + ide_drive_t *mate = &hwif->drives[1^drive->select.b.unit]; if (!mate->ata_flash) { mate->present = 0; mate->noprobe = 1; @@ -175,7 +191,7 @@ } drive->media = ide_disk; printk("ATA DISK drive\n"); - QUIRK_LIST(HWIF(drive),drive); + QUIRK_LIST(hwif, drive); return; err_misc: @@ -197,6 +213,7 @@ */ static int actual_try_to_identify (ide_drive_t *drive, byte cmd) { +// ide_hwif_t *hwif = HWIF(drive); int rc; ide_ioreg_t hd_status; unsigned long timeout; @@ -235,7 +252,7 @@ timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; do { - if (0 < (signed long)(jiffies - timeout)) { + if (time_after(jiffies, timeout)) { return 1; /* drive timed-out */ } ide_delay_50ms(); /* give drive a breather */ @@ -244,12 +261,12 @@ ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only; some systems need this */ + local_irq_save(flags); + /* local CPU only; some systems need this */ do_identify(drive, cmd); /* drive returned ID */ rc = 0; /* drive responded with ID */ (void) GET_STAT(); /* clear drive IRQ */ - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); } else rc = 2; /* drive refused ID */ return rc; @@ -257,11 +274,12 @@ static int try_to_identify (ide_drive_t *drive, byte cmd) { + ide_hwif_t *hwif = HWIF(drive); int retval; int autoprobe = 0; unsigned long cookie = 0; - if (IDE_CONTROL_REG && !HWIF(drive)->irq) { + if (IDE_CONTROL_REG && !hwif->irq) { autoprobe = 1; cookie = probe_irq_on(); OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ @@ -275,14 +293,14 @@ (void) GET_STAT(); /* clear drive IRQ */ udelay(5); irq = probe_irq_off(cookie); - if (!HWIF(drive)->irq) { + if (!hwif->irq) { if (irq > 0) { - HWIF(drive)->irq = irq; + hwif->irq = irq; } else { /* Mmmm.. multiple IRQs.. don't know which was ours */ printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie); #ifdef CONFIG_BLK_DEV_CMD640 #ifdef CMD640_DUMP_REGS - if (HWIF(drive)->chipset == ide_cmd640) { + if (hwif->chipset == ide_cmd640) { printk("%s: Hmmm.. probably a driver problem.\n", drive->name); CMD640_DUMP_REGS; } @@ -335,9 +353,8 @@ return 3; /* no i/f present: mmm.. this should be a 4 -ml */ } - if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) - || drive->present || cmd == WIN_PIDENTIFY) - { + if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) || + drive->present || cmd == WIN_PIDENTIFY) { if ((rc = try_to_identify(drive,cmd))) /* send cmd and wait */ rc = try_to_identify(drive,cmd); /* failed: try again */ if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) { @@ -371,10 +388,11 @@ */ static void enable_nest (ide_drive_t *drive) { + ide_hwif_t *hwif = HWIF(drive); unsigned long timeout; - printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model); - SELECT_DRIVE(HWIF(drive), drive); + printk("%s: enabling %s -- ", hwif->name, drive->id->model); + SELECT_DRIVE(hwif, drive); ide_delay_50ms(); OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); timeout = jiffies + WAIT_WORSTCASE; @@ -390,9 +408,9 @@ printk("failed (status = 0x%02x)\n", GET_STAT()); else printk("success\n"); - if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */ + + if (do_probe(drive, WIN_IDENTIFY) >= 2) /* if !(success||timed-out) */ (void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */ - } } /* @@ -530,8 +548,7 @@ return; } - __save_flags(flags); /* local CPU only */ - __sti(); /* local CPU only; needed for jiffies and irq probing */ + local_irq_set(flags); /* * Second drive should only exist if first drive was found, * but a lot of cdrom drives are configured as single slaves. @@ -541,7 +558,8 @@ (void) probe_for_drive (drive); if (drive->present && !hwif->present) { hwif->present = 1; - if (hwif->chipset != ide_4drives || !hwif->mate->present) { + if (hwif->chipset != ide_4drives || + !hwif->mate->present) { hwif_register(hwif); } } @@ -557,16 +575,16 @@ do { ide_delay_50ms(); stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); - } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies)); + } while ((stat & BUSY_STAT) && time_after(timeout, jiffies)); } - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; if (drive->present) { - ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; - if (tuneproc != NULL && drive->autotune == 1) - tuneproc(drive, 255); /* auto-tune PIO mode */ + if (hwif->tuneproc != NULL && drive->autotune == 1) + /* auto-tune PIO mode */ + hwif->tuneproc(drive, 255); } } } @@ -590,7 +608,8 @@ if (m && m->hwgroup && m->hwgroup != new->hwgroup) { if (!new->hwgroup) return; - printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name); + printk("%s: potential irq problem with %s and %s\n", + hwif->name, new->name, m->name); } if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */ *match = new; @@ -614,6 +633,7 @@ } } +#undef __IRQ_HELL_SPIN /* * This routine sets up the irq for an ide interface, and creates a new * hwgroup for the irq/hwif if none was previously assigned. @@ -639,8 +659,11 @@ new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL); - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ +#ifndef __IRQ_HELL_SPIN + save_and_cli(flags); +#else + spin_lock_irqsave(&io_request_lock, flags); +#endif hwif->hwgroup = NULL; #if MAX_HWIFS > 1 @@ -677,7 +700,11 @@ } else { hwgroup = new_hwgroup; if (!hwgroup) { - restore_flags(flags); /* all CPUs */ +#ifndef __IRQ_HELL_SPIN + restore_flags(flags); +#else + spin_unlock_irqrestore(&io_request_lock, flags); +#endif return 1; } memset(hwgroup, 0, sizeof(ide_hwgroup_t)); @@ -707,7 +734,11 @@ if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) { if (!match) kfree(hwgroup); - restore_flags(flags); /* all CPUs */ +#ifndef __IRQ_HELL_SPIN + restore_flags(flags); +#else + spin_unlock_irqrestore(&io_request_lock, flags); +#endif return 1; } } @@ -735,7 +766,12 @@ printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name); #endif } - restore_flags(flags); /* all CPUs; safe now that hwif->hwgroup is set up */ +#ifndef __IRQ_HELL_SPIN + restore_flags(flags); +#else + spin_unlock_irqrestore(&io_request_lock, flags); +#endif + /* all CPUs; safe now that hwif->hwgroup is set up */ #if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__) printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name, @@ -785,7 +821,8 @@ gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); if (!gd) goto err_kmalloc_gd; - memset (gd, 0, sizeof(struct gendisk)); + memset(gd, 0, sizeof(struct gendisk)); + gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); if (!gd->sizes) goto err_kmalloc_gd_sizes; @@ -893,7 +930,8 @@ } #ifdef CONFIG_BLK_DEV_HD if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) { - printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name); + printk("%s: CANNOT SHARE IRQ WITH OLD " + "HARDDISK DRIVER (hd.c)\n", hwif->name); return (hwif->present = 0); } #endif /* CONFIG_BLK_DEV_HD */ @@ -901,7 +939,8 @@ hwif->present = 0; /* we set it back to 1 if all is ok below */ if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) { - printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major); + printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", + hwif->name, hwif->major); return (hwif->present = 0); } @@ -912,7 +951,8 @@ * this port and try that. */ if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { - printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i); + printk("%s: Disabled unable to get IRQ %d.\n", + hwif->name, i); (void) unregister_blkdev (hwif->major, hwif->name); return (hwif->present = 0); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-proc.c linux.20pre2-ac1/drivers/ide/ide-proc.c --- linux.20pre2/drivers/ide/ide-proc.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-proc.c 2002-08-06 15:42:11.000000000 +0100 @@ -160,6 +160,8 @@ static struct proc_dir_entry * proc_ide_root = NULL; +#undef __PROC_HELL + static int proc_ide_write_config (struct file *file, const char *buffer, unsigned long count, void *data) { @@ -181,7 +183,11 @@ * Do one full pass to verify all parameters, * then do another to actually write the regs. */ +#ifndef __PROC_HELL save_flags(flags); /* all CPUs */ +#else + spin_lock_irqsave(&io_request_lock, flags); +#endif do { const char *p; if (for_real) { @@ -190,15 +196,32 @@ ide_hwgroup_t *mategroup = NULL; if (hwif->mate && hwif->mate->hwgroup) mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup); +#ifndef __PROC_HELL cli(); /* all CPUs; ensure all writes are done together */ - while (mygroup->busy || (mategroup && mategroup->busy)) { +#else + spin_lock_irqsave(&io_request_lock, flags); +#endif + while (mygroup->busy || + (mategroup && mategroup->busy)) { +#ifndef __PROC_HELL sti(); /* all CPUs */ - if (0 < (signed long)(jiffies - timeout)) { +#else + spin_unlock_irqrestore(&io_request_lock, flags); +#endif + if (time_after(jiffies, timeout)) { printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name); +#ifndef __PROC_HELL restore_flags(flags); /* all CPUs */ +#else + spin_unlock_irqrestore(&io_request_lock, flags); +#endif return -EBUSY; } +#ifndef __PROC_HELL cli(); /* all CPUs */ +#else + spin_lock_irqsave(&io_request_lock, flags); +#endif } } p = buffer; @@ -281,7 +304,11 @@ break; } if (rc) { +#ifndef __PROC_HELL restore_flags(flags); /* all CPUs */ +#else + spin_unlock_irqrestore(&io_request_lock, flags); +#endif printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n", msg, dev->bus->number, dev->devfn, reg, val); printk("proc_ide_write_config: error %d\n", rc); @@ -311,9 +338,9 @@ * */ switch (digits) { - case 2: outb(val, reg); + case 2: OUT_BYTE(val, reg); break; - case 4: outw(val, reg); + case 4: OUT_WORD(val, reg); break; case 8: outl(val, reg); break; @@ -323,10 +350,18 @@ } } } while (!for_real++); +#ifndef __PROC_HELL restore_flags(flags); /* all CPUs */ +#else + spin_unlock_irqrestore(&io_request_lock, flags); +#endif return count; parse_error: +#ifndef __PROC_HELL restore_flags(flags); /* all CPUs */ +#else + spin_unlock_irqrestore(&io_request_lock, flags); +#endif printk("parse error\n"); return xx_xx_parse_error(start, startn, msg); } @@ -446,26 +481,13 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_get_identify(ide_drive_t *drive, byte *buf) -{ - struct hd_drive_task_hdr taskfile; - struct hd_drive_hob_hdr hobfile; - memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); - memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr)); - - taskfile.sector_count = 0x01; - taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ; - - return ide_wait_taskfile(drive, &taskfile, &hobfile, buf); -} - 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; int len = 0, i = 0; - if (drive && !proc_ide_get_identify(drive, page)) { + if (drive && !taskfile_lib_get_identify(drive, page)) { unsigned short *val = (unsigned short *) page; char *out = ((char *)val) + (SECTOR_WORDS * 4); page = out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-tape.c linux.20pre2-ac1/drivers/ide/ide-tape.c --- linux.20pre2/drivers/ide/ide-tape.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-tape.c 2002-08-06 15:42:11.000000000 +0100 @@ -1835,10 +1835,9 @@ * idetape_end_request is used to finish servicing a request, and to * insert a pending pipeline request into the main device queue. */ -static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup) +static int idetape_end_request (ide_drive_t *drive, int uptodate) { - ide_drive_t *drive = hwgroup->drive; - struct request *rq = hwgroup->rq; + struct request *rq = HWGROUP(drive)->rq; idetape_tape_t *tape = drive->driver_data; unsigned long flags; int error; @@ -1932,6 +1931,7 @@ if (tape->active_data_request == NULL) clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); spin_unlock_irqrestore(&tape->spinlock, flags); + return 0; } static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive) @@ -1944,10 +1944,10 @@ #endif /* IDETAPE_DEBUG_LOG */ if (!tape->pc->error) { idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer); - idetape_end_request (1, HWGROUP (drive)); + idetape_end_request(drive, 1); } else { printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n"); - idetape_end_request (0, HWGROUP (drive)); + idetape_end_request(drive, 0); } return ide_stopped; } @@ -2050,10 +2050,11 @@ #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 4) - printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n"); + printk(KERN_INFO "ide-tape: Reached idetape_pc_intr " + "interrupt handler\n"); #endif /* IDETAPE_DEBUG_LOG */ - status.all = GET_STAT(); /* Clear the interrupt */ + status.all = GET_STAT(); /* Clear the interrupt */ #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { @@ -2090,11 +2091,14 @@ #endif /* IDETAPE_DEBUG_LOG */ clear_bit (PC_DMA_IN_PROGRESS, &pc->flags); - ide__sti(); /* local CPU only */ + local_irq_enable(); #if SIMULATE_ERRORS - if ((pc->c[0] == IDETAPE_WRITE_CMD || pc->c[0] == IDETAPE_READ_CMD) && (++error_sim_count % 100) == 0) { - printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name); + if ((pc->c[0] == IDETAPE_WRITE_CMD || + pc->c[0] == IDETAPE_READ_CMD) && + (++error_sim_count % 100) == 0) { + printk(KERN_INFO "ide-tape: %s: simulating error\n", + tape->name); status.b.check = 1; } #endif @@ -2103,10 +2107,10 @@ if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 1) - printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name); + printk(KERN_INFO "ide-tape: %s: I/O error, ",tape->name); #endif /* IDETAPE_DEBUG_LOG */ if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { - printk (KERN_ERR "ide-tape: I/O error in request sense command\n"); + printk(KERN_ERR "ide-tape: I/O error in request sense command\n"); return ide_do_reset (drive); } #if IDETAPE_DEBUG_LOG @@ -2116,31 +2120,34 @@ return idetape_retry_pc (drive); /* Retry operation */ } pc->error = 0; - if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) { /* Media access command */ + if (!tape->onstream && + test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) { + /* Media access command */ tape->dsc_polling_start = jiffies; tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST; tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT; - idetape_postpone_request (drive); /* Allow ide.c to handle other requests */ + idetape_postpone_request(drive); /* Allow ide.c to handle other requests */ return ide_stopped; } if (tape->failed_pc == pc) tape->failed_pc = NULL; - return pc->callback(drive); /* Command finished - Call the callback function */ + return pc->callback(drive); /* Command finished - Call the callback function */ } #ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) { - printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n"); - printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); + printk(KERN_ERR "ide-tape: The tape wants to issue more " + "interrupts in DMA mode\n"); + printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); (void) HWIF(drive)->dmaproc(ide_dma_off, drive); return ide_do_reset (drive); } #endif /* CONFIG_BLK_DEV_IDEDMA */ - bcount.b.high = IN_BYTE (IDE_BCOUNTH_REG); /* Get the number of bytes to transfer */ - bcount.b.low = IN_BYTE (IDE_BCOUNTL_REG); /* on this interrupt */ - ireason.all = IN_BYTE (IDE_IREASON_REG); + bcount.b.high = IN_BYTE(IDE_BCOUNTH_REG); /* Get the number of bytes to transfer */ + bcount.b.low = IN_BYTE(IDE_BCOUNTL_REG); /* on this interrupt */ + ireason.all = IN_BYTE(IDE_IREASON_REG); if (ireason.b.cod) { - printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n"); + printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n"); return ide_do_reset (drive); } if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ @@ -2154,6 +2161,8 @@ if (temp > pc->buffer_size) { printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); idetape_discard_data (drive, bcount.all); + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; } @@ -2180,6 +2189,8 @@ if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all); #endif + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* And set the interrupt handler again */ return ide_started; } @@ -2234,28 +2245,33 @@ int retries = 100; ide_startstop_t startstop; - if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { - printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); + if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { + printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); return startstop; } - ireason.all = IN_BYTE (IDE_IREASON_REG); + ireason.all = IN_BYTE(IDE_IREASON_REG); while (retries-- && (!ireason.b.cod || ireason.b.io)) { - printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n"); + printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing " + "a packet command, retrying\n"); udelay(100); ireason.all = IN_BYTE(IDE_IREASON_REG); if (retries == 0) { - printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n"); + printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while " + "issuing a packet command, ignoring\n"); ireason.b.cod = 1; ireason.b.io = 0; } } if (!ireason.b.cod || ireason.b.io) { - printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n"); + printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing " + "a packet command\n"); return ide_do_reset (drive); } tape->cmd_start_time = jiffies; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */ - atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ + atapi_output_bytes(drive,pc->c,12); /* Send the actual packet */ return ide_started; } @@ -2266,16 +2282,19 @@ int dma_ok = 0; #if IDETAPE_DEBUG_BUGS - if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { - printk (KERN_ERR "ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n"); + if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && + pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { + printk(KERN_ERR "ide-tape: possible ide-tape.c bug - " + "Two request sense in serial were issued\n"); } #endif /* IDETAPE_DEBUG_BUGS */ if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD) tape->failed_pc = pc; - tape->pc = pc; /* Set the current packet command */ + tape->pc = pc; /* Set the current packet command */ - if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) { + if (pc->retries > IDETAPE_MAX_PC_RETRIES || + test_bit(PC_ABORT, &pc->flags)) { /* * We will "abort" retrying a packet command in case * a legitimate error code was received (crossing a @@ -2283,14 +2302,19 @@ * example). */ if (!test_bit (PC_ABORT, &pc->flags)) { - if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 && - tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) { - printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n", - tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq); + if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && + tape->sense_key == 2 && tape->asc == 4 && + (tape->ascq == 1 || tape->ascq == 8))) { + printk(KERN_ERR "ide-tape: %s: I/O error, " + "pc = %2x, key = %2x, " + "asc = %2x, ascq = %2x\n", + tape->name, pc->c[0], + tape->sense_key, tape->asc, + tape->ascq); if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11) /* AJN-1: 11 should be 0x11 */ printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name); } - pc->error = IDETAPE_ERROR_GENERAL; /* Giving up */ + pc->error = IDETAPE_ERROR_GENERAL; /* Giving up */ } tape->failed_pc = NULL; return pc->callback(drive); @@ -2301,13 +2325,14 @@ #endif /* IDETAPE_DEBUG_LOG */ pc->retries++; - pc->actually_transferred = 0; /* We haven't transferred any data yet */ + pc->actually_transferred = 0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; - bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ + bcount.all=pc->request_transfer; /* Request to transfer the entire buffer at once */ #ifdef CONFIG_BLK_DEV_IDEDMA - if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) { - printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n"); + if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { + printk(KERN_WARNING "ide-tape: DMA disabled, " + "reverting to PIO\n"); (void) HWIF(drive)->dmaproc(ide_dma_off, drive); } if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) @@ -2315,18 +2340,20 @@ #endif /* CONFIG_BLK_DEV_IDEDMA */ if (IDE_CONTROL_REG) - OUT_BYTE (drive->ctl, IDE_CONTROL_REG); - OUT_BYTE (dma_ok ? 1 : 0, IDE_FEATURE_REG); /* Use PIO/DMA */ - OUT_BYTE (bcount.b.high, IDE_BCOUNTH_REG); - OUT_BYTE (bcount.b.low, IDE_BCOUNTL_REG); - OUT_BYTE (drive->select.all, IDE_SELECT_REG); + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); + OUT_BYTE(dma_ok ? 1 : 0, IDE_FEATURE_REG); /* Use PIO/DMA */ + OUT_BYTE(bcount.b.high, IDE_BCOUNTH_REG); + OUT_BYTE(bcount.b.low, IDE_BCOUNTL_REG); + OUT_BYTE(drive->select.all, IDE_SELECT_REG); #ifdef CONFIG_BLK_DEV_IDEDMA - if (dma_ok) { /* Begin DMA, if necessary */ + if (dma_ok) { /* Begin DMA, if necessary */ set_bit (PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL); OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); return ide_started; @@ -2348,7 +2375,7 @@ printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n"); #endif /* IDETAPE_DEBUG_LOG */ - idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive)); + idetape_end_request(drive, tape->pc->error ? 0 : 1); return ide_stopped; } @@ -2360,10 +2387,10 @@ idetape_init_pc (pc); pc->c[0] = IDETAPE_MODE_SENSE_CMD; if (page_code != IDETAPE_BLOCK_DESCRIPTOR) - pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors */ + pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors */ pc->c[2] = page_code; - pc->c[3] = 255; /* Don't limit the returned information */ - pc->c[4] = 255; /* (We will just discard data in that case) */ + pc->c[3] = 255; /* Don't limit the returned information */ + pc->c[4] = 255; /* (We will just discard data in that case) */ if (page_code == IDETAPE_BLOCK_DESCRIPTOR) pc->request_transfer = 12; else if (page_code == IDETAPE_CAPABILITIES_PAGE) @@ -2391,13 +2418,15 @@ } tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ; #if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, + tape->tape_head, tape->minor); #endif #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames); + printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", + tape->cur_frames, tape->max_frames); #endif - idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive)); + idetape_end_request(drive, tape->pc->error ? 0 : 1); return ide_stopped; } @@ -2471,9 +2500,9 @@ printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n"); status.all = GET_STAT(); if (status.b.dsc) { - if (status.b.check) { /* Error detected */ + if (status.b.check) { /* Error detected */ printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name); - return idetape_retry_pc (drive); /* Retry operation */ + return idetape_retry_pc (drive); /* Retry operation */ } pc->error = 0; if (tape->failed_pc == pc) @@ -2517,9 +2546,9 @@ rq->current_nr_sectors -= blocks; if (!tape->pc->error) - idetape_end_request (1, HWGROUP (drive)); + idetape_end_request(drive, 1); else - idetape_end_request (tape->pc->error, HWGROUP (drive)); + idetape_end_request(drive, tape->pc->error); return ide_stopped; } @@ -2607,6 +2636,38 @@ } /* + * This is our end_request replacement function. + */ +static int idetape_do_end_request (ide_drive_t *drive, int uptodate) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&io_request_lock, flags); + rq = HWGROUP(drive)->rq; + + /* + * 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->dmaproc(ide_dma_on, drive); + } + + if (!end_that_request_first(rq, uptodate, drive->name)) { + add_blkdev_randomness(MAJOR(rq->rq_dev)); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&io_request_lock, flags); + return ret; +} + +/* * idetape_do_request is our request handling function. */ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) @@ -2618,31 +2679,38 @@ #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 5) - printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); + printk (KERN_INFO "ide-tape: rq_status: %d, " + "rq_dev: %u, cmd: %d, errors: %d\n", rq->rq_status, + (unsigned int) rq->rq_dev, rq->cmd, rq->errors); if (tape->debug_level >= 2) - printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); + printk (KERN_INFO "ide-tape: sector: %ld, " + "nr_sectors: %ld, current_nr_sectors: %ld\n", + rq->sector, rq->nr_sectors, rq->current_nr_sectors); #endif /* IDETAPE_DEBUG_LOG */ if (!IDETAPE_RQ_CMD (rq->cmd)) { /* * We do not support buffer cache originated requests. */ - printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd); - ide_end_request (0, HWGROUP (drive)); /* Let the common code handle it */ + printk (KERN_NOTICE "ide-tape: %s: Unsupported command in " + "request queue (%d)\n", drive->name, rq->cmd); + idetape_do_end_request(drive, 0); return ide_stopped; } /* * Retry a failed packet command */ - if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { + if (tape->failed_pc != NULL && + tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { return idetape_issue_packet_command (drive, tape->failed_pc); } #if IDETAPE_DEBUG_BUGS if (postponed_rq != NULL) if (rq != postponed_rq) { - printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n"); - idetape_end_request (0, HWGROUP (drive)); + printk (KERN_ERR "ide-tape: ide-tape.c bug - " + "Two DSC requests were queued\n"); + idetape_end_request(drive, 0); return ide_stopped; } #endif /* IDETAPE_DEBUG_BUGS */ @@ -2674,7 +2742,8 @@ */ if (tape->tape_still_time > 100 && tape->tape_still_time < 200) tape->measure_insert_time = 1; - if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) { + if (tape->req_buffer_fill && + (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) { tape->req_buffer_fill = 0; tape->writes_since_buffer_fill = 0; tape->reads_since_buffer_fill = 0; @@ -2699,7 +2768,8 @@ tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) { #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n", + printk(KERN_INFO "ide-tape: postponing request, " + "cmd %d, cur %d, max %d\n", rq->cmd, tape->cur_frames, tape->max_frames); #endif if (tape->postpone_cnt++ < 500) { @@ -2708,7 +2778,8 @@ } #if ONSTREAM_DEBUG else if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt); + printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", + tape->name, tape->postpone_cnt); #endif } if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) { @@ -2770,7 +2841,7 @@ break; case IDETAPE_ABORTED_WRITE_RQ: rq->cmd = IDETAPE_WRITE_RQ; - idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive)); + idetape_end_request(drive, IDETAPE_ERROR_EOD); return ide_stopped; case IDETAPE_ABORTED_READ_RQ: #if IDETAPE_DEBUG_LOG @@ -2778,7 +2849,7 @@ printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name); #endif rq->cmd = IDETAPE_READ_RQ; - idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive)); + idetape_end_request(drive, IDETAPE_ERROR_EOD); return ide_stopped; case IDETAPE_PC_RQ1: pc = (idetape_pc_t *) rq->buffer; @@ -2789,7 +2860,7 @@ return ide_stopped; default: printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n"); - idetape_end_request (0, HWGROUP (drive)); + idetape_end_request(drive, 0); return ide_stopped; } return idetape_issue_packet_command (drive, pc); @@ -3112,7 +3183,7 @@ if (result->bpu) { printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n"); clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags); - idetape_end_request (0, HWGROUP (drive)); + idetape_end_request(drive, 0); } else { #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 2) @@ -3123,10 +3194,10 @@ tape->last_frame_position = ntohl (result->last_block); tape->blocks_in_buffer = result->blocks_in_buffer[2]; set_bit (IDETAPE_ADDRESS_VALID, &tape->flags); - idetape_end_request (1, HWGROUP (drive)); + idetape_end_request(drive, 1); } } else { - idetape_end_request (0, HWGROUP (drive)); + idetape_end_request(drive, 0); } return ide_stopped; } @@ -6085,14 +6156,14 @@ int minor = tape->minor; unsigned long flags; - save_flags (flags); /* all CPUs (overkill?) */ - cli(); /* all CPUs (overkill?) */ - if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) { - restore_flags(flags); /* all CPUs (overkill?) */ + spin_lock_irqsave(&io_request_lock, flags); + if (test_bit (IDETAPE_BUSY, &tape->flags) || drive->usage || + tape->first_stage != NULL || tape->merge_stage_size) { + spin_unlock_irqrestore(&io_request_lock, flags); return 1; } idetape_chrdevs[minor].drive = NULL; - restore_flags (flags); /* all CPUs (overkill?) */ + spin_unlock_irqrestore(&io_request_lock, flags); DRIVER(drive)->busy = 0; (void) ide_unregister_subdriver (drive); drive->driver_data = NULL; @@ -6132,6 +6203,7 @@ #endif +int idetape_init (void); int idetape_reinit(ide_drive_t *drive); /* @@ -6142,13 +6214,21 @@ version: IDETAPE_VERSION, media: ide_tape, busy: 1, +#ifdef CONFIG_IDEDMA_ONLYDISK + supports_dma: 0, +#else supports_dma: 1, +#endif supports_dsc_overlap: 1, cleanup: idetape_cleanup, standby: NULL, + suspend: NULL, + resume: NULL, flushcache: NULL, do_request: idetape_do_request, end_request: idetape_end_request, + sense: NULL, + error: NULL, ioctl: idetape_blkdev_ioctl, open: idetape_blkdev_open, release: idetape_blkdev_release, @@ -6156,13 +6236,14 @@ revalidate: NULL, pre_reset: idetape_pre_reset, capacity: NULL, + special: NULL, proc: idetape_proc, + init: idetape_init, reinit: idetape_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, }; -int idetape_init (void); static ide_module_t idetape_module = { IDE_DRIVER_MODULE, idetape_init, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ide-taskfile.c linux.20pre2-ac1/drivers/ide/ide-taskfile.c --- linux.20pre2/drivers/ide/ide-taskfile.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ide-taskfile.c 2002-08-06 15:42:11.000000000 +0100 @@ -1,12 +1,29 @@ /* - * linux/drivers/ide/ide-taskfile.c Version 0.20 Oct 11, 2000 + * linux/drivers/ide/ide-taskfile.c Version 0.33 April 11, 2002 * - * Copyright (C) 2000 Michael Cornwell - * Copyright (C) 2000 Andre Hedrick + * Copyright (C) 2000-2002 Michael Cornwell + * Copyright (C) 2000-2002 Andre Hedrick + * Copyright (C) 2001-2002 Klaus Smolin + * IBM Storage Technology Division * - * May be copied or modified under the terms of the GNU General Public License + * The big the bad and the ugly. * - * IDE_DEBUG(__LINE__); + * Problems to be fixed because of BH interface or the lack therefore. + * + * Fill me in stupid !!! + * + * HOST: + * General refers to the Controller and Driver "pair". + * DATA HANDLER: + * Under the context of Linux it generally refers to an interrupt handler. + * However, it correctly describes the 'HOST' + * DATA BLOCK: + * The amount of data needed to be transfered as predefined in the + * setup of the device. + * STORAGE ATOMIC: + * The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as + * small as a single sector or as large as the entire command block + * request. */ #include @@ -34,20 +51,41 @@ #include #include -#ifdef CONFIG_IDE_TASKFILE_IO -# define __TASKFILE__IO -#else /* CONFIG_IDE_TASKFILE_IO */ -# undef __TASKFILE__IO -#endif /* CONFIG_IDE_TASKFILE_IO */ - #define DEBUG_TASKFILE 0 /* unset when fixed */ #if DEBUG_TASKFILE -#define DTF(x...) printk(##x) +#define DTF(x...) printk(x) #else #define DTF(x...) #endif +/* + * + */ +#define task_rq_offset(rq) \ + (((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE) + +/* + * for now, taskfile requests are special :/ + * + * However, upon the creation of the atapi version of packet_command + * data-phase ISR plus it own diagnostics and extensions for direct access + * (ioctl,read,write,rip,stream -- atapi), the kmap/kunmap for PIO will + * come localized. + */ +inline char *task_map_rq (struct request *rq, unsigned long *flags) +{ + if (rq->bh) + return ide_map_buffer(rq, flags); + return rq->buffer + task_rq_offset(rq); +} + +inline void task_unmap_rq (struct request *rq, char *buf, unsigned long *flags) +{ + if (rq->bh) + ide_unmap_buffer(buf, flags); +} + inline u32 task_read_24 (ide_drive_t *drive) { return (IN_BYTE(IDE_HCYL_REG)<<16) | @@ -73,10 +111,11 @@ * of the sector count register location, with interrupts disabled * to ensure that the reads all happen together. */ -static inline void task_vlb_sync (ide_ioreg_t port) { - (void) inb (port); - (void) inb (port); - (void) inb (port); +static inline void task_vlb_sync (ide_ioreg_t port) +{ + (void) IN_BYTE (port); + (void) IN_BYTE (port); + (void) IN_BYTE (port); } #endif /* SUPPORT_VLB_SYNC */ @@ -85,17 +124,28 @@ */ void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) { - byte io_32bit = drive->io_32bit; + byte io_32bit; + + /* + * first check if this controller has defined a special function + * for handling polled ide transfers + */ + + if (HWIF(drive)->ideproc) { + HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount); + return; + } + + io_32bit = drive->io_32bit; if (io_32bit) { #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); task_vlb_sync(IDE_NSECTOR_REG); insl(IDE_DATA_REG, buffer, wcount); - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); } else #endif /* SUPPORT_VLB_SYNC */ insl(IDE_DATA_REG, buffer, wcount); @@ -118,17 +168,23 @@ */ void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) { - byte io_32bit = drive->io_32bit; + byte io_32bit; + + if (HWIF(drive)->ideproc) { + HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount); + return; + } + + io_32bit = drive->io_32bit; if (io_32bit) { #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); task_vlb_sync(IDE_NSECTOR_REG); outsl(IDE_DATA_REG, buffer, wcount); - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); } else #endif /* SUPPORT_VLB_SYNC */ outsl(IDE_DATA_REG, buffer, wcount); @@ -146,15 +202,61 @@ } } +/* + * The following routines are mainly used by the ATAPI drivers. + * + * These routines will round up any request for an odd number of bytes, + * so if an odd bytecount is specified, be sure that there's at least one + * extra byte allocated for the buffer. + */ +void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) +{ + if (HWIF(drive)->ideproc) { + HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount); + return; + } + + ++bytecount; +#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) + if (MACH_IS_ATARI || MACH_IS_Q40) { + /* Atari has a byte-swapped IDE interface */ + insw_swapw(IDE_DATA_REG, buffer, bytecount / 2); + return; + } +#endif /* CONFIG_ATARI */ + ata_input_data (drive, buffer, bytecount / 4); + if ((bytecount & 0x03) >= 2) + insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); +} + +void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) +{ + if (HWIF(drive)->ideproc) { + HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount); + return; + } + + ++bytecount; +#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) + if (MACH_IS_ATARI || MACH_IS_Q40) { + /* Atari has a byte-swapped IDE interface */ + outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2); + return; + } +#endif /* CONFIG_ATARI */ + ata_output_data (drive, buffer, bytecount / 4); + if ((bytecount & 0x03) >= 2) + outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1); +} -static inline void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) { ata_input_data(drive, buffer, wcount); if (drive->bswap) ata_bswap_data(buffer, wcount); } -static inline void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) { if (drive->bswap) { ata_bswap_data(buffer, wcount); @@ -165,102 +267,154 @@ } } -ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) +/* + * Needed for PCI irq sharing + */ +int drive_is_ready (ide_drive_t *drive) { - task_struct_t *taskfile = (task_struct_t *) task->tfRegister; - hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; - struct hd_driveid *id = drive->id; - byte HIHI = (drive->addressing) ? 0xE0 : 0xEF; + byte stat = 0; + if (drive->waiting_for_dma) + return HWIF(drive)->dmaproc(ide_dma_test_irq, drive); +#if 0 + /* need to guarantee 400ns since last command was issued */ + udelay(1); +#endif - /* (ks/hs): Moved to start, do not use for multiple out commands */ - if (task->handler != task_mulout_intr) { - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(HWIF(drive), drive, 0); - } +#ifdef CONFIG_IDEPCI_SHARE_IRQ + /* + * We do a passive status test under shared PCI interrupts on + * cards that truly share the ATA side interrupt, but may also share + * an interrupt with another pci card/device. We make no assumptions + * about possible isa-pnp and pci-pnp issues yet. + */ + if (IDE_CONTROL_REG) + stat = GET_ALTSTAT(); + else +#endif /* CONFIG_IDEPCI_SHARE_IRQ */ + stat = GET_STAT(); /* Note: this may clear a pending IRQ!! */ - if ((id->command_set_2 & 0x0400) && - (id->cfs_enable_2 & 0x0400) && - (drive->addressing == 1)) { - OUT_BYTE(hobfile->feature, IDE_FEATURE_REG); - OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG); - OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG); - OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG); - OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG); - } + if (stat & BUSY_STAT) + return 0; /* drive busy: definitely not interrupting */ + return 1; /* drive ready: *might* be interrupting */ +} - OUT_BYTE(taskfile->feature, IDE_FEATURE_REG); - OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG); - /* refers to number of sectors to transfer */ - OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG); - /* refers to sector offset or start sector */ - OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG); - OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG); +/* + * Global for All, and taken from ide-pmac.c + */ +int wait_for_ready (ide_drive_t *drive, int timeout) +{ + byte stat = 0; - OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG); - if (task->handler != NULL) { -#if 0 - ide_set_handler (drive, task->handler, WAIT_CMD, NULL); - OUT_BYTE(taskfile->command, IDE_COMMAND_REG); - /* - * warning check for race between handler and prehandler for - * writing first block of data. however since we are well - * inside the boundaries of the seek, we should be okay. - */ - if (task->prehandler != NULL) { - return task->prehandler(drive, task->rq); + while(--timeout) { + stat = GET_STAT(); + if(!(stat & BUSY_STAT)) { + if (drive->ready_stat == 0) + break; + else if((stat & drive->ready_stat) || (stat & ERR_STAT)) + break; } -#else - ide_startstop_t startstop; - - ide_set_handler (drive, task->handler, WAIT_CMD, NULL); - OUT_BYTE(taskfile->command, IDE_COMMAND_REG); + mdelay(1); + } + if((stat & ERR_STAT) || timeout <= 0) { + if (stat & ERR_STAT) { + printk(KERN_ERR "%s: wait_for_ready, error status: %x\n", drive->name, stat); + } + return 1; + } + return 0; +} - if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing %s\n", - drive->name, - drive->mult_count ? "MULTWRITE" : "WRITE"); - return startstop; - } - /* (ks/hs): Fixed Multi Write */ - if ((taskfile->command != WIN_MULTWRITE) && - (taskfile->command != WIN_MULTWRITE_EXT)) { - struct request *rq = HWGROUP(drive)->rq; - /* For Write_sectors we need to stuff the first sector */ - taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); - rq->current_nr_sectors--; - } else { - /* Stuff first sector(s) by implicitly calling the handler */ - if (!(drive_is_ready(drive))) { - /* FIXME: Replace hard-coded 100, error handling? */ - int i; - for (i=0; i<100; i++) { - if (drive_is_ready(drive)) - break; - } +/* + * This routine busy-waits for the drive status to be not "busy". + * It then checks the status for all of the "good" bits and none + * of the "bad" bits, and if all is okay it returns 0. All other + * cases return 1 after invoking ide_error() -- caller should just return. + * + * This routine should get fixed to not hog the cpu during extra long waits.. + * That could be done by busy-waiting for the first jiffy or two, and then + * setting a timer to wake up at half second intervals thereafter, + * until timeout is achieved, before timing out. + */ +int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) +{ + byte stat; + int i; + unsigned long flags; + + /* bail early if we've exceeded max_failures */ + if (drive->max_failures && (drive->failures > drive->max_failures)) { + *startstop = ide_stopped; + return 1; + } + + udelay(1); /* spec allows drive 400ns to assert "BUSY" */ + if ((stat = GET_STAT()) & BUSY_STAT) { + local_irq_set(flags); + timeout += jiffies; + while ((stat = GET_STAT()) & BUSY_STAT) { + if (time_after(jiffies, timeout)) { + local_irq_restore(flags); + *startstop = DRIVER(drive)->error(drive, "status timeout", stat); + return 1; } - return task->handler(drive); } -#endif - } else { - /* for dma commands we down set the handler */ - if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive))); + local_irq_restore(flags); + } + /* + * Allow status to settle, then read it again. + * A few rare drives vastly violate the 400ns spec here, + * so we'll wait up to 10usec for a "good" status + * rather than expensively fail things immediately. + * This fix courtesy of Matthew Faupel & Niccolo Rigacci. + */ + for (i = 0; i < 10; i++) { + udelay(1); + if (OK_STAT((stat = GET_STAT()), good, bad)) + return 0; } + *startstop = DRIVER(drive)->error(drive, "status error", stat); + return 1; +} - return ide_started; +void debug_taskfile (ide_drive_t *drive, ide_task_t *args) +{ +#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG + printk(KERN_INFO "%s: ", drive->name); +// printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]); + printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]); + printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]); + printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]); + printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]); + printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]); + printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]); + printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]); + printk(KERN_INFO "%s: ", drive->name); +// printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]); + printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]); + printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]); + printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]); + printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]); + printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]); + printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]); + printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]); +#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ } -void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler) +ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) { + task_struct_t *taskfile = (task_struct_t *) task->tfRegister; + hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; struct hd_driveid *id = drive->id; - byte HIHI = (drive->addressing) ? 0xE0 : 0xEF; + byte HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF; - /* (ks/hs): Moved to start, do not use for multiple out commands */ - if (*handler != task_mulout_intr) { - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(HWIF(drive), drive, 0); - } +#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG + void debug_taskfile(drive, task); +#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ + + /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive), drive, 0); if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) && @@ -281,147 +435,41 @@ OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG); OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG); - if (handler != NULL) { - ide_set_handler (drive, handler, WAIT_CMD, NULL); - OUT_BYTE(taskfile->command, IDE_COMMAND_REG); - } else { - /* for dma commands we down set the handler */ - if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive))); - } -} - -#if 0 -ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) -{ - task_struct_t *taskfile = (task_struct_t *) task->tfRegister; - hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; - struct hd_driveid *id = drive->id; - - /* - * (KS) Check taskfile in/out flags. - * If set, then execute as it is defined. - * If not set, then define default settings. - * The default values are: - * write and read all taskfile registers (except data) - * write and read the hob registers (sector,nsector,lcyl,hcyl) - */ - if (task->tf_out_flags.all == 0) { - task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS; - if ((id->command_set_2 & 0x0400) && - (id->cfs_enable_2 & 0x0400) && - (drive->addressing == 1)) { - task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8); - } - } - - if (task->tf_in_flags.all == 0) { - task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; - if ((id->command_set_2 & 0x0400) && - (id->cfs_enable_2 & 0x0400) && - (drive->addressing == 1)) { - task->tf_in_flags.all != (IDE_HOB_STD_IN_FLAGS << 8); - } - } - - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(HWIF(drive), drive, 0); - - if (task->tf_out_flags.b.data) { - unsigned short data = taskfile->data + (hobfile->data << 8); - OUT_WORD (data, IDE_DATA_REG); - } - - /* (KS) send hob registers first */ - if (task->tf_out_flags.b.nsector_hob) - OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG); - if (task->tf_out_flags.b.sector_hob) - OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG); - if (task->tf_out_flags.b.lcyl_hob) - OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG); - if (task->tf_out_flags.b.hcyl_hob) - OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG); - - - /* (KS) Send now the standard registers */ - if (task->tf_out_flags.b.error_feature) - OUT_BYTE(taskfile->feature, IDE_FEATURE_REG); - /* refers to number of sectors to transfer */ - if (task->tf_out_flags.b.nsector) - OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG); - /* refers to sector offset or start sector */ - if (task->tf_out_flags.b.sector) - OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG); - if (task->tf_out_flags.b.lcyl) - OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG); - if (task->tf_out_flags.b.hcyl) - OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG); - - /* - * (KS) Do not modify the specified taskfile. We want to have a - * universal pass through, so we must execute ALL specified values. - * - * (KS) The drive head register is mandatory. - * Don't care about the out flags ! - */ - OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG); if (task->handler != NULL) { -#if 0 ide_set_handler (drive, task->handler, WAIT_CMD, NULL); OUT_BYTE(taskfile->command, IDE_COMMAND_REG); - /* - * warning check for race between handler and prehandler for - * writing first block of data. however since we are well - * inside the boundaries of the seek, we should be okay. - */ - if (task->prehandler != NULL) { + if (task->prehandler != NULL) return task->prehandler(drive, task->rq); - } + return ide_started; + } +#if 0 + switch(task->data_phase) { +#ifdef CONFIG_BLK_DEV_IDEDMA + case TASKFILE_OUT_DMAQ: + case TASKFILE_OUT_DMA: + HWIF(drive)->dmaproc(ide_dma_write, drive); + break; + case TASKFILE_IN_DMAQ: + case TASKFILE_IN_DMA: + HWIF(drive)->dmaproc(ide_dma_read, drive); + break; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + default: + if (task->handler == NULL) + return ide_stopped; + ide_set_handler (drive, task->handler, WAIT_WORSTCASE, NULL); + /* Issue the command */ + OUT_BYTE(taskfile->command, IDE_COMMAND_REG); + if (task->prehandler != NULL) + return task->prehandler(drive, HWGROUP(drive)->rq); + } #else - ide_startstop_t startstop; - - ide_set_handler (drive, task->handler, WAIT_CMD, NULL); - - /* - * (KS) The drive command register is also mandatory. - * Don't care about the out flags ! - */ - OUT_BYTE(taskfile->command, IDE_COMMAND_REG); - - if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing %s\n", - drive->name, - drive->mult_count ? "MULTWRITE" : "WRITE"); - return startstop; - } - /* (ks/hs): Fixed Multi Write */ - if ((taskfile->command != WIN_MULTWRITE) && - (taskfile->command != WIN_MULTWRITE_EXT)) { - struct request *rq = HWGROUP(drive)->rq; - /* For Write_sectors we need to stuff the first sector */ - taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); - rq->current_nr_sectors--; - } else { - /* Stuff first sector(s) by implicitly calling the handler */ - if (!(drive_is_ready(drive))) { - /* FIXME: Replace hard-coded 100, error handling? */ - int i; - for (i=0; i<100; i++) { - if (drive_is_ready(drive)) - break; - } - } - return task->handler(drive); - } + // if ((rq->cmd == WRITE) && (drive->using_dma)) + /* for dma commands we down set the handler */ + if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive))); #endif - } else { - /* for dma commands we down set the handler */ - if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive))); - } - return ide_started; } -#endif #if 0 /* @@ -432,8 +480,7 @@ unsigned long flags; byte err = 0; - __save_flags (flags); /* local CPU only */ - ide__sti(); /* local CPU only */ + local_irq_set(flags); printk("%s: %s: status=0x%02x", drive->name, msg, stat); #if FANCY_STATUS_DUMPS printk(" { "); @@ -492,15 +539,16 @@ } } if (HWGROUP(drive)->rq) - printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector); + printk(", sector=%lu", (__u64) HWGROUP(drive)->rq->sector); } } #endif /* FANCY_STATUS_DUMPS */ printk("\n"); } - __restore_flags (flags); /* local CPU only */ + local_irq_restore(flags); return err; } +#endif /* * Clean up after success/failure of an explicit taskfile operation. @@ -519,8 +567,14 @@ command = args->tfRegister[IDE_COMMAND_OFFSET]; - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (rq->errors == 0) + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args->tf_in_flags.b.data) { + unsigned short data = IN_WORD(IDE_DATA_REG); + args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF; + args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF; + } args->tfRegister[IDE_ERROR_OFFSET] = err; args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG); args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG); @@ -539,8 +593,13 @@ args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(IDE_HCYL_REG); } +#if 0 /* taskfile_settings_update(drive, args, command); */ + if (args->posthandler != NULL) + args->posthandler(drive, args); +#endif + spin_lock_irqsave(&io_request_lock, flags); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; @@ -548,6 +607,7 @@ spin_unlock_irqrestore(&io_request_lock, flags); } +#if 0 /* * try_to_flush_leftover_data() is invoked in response to a drive * unexpectedly having its DRQ_STAT bit set. As an alternative to @@ -608,10 +668,7 @@ OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); /* force an abort */ if (rq->errors >= ERROR_MAX) { - if (drive->driver != NULL) - DRIVER(drive)->end_request(0, HWGROUP(drive)); - else - ide_end_request(0, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 0); } else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { ++rq->errors; @@ -657,8 +714,10 @@ return ide_stopped; if (stat & (ERR_STAT|DRQ_STAT)) - return ide_error(drive, "set_geometry_intr", stat); + return DRIVER(drive)->error(drive, "set_geometry_intr", stat); + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL); return ide_started; } @@ -671,7 +730,7 @@ byte stat = GET_STAT(); if (!OK_STAT(stat,READY_STAT,BAD_STAT)) - return ide_error(drive, "recal_intr", stat); + return DRIVER(drive)->error(drive, "recal_intr", stat); return ide_stopped; } @@ -683,11 +742,13 @@ ide_task_t *args = HWGROUP(drive)->rq->special; byte stat = GET_STAT(); - ide__sti(); /* local CPU only */ - - if (!OK_STAT(stat, READY_STAT, BAD_STAT)) - return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ - + local_irq_enable(); + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { + DTF("%s: command opcode 0x%02x\n", drive->name, + args->tfRegister[IDE_COMMAND_OFFSET]); + return DRIVER(drive)->error(drive, "task_no_data_intr", stat); + /* calls ide_end_drive_cmd */ + } if (args) ide_end_drive_cmd (drive, stat, GET_ERR()); @@ -695,42 +756,85 @@ } /* - * Handler for command with PIO data-in phase + * Handler for command with PIO data-in phase, READ + */ +/* + * FIXME before 2.4 enable ... + * DATA integrity issue upon error. */ ide_startstop_t task_in_intr (ide_drive_t *drive) { byte stat = GET_STAT(); - byte io_32bit = drive->io_32bit; struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; + unsigned long flags; if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { - return ide_error(drive, "task_in_intr", stat); +#if 0 + DTF("%s: attempting to recover last " \ + "sector counter status=0x%02x\n", + drive->name, stat); + /* + * Expect a BUG BOMB if we attempt to rewind the + * offset in the BH aka PAGE in the current BLOCK + * segment. This is different than the HOST segment. + */ +#endif + if (!rq->bh) + rq->current_nr_sectors++; + return DRIVER(drive)->error(drive, "task_in_intr", stat); } if (!(stat & BUSY_STAT)) { DTF("task_in_intr to Soon wait for next interrupt\n"); - ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); + if (HWGROUP(drive)->handler == NULL) + ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); return ide_started; } } - DTF("stat: %02x\n", stat); - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); - DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); +#if 0 - drive->io_32bit = 0; - taskfile_input_data(drive, pBuf, SECTOR_WORDS); - drive->io_32bit = io_32bit; + /* + * Holding point for a brain dump of a thought :-/ + */ - if (--rq->current_nr_sectors <= 0) { - /* (hs): swapped next 2 lines */ - DTF("Request Ended stat: %02x\n", GET_STAT()); - ide_end_request(1, HWGROUP(drive)); - } else { + if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) { + DTF("%s: READ attempting to recover last " \ + "sector counter status=0x%02x\n", + drive->name, stat); + rq->current_nr_sectors++; + return DRIVER(drive)->error(drive, "task_in_intr", stat); + } + if (!rq->current_nr_sectors) + if (!DRIVER(drive)->end_request(drive, 1)) + return ide_stopped; + + if (--rq->current_nr_sectors <= 0) + if (!DRIVER(drive)->end_request(drive, 1)) + return ide_stopped; +#endif + + pBuf = task_map_rq(rq, &flags); + DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n", + pBuf, (int) rq->current_nr_sectors, stat); + taskfile_input_data(drive, pBuf, SECTOR_WORDS); + task_unmap_rq(rq, pBuf, &flags); + /* + * FIXME :: We really can not legally get a new page/bh + * regardless, if this is the end of our segment. + * BH walking or segment can only be updated after we have a good + * GET_STAT(); return. + */ + if (--rq->current_nr_sectors <= 0) + if (!DRIVER(drive)->end_request(drive, 1)) + return ide_stopped; + /* + * ERM, it is techincally legal to leave/exit here but it makes + * a mess of the code ... + */ + if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); - return ide_started; - } - return ide_stopped; + return ide_started; } #undef ALTSTAT_SCREW_UP @@ -765,6 +869,7 @@ */ byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg) { + /* (ks/hs): FIXME: Error handling, time-out? */ while (stat & BUSY_STAT) stat = GET_ALTSTAT(); @@ -778,30 +883,37 @@ */ ide_startstop_t task_mulin_intr (ide_drive_t *drive) { - unsigned int msect, nsect; - #ifdef ALTSTAT_SCREW_UP byte stat = altstat_multi_busy(drive, GET_ALTSTAT(), "read"); #else byte stat = GET_STAT(); #endif /* ALTSTAT_SCREW_UP */ - - byte io_32bit = drive->io_32bit; struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; + unsigned int msect = drive->mult_count; + unsigned int nsect; + unsigned long flags; if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { - return ide_error(drive, "task_mulin_intr", stat); + if (!rq->bh) { + rq->current_nr_sectors += drive->mult_count; + /* + * NOTE: could rewind beyond beginning :-/ + */ + } else { + printk("%s: MULTI-READ assume all data " \ + "transfered is bad status=0x%02x\n", + drive->name, stat); + } + return DRIVER(drive)->error(drive, "task_mulin_intr", stat); } /* no data yet, so wait for another interrupt */ - ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); + if (HWGROUP(drive)->handler == NULL) + ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); return ide_started; } - /* (ks/hs): Fixed Multi-Sector transfer */ - msect = drive->mult_count; - #ifdef ALTSTAT_SCREW_UP /* * Screw the request we do not support bad data-phase setups! @@ -814,157 +926,237 @@ */ nsect = 1; while (rq->current_nr_sectors) { - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); - DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors); - drive->io_32bit = 0; + pBuf = task_map_rq(rq, &flags); + DTF("Multiread: %p, nsect: %d, " \ + "rq->current_nr_sectors: %ld\n", + pBuf, nsect, rq->current_nr_sectors); +// rq->current_nr_sectors -= nsect; taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); - drive->io_32bit = io_32bit; + task_unmap_rq(rq, pBuf, &flags); rq->errors = 0; rq->current_nr_sectors -= nsect; stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read"); } - ide_end_request(1, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 1); return ide_stopped; } #endif /* ALTSTAT_SCREW_UP */ - nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); - - DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n", - pBuf, nsect, rq->current_nr_sectors); - drive->io_32bit = 0; - taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); - drive->io_32bit = io_32bit; - rq->errors = 0; - rq->current_nr_sectors -= nsect; - if (rq->current_nr_sectors != 0) { + do { + nsect = rq->current_nr_sectors; + if (nsect > msect) + nsect = msect; + pBuf = task_map_rq(rq, &flags); + DTF("Multiread: %p, nsect: %d, msect: %d, " \ + " rq->current_nr_sectors: %d\n", + pBuf, nsect, msect, rq->current_nr_sectors); +// rq->current_nr_sectors -= nsect; +// msect -= nsect; + taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); + task_unmap_rq(rq, pBuf, &flags); + rq->errors = 0; + rq->current_nr_sectors -= nsect; + msect -= nsect; + /* + * FIXME :: We really can not legally get a new page/bh + * regardless, if this is the end of our segment. + * BH walking or segment can only be updated after we have a + * good GET_STAT(); return. + */ + if (!rq->current_nr_sectors) { + if (!DRIVER(drive)->end_request(drive, 1)) + return ide_stopped; + } + } while (msect); + if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); - return ide_started; - } - ide_end_request(1, HWGROUP(drive)); - return ide_stopped; + return ide_started; } +/* + * VERIFY ME before 2.4 ... unexpected race is possible based on details + * RMK with 74LS245/373/374 TTL buffer logic because of passthrough. + */ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) { - ide_task_t *args = rq->special; + char *pBuf = NULL; + unsigned long flags; ide_startstop_t startstop; - if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE"); + if (ide_wait_stat(&startstop, drive, DATA_READY, + drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing %s\n", + drive->name, + drive->addressing ? "WRITE_EXT" : "WRITE"); return startstop; } - - /* (ks/hs): Fixed Multi Write */ - if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) && - (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) { - /* For Write_sectors we need to stuff the first sector */ - taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); - rq->current_nr_sectors--; - return ide_started; - } else { - /* - * (ks/hs): Stuff the first sector(s) - * by implicitly calling the handler - */ - if (!(drive_is_ready(drive))) { - int i; - /* - * (ks/hs): FIXME: Replace hard-coded - * 100, error handling? - */ - for (i=0; i<100; i++) { - if (drive_is_ready(drive)) - break; - } - } - return args->handler(drive); - } + /* For Write_sectors we need to stuff the first sector */ + pBuf = task_map_rq(rq, &flags); +// rq->current_nr_sectors--; + taskfile_output_data(drive, pBuf, SECTOR_WORDS); + rq->current_nr_sectors--; + /* + * WARNING :: Interrupt could happen instantly :-/ + */ + task_unmap_rq(rq, pBuf, &flags); return ide_started; } /* - * Handler for command with PIO data-out phase + * Handler for command with PIO data-out phase WRITE + * + * WOOHOO this is a CORRECT STATE DIAGRAM NOW, */ ide_startstop_t task_out_intr (ide_drive_t *drive) { byte stat = GET_STAT(); - byte io_32bit = drive->io_32bit; struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; - - if (!rq->current_nr_sectors) { - ide_end_request(1, HWGROUP(drive)); - return ide_stopped; - } + unsigned long flags; if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) { - return ide_error(drive, "task_out_intr", stat); + DTF("%s: WRITE attempting to recover last " \ + "sector counter status=0x%02x\n", + drive->name, stat); + rq->current_nr_sectors++; + return DRIVER(drive)->error(drive, "task_out_intr", stat); } + /* + * Safe to update request for partial completions. + * We have a good STATUS CHECK!!! + */ + if (!rq->current_nr_sectors) + if (!DRIVER(drive)->end_request(drive, 1)) + return ide_stopped; if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { rq = HWGROUP(drive)->rq; - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); - DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); - drive->io_32bit = 0; + pBuf = task_map_rq(rq, &flags); + DTF("write: %p, rq->current_nr_sectors: %d\n", + pBuf, (int) rq->current_nr_sectors); +// rq->current_nr_sectors--; taskfile_output_data(drive, pBuf, SECTOR_WORDS); - drive->io_32bit = io_32bit; + task_unmap_rq(rq, pBuf, &flags); rq->errors = 0; rq->current_nr_sectors--; } - - if (rq->current_nr_sectors <= 0) { - ide_end_request(1, HWGROUP(drive)); - } else { + if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL); - return ide_started; + return ide_started; +} + +ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) +{ + ide_task_t *args = rq->special; + ide_startstop_t startstop; + +#if 0 + /* + * assign private copy for multi-write + */ + memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request)); +#endif + + if (ide_wait_stat(&startstop, drive, DATA_READY, + drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing %s\n", + drive->name, + drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE"); + return startstop; } - return ide_stopped; +#if 0 + if (wait_for_ready(drive, 100)) + IDE_DEBUG(__LINE__); //BUG(); +#else + if (!(drive_is_ready(drive))) { + int i; + for (i=0; i<100; i++) { + if (drive_is_ready(drive)) + break; + } + } +#endif + /* + * WARNING :: if the drive as not acked good status we may not + * move the DATA-TRANSFER T-Bar as BSY != 0. + */ + return args->handler(drive); } /* + * FIXME before enabling in 2.4 ... DATA integrity issue upon error. + */ +/* * Handler for command write multiple * Called directly from execute_drive_cmd for the first bunch of sectors, * afterwards only by the ISR */ ide_startstop_t task_mulout_intr (ide_drive_t *drive) { - unsigned int msect, nsect; - #ifdef ALTSTAT_SCREW_UP byte stat = altstat_multi_busy(drive, GET_ALTSTAT(), "write"); #else byte stat = GET_STAT(); #endif /* ALTSTAT_SCREW_UP */ - byte io_32bit = drive->io_32bit; - struct request *rq = HWGROUP(drive)->rq; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - char *pBuf = NULL; + struct request *rq = HWGROUP(drive)->rq; + char *pBuf = NULL; + ide_startstop_t startstop = ide_stopped; + unsigned int msect = drive->mult_count; + unsigned int nsect; + unsigned long flags; /* * (ks/hs): Handle last IRQ on multi-sector transfer, - * occurs after all data was sent + * occurs after all data was sent in this chunk */ if (rq->current_nr_sectors == 0) { - if (stat & (ERR_STAT|DRQ_STAT)) - return ide_error(drive, "task_mulout_intr", stat); - ide_end_request(1, HWGROUP(drive)); - return ide_stopped; + if (stat & (ERR_STAT|DRQ_STAT)) { + if (!rq->bh) { + rq->current_nr_sectors += drive->mult_count; + /* + * NOTE: could rewind beyond beginning :-/ + */ + } else { + printk("%s: MULTI-WRITE assume all data " \ + "transfered is bad status=0x%02x\n", + drive->name, stat); + } + return DRIVER(drive)->error(drive, "task_mulout_intr", stat); + } + if (!rq->bh) + DRIVER(drive)->end_request(drive, 1); + return startstop; } - + /* + * DON'T be lazy code the above and below togather !!! + */ if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { - return ide_error(drive, "task_mulout_intr", stat); + if (!rq->bh) { + rq->current_nr_sectors += drive->mult_count; + /* + * NOTE: could rewind beyond beginning :-/ + */ + } else { + printk("%s: MULTI-WRITE assume all data " \ + "transfered is bad status=0x%02x\n", + drive->name, stat); + } + return DRIVER(drive)->error(drive, "task_mulout_intr", stat); } /* no data yet, so wait for another interrupt */ - if (hwgroup->handler == NULL) + if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL); return ide_started; } - /* (ks/hs): See task_mulin_intr */ - msect = drive->mult_count; + if (HWGROUP(drive)->handler != NULL) { + unsigned long lflags; + spin_lock_irqsave(&io_request_lock, lflags); + HWGROUP(drive)->handler = NULL; + del_timer(&HWGROUP(drive)->timer); + spin_unlock_irqrestore(&io_request_lock, lflags); + } #ifdef ALTSTAT_SCREW_UP /* @@ -974,30 +1166,49 @@ if (!msect) { nsect = 1; while (rq->current_nr_sectors) { - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); - DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors); - drive->io_32bit = 0; + pBuf = task_map_rq(rq, &flags); + DTF("Multiwrite: %p, nsect: %d, " \ + "rq->current_nr_sectors: %d\n", + pBuf, nsect, rq->current_nr_sectors); +// rq->current_nr_sectors -= nsect; taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); - drive->io_32bit = io_32bit; + task_unmap_rq(pBuf, &flags); rq->errors = 0; rq->current_nr_sectors -= nsect; stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write"); } - ide_end_request(1, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 1); return ide_stopped; } #endif /* ALTSTAT_SCREW_UP */ - nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; - pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); - DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n", - pBuf, nsect, rq->current_nr_sectors); - drive->io_32bit = 0; - taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); - drive->io_32bit = io_32bit; + do { + nsect = rq->current_nr_sectors; + if (nsect > msect) + nsect = msect; + pBuf = task_map_rq(rq, &flags); + DTF("Multiwrite: %p, nsect: %d, msect: %d, " \ + "rq->current_nr_sectors: %ld\n", + pBuf, nsect, msect, rq->current_nr_sectors); + msect -= nsect; +// rq->current_nr_sectors -= nsect; + taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + task_unmap_rq(rq, pBuf, &flags); + rq->current_nr_sectors -= nsect; + /* + * FIXME :: We really can not legally get a new page/bh + * regardless, if this is the end of our segment. + * BH walking or segment can only be updated after we + * have a good GET_STAT(); return. + */ + if (!rq->current_nr_sectors) { + if (!DRIVER(drive)->end_request(drive, 1)) + if (!rq->bh) + return ide_stopped; + } + } while (msect); rq->errors = 0; - rq->current_nr_sectors -= nsect; - if (hwgroup->handler == NULL) + if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL); return ide_started; } @@ -1008,14 +1219,16 @@ switch(taskfile->command) { /* IDE_DRIVE_TASK_RAW_WRITE */ case CFA_WRITE_MULTI_WO_ERASE: + // case WIN_WRITE_LONG: + // case WIN_WRITE_LONG_ONCE: case WIN_MULTWRITE: case WIN_MULTWRITE_EXT: -// case WIN_WRITEDMA: -// case WIN_WRITEDMA_QUEUED: -// case WIN_WRITEDMA_EXT: -// case WIN_WRITEDMA_QUEUED_EXT: + return &pre_task_mulout_intr; + /* IDE_DRIVE_TASK_OUT */ case WIN_WRITE: + // case WIN_WRITE_ONCE: + case WIN_WRITE_EXT: case WIN_WRITE_VERIFY: case WIN_WRITE_BUFFER: case CFA_WRITE_SECT_WO_ERASE: @@ -1025,6 +1238,12 @@ case WIN_SMART: if (taskfile->feature == SMART_WRITE_LOG_SECTOR) return &pre_task_out_intr; + case WIN_WRITEDMA: + // case WIN_WRITEDMA_ONCE: + case WIN_WRITEDMA_QUEUED: + case WIN_WRITEDMA_EXT: + case WIN_WRITEDMA_QUEUED_EXT: + /* IDE_DRIVE_TASK_OUT */ default: break; } @@ -1040,6 +1259,7 @@ case CFA_TRANSLATE_SECTOR: case WIN_READ_BUFFER: case WIN_READ: + // case WIN_READ_ONCE: case WIN_READ_EXT: return &task_in_intr; case WIN_SECURITY_DISABLE: @@ -1051,11 +1271,16 @@ case WIN_WRITE_BUFFER: case WIN_WRITE_VERIFY: case WIN_WRITE: + // case WIN_WRITE_ONCE: case WIN_WRITE_EXT: return &task_out_intr; + // case WIN_READ_LONG: + // case WIN_READ_LONG_ONCE: case WIN_MULTREAD: case WIN_MULTREAD_EXT: return &task_mulin_intr; + // case WIN_WRITE_LONG: + // case WIN_WRITE_LONG_ONCE: case CFA_WRITE_MULTI_WO_ERASE: case WIN_MULTWRITE: case WIN_MULTWRITE_EXT: @@ -1074,13 +1299,16 @@ case CFA_REQ_EXT_ERROR_CODE: case CFA_ERASE_SECTORS: case WIN_VERIFY: + // case WIN_VERIFY_ONCE: case WIN_VERIFY_EXT: case WIN_SEEK: return &task_no_data_intr; case WIN_SPECIFY: return &set_geometry_intr; - case WIN_RESTORE: + case WIN_RECAL: + // case WIN_RESTORE: return &recal_intr; + case WIN_NOP: case WIN_DIAGNOSE: case WIN_FLUSH_CACHE: case WIN_FLUSH_CACHE_EXT: @@ -1111,11 +1339,13 @@ return &task_no_data_intr; #ifdef CONFIG_BLK_DEV_IDEDMA case WIN_READDMA: + // case WIN_READDMA_ONCE: case WIN_IDENTIFY_DMA: case WIN_READDMA_QUEUED: case WIN_READDMA_EXT: case WIN_READDMA_QUEUED_EXT: case WIN_WRITEDMA: + // case WIN_WRITEDMA_ONCE: case WIN_WRITEDMA_QUEUED: case WIN_WRITEDMA_EXT: case WIN_WRITEDMA_QUEUED_EXT: @@ -1130,14 +1360,26 @@ } } +ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile) +{ + switch(taskfile->command) { + case WIN_SPECIFY: /* set_geometry_intr */ + case WIN_RESTORE: /* recal_intr */ + case WIN_SETMULT: /* set_multmode_intr */ + default: + return(NULL); + } +} + /* Called by ioctl to feature out type of command being called */ int ide_cmd_type_parser (ide_task_t *args) { struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister; struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister; - args->prehandler = ide_pre_handler_parser(taskfile, hobfile); - args->handler = ide_handler_parser(taskfile, hobfile); + args->prehandler = ide_pre_handler_parser(taskfile, hobfile); + args->handler = ide_handler_parser(taskfile, hobfile); + args->posthandler = ide_post_handler_parser(taskfile, hobfile); switch(args->tfRegister[IDE_COMMAND_OFFSET]) { case WIN_IDENTIFY: @@ -1145,18 +1387,28 @@ return IDE_DRIVE_TASK_IN; case CFA_TRANSLATE_SECTOR: case WIN_READ: + // case WIN_READ_ONCE: + case WIN_READ_EXT: case WIN_READ_BUFFER: return IDE_DRIVE_TASK_IN; case WIN_WRITE: + // case WIN_WRITE_ONCE: + case WIN_WRITE_EXT: case WIN_WRITE_VERIFY: case WIN_WRITE_BUFFER: case CFA_WRITE_SECT_WO_ERASE: case WIN_DOWNLOAD_MICROCODE: return IDE_DRIVE_TASK_RAW_WRITE; + // case WIN_READ_LONG: + // case WIN_READ_LONG_ONCE: case WIN_MULTREAD: + case WIN_MULTREAD_EXT: return IDE_DRIVE_TASK_IN; + // case WIN_WRITE_LONG: + // case WIN_WRITE_LONG_ONCE: case CFA_WRITE_MULTI_WO_ERASE: case WIN_MULTWRITE: + case WIN_MULTWRITE_EXT: return IDE_DRIVE_TASK_RAW_WRITE; case WIN_SECURITY_DISABLE: case WIN_SECURITY_ERASE_UNIT: @@ -1178,12 +1430,14 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA case WIN_READDMA: + // case WIN_READDMA_ONCE: case WIN_IDENTIFY_DMA: case WIN_READDMA_QUEUED: case WIN_READDMA_EXT: case WIN_READDMA_QUEUED_EXT: return IDE_DRIVE_TASK_IN; case WIN_WRITEDMA: + // case WIN_WRITEDMA_ONCE: case WIN_WRITEDMA_QUEUED: case WIN_WRITEDMA_EXT: case WIN_WRITEDMA_QUEUED_EXT: @@ -1191,20 +1445,32 @@ #endif case WIN_SETFEATURES: switch(args->tfRegister[IDE_FEATURE_OFFSET]) { + case SETFEATURES_EN_8BIT: + case SETFEATURES_EN_WCACHE: + return IDE_DRIVE_TASK_NO_DATA; case SETFEATURES_XFER: return IDE_DRIVE_TASK_SET_XFER; case SETFEATURES_DIS_DEFECT: case SETFEATURES_EN_APM: case SETFEATURES_DIS_MSN: + case SETFEATURES_DIS_RETRY: + case SETFEATURES_EN_AAM: + case SETFEATURES_RW_LONG: + case SETFEATURES_SET_CACHE: + case SETFEATURES_DIS_RLA: case SETFEATURES_EN_RI: case SETFEATURES_EN_SI: case SETFEATURES_DIS_RPOD: case SETFEATURES_DIS_WCACHE: case SETFEATURES_EN_DEFECT: case SETFEATURES_DIS_APM: + case SETFEATURES_EN_ECC: case SETFEATURES_EN_MSN: + case SETFEATURES_EN_RETRY: case SETFEATURES_EN_RLA: case SETFEATURES_PREFETCH: + case SETFEATURES_4B_RW_LONG: + case SETFEATURES_DIS_AAM: case SETFEATURES_EN_RPOD: case SETFEATURES_DIS_RI: case SETFEATURES_DIS_SI: @@ -1215,6 +1481,7 @@ case CFA_REQ_EXT_ERROR_CODE: case CFA_ERASE_SECTORS: case WIN_VERIFY: + // case WIN_VERIFY_ONCE: case WIN_VERIFY_EXT: case WIN_SEEK: case WIN_SPECIFY: @@ -1254,119 +1521,462 @@ } /* - * This function is intended to be used prior to invoking ide_do_drive_cmd(). + * NOTICE: This is additions from IBM to provide a discrete interface, + * for selective taskregister access operations. Nice JOB Klaus!!! + * Glad to be able to work and co-develop this with you and IBM. */ -void ide_init_drive_taskfile (struct request *rq) +ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) { - memset(rq, 0, sizeof(*rq)); - rq->cmd = IDE_DRIVE_TASK_NO_DATA; -} + task_struct_t *taskfile = (task_struct_t *) task->tfRegister; + hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; + struct hd_driveid *id = drive->id; +#if DEBUG_TASKFILE + byte status; +#endif -/* - * This is kept for internal use only !!! - * This is an internal call and nobody in user-space has a damn - * reason to call this taskfile. - * - * ide_raw_taskfile is the one that user-space executes. - */ -int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf) -{ - struct request rq; - ide_task_t args; - memset(&args, 0, sizeof(ide_task_t)); +#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG + void debug_taskfile(drive, task); +#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ - args.tfRegister[IDE_DATA_OFFSET] = taskfile->data; - args.tfRegister[IDE_FEATURE_OFFSET] = taskfile->feature; - args.tfRegister[IDE_NSECTOR_OFFSET] = taskfile->sector_count; - args.tfRegister[IDE_SECTOR_OFFSET] = taskfile->sector_number; - args.tfRegister[IDE_LCYL_OFFSET] = taskfile->low_cylinder; - args.tfRegister[IDE_HCYL_OFFSET] = taskfile->high_cylinder; - args.tfRegister[IDE_SELECT_OFFSET] = taskfile->device_head; - args.tfRegister[IDE_COMMAND_OFFSET] = taskfile->command; - - args.hobRegister[IDE_DATA_OFFSET_HOB] = hobfile->data; - args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature; - args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count; - args.hobRegister[IDE_SECTOR_OFFSET_HOB] = hobfile->sector_number; - args.hobRegister[IDE_LCYL_OFFSET_HOB] = hobfile->low_cylinder; - args.hobRegister[IDE_HCYL_OFFSET_HOB] = hobfile->high_cylinder; - args.hobRegister[IDE_SELECT_OFFSET_HOB] = hobfile->device_head; - args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control; + /* + * (ks) Check taskfile in/out flags. + * If set, then execute as it is defined. + * If not set, then define default settings. + * The default values are: + * write and read all taskfile registers (except data) + * write and read the hob registers (sector,nsector,lcyl,hcyl) + */ + if (task->tf_out_flags.all == 0) { + task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS; + if ((id->command_set_2 & 0x0400) && + (id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8); + } + } - ide_init_drive_taskfile(&rq); - /* This is kept for internal use only !!! */ - args.command_type = ide_cmd_type_parser (&args); - if (args.command_type != IDE_DRIVE_TASK_NO_DATA) - rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count; + if (task->tf_in_flags.all == 0) { + task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; + if ((id->command_set_2 & 0x0400) && + (id->cfs_enable_2 & 0x0400) && + (drive->addressing == 1)) { + task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); + } + } - rq.cmd = IDE_DRIVE_TASKFILE; - rq.buffer = buf; - rq.special = &args; - return ide_do_drive_cmd(drive, &rq, ide_wait); -} + /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive), drive, 0); -int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf) -{ - struct request rq; - ide_init_drive_taskfile(&rq); - rq.cmd = IDE_DRIVE_TASKFILE; - rq.buffer = buf; +#if DEBUG_TASKFILE + status = GET_STAT(); + if (status & 0x80) { + printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status); + udelay(100); + status = GET_STAT(); + printk("flagged_taskfile -> Status = %02x\n", status); + } +#endif - if (args->command_type != IDE_DRIVE_TASK_NO_DATA) - rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET]; + if (task->tf_out_flags.b.data) { + unsigned short data = taskfile->data + (hobfile->data << 8); + OUT_WORD(data, IDE_DATA_REG); + } - rq.special = args; - return ide_do_drive_cmd(drive, &rq, ide_wait); -} + /* (ks) send hob registers first */ + if (task->tf_out_flags.b.nsector_hob) + OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG); + if (task->tf_out_flags.b.sector_hob) + OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG); + if (task->tf_out_flags.b.lcyl_hob) + OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG); + if (task->tf_out_flags.b.hcyl_hob) + OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG); + + /* (ks) Send now the standard registers */ + if (task->tf_out_flags.b.error_feature) + OUT_BYTE(taskfile->feature, IDE_FEATURE_REG); + /* refers to number of sectors to transfer */ + if (task->tf_out_flags.b.nsector) + OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG); + /* refers to sector offset or start sector */ + if (task->tf_out_flags.b.sector) + OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG); + if (task->tf_out_flags.b.lcyl) + OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG); + if (task->tf_out_flags.b.hcyl) + OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG); + + /* + * (ks) In the flagged taskfile approch, we will used all specified + * registers and the register value will not be changed. Except the + * select bit (master/slave) in the drive_head register. We must make + * sure that the desired drive is selected. + */ + OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG); + switch(task->data_phase) { + case TASKFILE_OUT_DMAQ: + case TASKFILE_OUT_DMA: + HWIF(drive)->dmaproc(ide_dma_write, drive); + break; -#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG -char * ide_ioctl_verbose (unsigned int cmd) -{ - return("unknown"); + case TASKFILE_IN_DMAQ: + case TASKFILE_IN_DMA: + HWIF(drive)->dmaproc(ide_dma_read, drive); + break; + + default: + if (task->handler == NULL) + return ide_stopped; + + ide_set_handler (drive, task->handler, WAIT_WORSTCASE, NULL); + /* Issue the command */ + OUT_BYTE(taskfile->command, IDE_COMMAND_REG); + if (task->prehandler != NULL) + return task->prehandler(drive, HWGROUP(drive)->rq); + } + + return ide_started; } -char * ide_task_cmd_verbose (byte task) +ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive) { - return("unknown"); -} -#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ + byte stat = GET_STAT(); -/* - * The taskfile glue table - * - * reqtask.data_phase reqtask.req_cmd - * args.command_type args.handler - * - * TASKFILE_P_OUT_DMAQ ?? ?? - * TASKFILE_P_IN_DMAQ ?? ?? - * TASKFILE_P_OUT_DMA ?? ?? - * TASKFILE_P_IN_DMA ?? ?? - * TASKFILE_P_OUT ?? ?? - * TASKFILE_P_IN ?? ?? - * - * TASKFILE_OUT_DMAQ IDE_DRIVE_TASK_RAW_WRITE NULL - * TASKFILE_IN_DMAQ IDE_DRIVE_TASK_IN NULL - * - * TASKFILE_OUT_DMA IDE_DRIVE_TASK_RAW_WRITE NULL - * TASKFILE_IN_DMA IDE_DRIVE_TASK_IN NULL - * - * TASKFILE_IN_OUT ?? ?? - * - * TASKFILE_MULTI_OUT IDE_DRIVE_TASK_RAW_WRITE task_mulout_intr - * TASKFILE_MULTI_IN IDE_DRIVE_TASK_IN task_mulin_intr - * - * TASKFILE_OUT IDE_DRIVE_TASK_RAW_WRITE task_out_intr - * TASKFILE_OUT IDE_DRIVE_TASK_OUT task_out_intr - * - * TASKFILE_IN IDE_DRIVE_TASK_IN task_in_intr - * TASKFILE_NO_DATA IDE_DRIVE_TASK_NO_DATA task_no_data_intr - * - * IDE_DRIVE_TASK_SET_XFER task_no_data_intr - * IDE_DRIVE_TASK_INVALID - * + local_irq_enable(); + + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { + if (stat & ERR_STAT) { + return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat); + } + /* + * (ks) Unexpected ATA data phase detected. + * This should not happen. But, it can ! + * I am not sure, which function is best to clean up + * this situation. I choose: ide_error(...) + */ + return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); + } + + ide_end_drive_cmd (drive, stat, GET_ERR()); + + return ide_stopped; +} + +/* + * Handler for command with PIO data-in phase */ +ide_startstop_t flagged_task_in_intr (ide_drive_t *drive) +{ + byte stat = GET_STAT(); + struct request *rq = HWGROUP(drive)->rq; + char *pBuf = NULL; + int retries = 5; + + if (rq->current_nr_sectors == 0) + return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); + + if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { + if (stat & ERR_STAT) { + return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat); + } + /* + * (ks) Unexpected ATA data phase detected. + * This should not happen. But, it can ! + * I am not sure, which function is best to clean up + * this situation. I choose: ide_error(...) + */ + return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); + } + + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("Read - rq->current_nr_sectors: %d, status: %02x\n", (int) rq->current_nr_sectors, stat); + + taskfile_input_data(drive, pBuf, SECTOR_WORDS); + + if (--rq->current_nr_sectors != 0) { + /* + * (ks) We don't know which command was executed. + * So, we wait the 'WORSTCASE' value. + */ + ide_set_handler(drive, &flagged_task_in_intr, WAIT_WORSTCASE, NULL); + return ide_started; + } + /* + * (ks) Last sector was transfered, wait until drive is ready. + * This can take up to 10 usec. We willl wait max 50 us. + */ + while (((stat = GET_STAT()) & BUSY_STAT) && retries--) + udelay(10); + ide_end_drive_cmd (drive, stat, GET_ERR()); + + return ide_stopped; +} + +ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive) +{ + byte stat = GET_STAT(); + struct request *rq = HWGROUP(drive)->rq; + char *pBuf = NULL; + int retries = 5; + unsigned int msect, nsect; + + if (rq->current_nr_sectors == 0) + return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); + + msect = drive->mult_count; + if (msect == 0) + return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); + + if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { + if (stat & ERR_STAT) { + return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat); + } + /* + * (ks) Unexpected ATA data phase detected. + * This should not happen. But, it can ! + * I am not sure, which function is best to clean up + * this situation. I choose: ide_error(...) + */ + return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); + } + + nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + + DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n", + pBuf, nsect, rq->current_nr_sectors); + + taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); + + rq->current_nr_sectors -= nsect; + if (rq->current_nr_sectors != 0) { + /* + * (ks) We don't know which command was executed. + * So, we wait the 'WORSTCASE' value. + */ + ide_set_handler(drive, &flagged_task_mulin_intr, WAIT_WORSTCASE, NULL); + return ide_started; + } + + /* + * (ks) Last sector was transfered, wait until drive is ready. + * This can take up to 10 usec. We willl wait max 50 us. + */ + while (((stat = GET_STAT()) & BUSY_STAT) && retries--) + udelay(10); + ide_end_drive_cmd (drive, stat, GET_ERR()); + + return ide_stopped; +} + +/* + * Pre handler for command with PIO data-out phase + */ +ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq) +{ + byte stat = GET_STAT(); + ide_startstop_t startstop; + + if (!rq->current_nr_sectors) { + return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat); + } + + if (ide_wait_stat(&startstop, drive, DATA_READY, + BAD_W_STAT, WAIT_DRQ)) { + printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name); + return startstop; + } + + taskfile_output_data(drive, rq->buffer, SECTOR_WORDS); + --rq->current_nr_sectors; + + return ide_started; +} + +ide_startstop_t flagged_task_out_intr (ide_drive_t *drive) +{ + byte stat = GET_STAT(); + struct request *rq = HWGROUP(drive)->rq; + char *pBuf = NULL; + + if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) + return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat); + + if (!rq->current_nr_sectors) { + ide_end_drive_cmd (drive, stat, GET_ERR()); + return ide_stopped; + } + + if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) { + /* + * (ks) Unexpected ATA data phase detected. + * This should not happen. But, it can ! + * I am not sure, which function is best to clean up + * this situation. I choose: ide_error(...) + */ + return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); + } + + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("Write - rq->current_nr_sectors: %d, status: %02x\n", + (int) rq->current_nr_sectors, stat); + + taskfile_output_data(drive, pBuf, SECTOR_WORDS); + --rq->current_nr_sectors; + + /* + * (ks) We don't know which command was executed. + * So, we wait the 'WORSTCASE' value. + */ + ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL); + + return ide_started; +} + +ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) +{ + byte stat = GET_STAT(); + char *pBuf = NULL; + ide_startstop_t startstop; + unsigned int msect, nsect; + + if (!rq->current_nr_sectors) + return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat); + + msect = drive->mult_count; + if (msect == 0) + return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat); + + if (ide_wait_stat(&startstop, drive, DATA_READY, + BAD_W_STAT, WAIT_DRQ)) { + printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name); + return startstop; + } + + nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n", + pBuf, nsect, rq->current_nr_sectors); + + taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + + rq->current_nr_sectors -= nsect; + + return ide_started; +} + +ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive) +{ + byte stat = GET_STAT(); + struct request *rq = HWGROUP(drive)->rq; + char *pBuf = NULL; + unsigned int msect, nsect; + + msect = drive->mult_count; + if (msect == 0) + return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (multimode not set)", stat); + + if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) + return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat); + + if (!rq->current_nr_sectors) { + ide_end_drive_cmd (drive, stat, GET_ERR()); + return ide_stopped; + } + + if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) { + /* + * (ks) Unexpected ATA data phase detected. + * This should not happen. But, it can ! + * I am not sure, which function is best to clean up + * this situation. I choose: ide_error(...) + */ + return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); + } + + nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors; + pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE); + DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n", + pBuf, nsect, rq->current_nr_sectors); + + taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + rq->current_nr_sectors -= nsect; + + /* + * (ks) We don't know which command was executed. + * So, we wait the 'WORSTCASE' value. + */ + ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL); + + return ide_started; +} + +/* + * This function is intended to be used prior to invoking ide_do_drive_cmd(). + */ +void ide_init_drive_taskfile (struct request *rq) +{ + memset(rq, 0, sizeof(*rq)); + rq->cmd = IDE_DRIVE_TASK_NO_DATA; +} + +int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, byte *buf) +{ + struct request rq; + + ide_init_drive_taskfile(&rq); + rq.cmd = IDE_DRIVE_TASKFILE; + rq.buffer = buf; + + /* + * (ks) We transfer currently only whole sectors. + * This is suffient for now. But, it would be great, + * if we would find a solution to transfer any size. + * To support special commands like READ LONG. + */ + if (args->command_type != IDE_DRIVE_TASK_NO_DATA) { + if (data_size == 0) + rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET]; + /* rq.hard_cur_sectors */ + else + rq.current_nr_sectors = rq.nr_sectors = data_size / SECTOR_SIZE; + /* rq.hard_cur_sectors */ + } + + if (args->tf_out_flags.all == 0) { + /* + * clean up kernel settings for driver sanity, regardless. + * except for discrete diag services. + */ + args->posthandler = ide_post_handler_parser( + (struct hd_drive_task_hdr *) args->tfRegister, + (struct hd_drive_hob_hdr *) args->hobRegister); + + } + rq.special = args; + return ide_do_drive_cmd(drive, &rq, ide_wait); +} + +int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf) +{ + return ide_diag_taskfile(drive, args, 0, buf); +} + +#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG +char * ide_ioctl_verbose (unsigned int cmd) +{ + return("unknown"); +} + +char * ide_task_cmd_verbose (byte task) +{ + return("unknown"); +} +#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ #define MAX_DMA (256*SECTOR_WORDS) @@ -1374,7 +1984,6 @@ { ide_task_request_t *req_task; ide_task_t args; - byte *outbuf = NULL; byte *inbuf = NULL; task_ioreg_t *argsptr = args.tfRegister; @@ -1383,6 +1992,9 @@ int tasksize = sizeof(struct ide_task_request_s); int taskin = 0; int taskout = 0; + byte io_32bit = drive->io_32bit; + +// printk("IDE Taskfile ...\n"); req_task = kmalloc(tasksize, GFP_KERNEL); if (req_task == NULL) return -ENOMEM; @@ -1423,8 +2035,7 @@ } } - memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE); - memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE); + memset (&args, 0, sizeof (ide_task_t) ); memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE); @@ -1440,64 +2051,61 @@ ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET])); #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */ + drive->io_32bit = 0; switch(req_task->data_phase) { case TASKFILE_OUT_DMAQ: case TASKFILE_OUT_DMA: - args.prehandler = NULL; - args.handler = NULL; - args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, outbuf); + err = ide_diag_taskfile(drive, &args, taskout, outbuf); break; case TASKFILE_IN_DMAQ: case TASKFILE_IN_DMA: - args.prehandler = NULL; - args.handler = NULL; - args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, inbuf); + err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; case TASKFILE_IN_OUT: #if 0 args.prehandler = &pre_task_out_intr; args.handler = &task_out_intr; args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, outbuf); + err = ide_diag_taskfile(drive, &args, taskout, outbuf); args.prehandler = NULL; args.handler = &task_in_intr; args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, inbuf); + err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; #else err = -EFAULT; goto abort; #endif case TASKFILE_MULTI_OUT: - if (drive->mult_count) { - args.prehandler = &pre_task_out_intr; - args.handler = &task_mulout_intr; - args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, outbuf); - } else { + if (!drive->mult_count) { /* (hs): give up if multcount is not set */ printk("%s: %s Multimode Write " \ "multcount is not set\n", - drive->name, __FUNCTION__); + drive->name, __FUNCTION__); err = -EPERM; goto abort; } + if (args.tf_out_flags.all != 0) { + args.prehandler = &flagged_pre_task_mulout_intr; + args.handler = &flagged_task_mulout_intr; + } else { + args.prehandler = &pre_task_mulout_intr; + args.handler = &task_mulout_intr; + } + err = ide_diag_taskfile(drive, &args, taskout, outbuf); break; case TASKFILE_OUT: - args.prehandler = &pre_task_out_intr; - args.handler = &task_out_intr; - args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, outbuf); + if (args.tf_out_flags.all != 0) { + args.prehandler = &flagged_pre_task_out_intr; + args.handler = &flagged_task_out_intr; + } else { + args.prehandler = &pre_task_out_intr; + args.handler = &task_out_intr; + } + err = ide_diag_taskfile(drive, &args, taskout, outbuf); break; case TASKFILE_MULTI_IN: - if (drive->mult_count) { - args.prehandler = NULL; - args.handler = &task_mulin_intr; - args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, inbuf); - } else { + if (!drive->mult_count) { /* (hs): give up if multcount is not set */ printk("%s: %s Multimode Read failure " \ "multcount is not set\n", @@ -1505,23 +2113,30 @@ err = -EPERM; goto abort; } + if (args.tf_out_flags.all != 0) { + args.handler = &flagged_task_mulin_intr; + } else { + args.handler = &task_mulin_intr; + } + err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; case TASKFILE_IN: - args.prehandler = NULL; - args.handler = &task_in_intr; - args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, inbuf); + if (args.tf_out_flags.all != 0) { + args.handler = &flagged_task_in_intr; + } else { + args.handler = &task_in_intr; + } + err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; case TASKFILE_NO_DATA: - args.prehandler = NULL; - args.handler = &task_no_data_intr; - args.posthandler = NULL; - err = ide_raw_taskfile(drive, &args, NULL); + if (args.tf_out_flags.all != 0) { + args.handler = &flagged_task_no_data_intr; + } else { + args.handler = &task_no_data_intr; + } + err = ide_diag_taskfile(drive, &args, 0, NULL); break; default: - args.prehandler = NULL; - args.handler = NULL; - args.posthandler = NULL; err = -EFAULT; goto abort; } @@ -1555,15 +2170,175 @@ kfree(outbuf); if (inbuf != NULL) kfree(inbuf); + +// printk("IDE Taskfile ioctl ended. rc = %i\n", err); + + drive->io_32bit = io_32bit; + + return err; +} + +int ide_ata66_check (ide_drive_t *drive, ide_task_t *args); +int set_transfer(ide_drive_t *drive, ide_task_t *args); + +/* + * FIXME : this needs to map into at taskfile. + */ +int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ +#if 1 + int err = 0; + byte args[4], *argbuf = args; + byte xfer_rate = 0; + int argsize = 4; + ide_task_t tfargs; + + if (NULL == (void *) arg) { + struct request rq; + ide_init_drive_cmd(&rq); + return ide_do_drive_cmd(drive, &rq, ide_wait); + } + + if (copy_from_user(args, (void *)arg, 4)) + return -EFAULT; + + memset(&tfargs, 0, sizeof(ide_task_t)); + tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2]; + tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3]; + tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1]; + tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00; + tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00; + tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00; + tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0]; + + if (args[3]) { + argsize = 4 + (SECTOR_WORDS * 4 * args[3]); + argbuf = kmalloc(argsize, GFP_KERNEL); + if (argbuf == NULL) + return -ENOMEM; + memcpy(argbuf, args, 4); + } + if (set_transfer(drive, &tfargs)) { + xfer_rate = args[1]; + if (ide_ata66_check(drive, &tfargs)) + goto abort; + } + + err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); + + if (!err && xfer_rate) { + /* active-retuning-calls future */ + if ((HWIF(drive)->speedproc) != NULL) + HWIF(drive)->speedproc(drive, xfer_rate); + ide_driveid_update(drive); + } +abort: + if (copy_to_user((void *)arg, argbuf, argsize)) + err = -EFAULT; + if (argsize > 4) + kfree(argbuf); + return err; + +#else + + int err = 0; + byte args[4], *argbuf = args; + byte xfer_rate = 0; + int argsize = 0; + ide_task_t tfargs; + + if (NULL == (void *) arg) { + struct request rq; + ide_init_drive_cmd(&rq); + return ide_do_drive_cmd(drive, &rq, ide_wait); + } + + if (copy_from_user(args, (void *)arg, 4)) + return -EFAULT; + + memset(&tfargs, 0, sizeof(ide_task_t)); + tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2]; + tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3]; + tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1]; + tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00; + tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00; + tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00; + tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0]; + + if (args[3]) { + argsize = (SECTOR_WORDS * 4 * args[3]); + argbuf = kmalloc(argsize, GFP_KERNEL); + if (argbuf == NULL) + return -ENOMEM; + } + + if (set_transfer(drive, &tfargs)) { + xfer_rate = args[1]; + if (ide_ata66_check(drive, &tfargs)) + goto abort; + } + + tfargs.command_type = ide_cmd_type_parser(&tfargs); + err = ide_raw_taskfile(drive, &tfargs, argbuf); + + if (!err && xfer_rate) { + /* active-retuning-calls future */ + if ((HWIF(drive)->speedproc) != NULL) + HWIF(drive)->speedproc(drive, xfer_rate); + ide_driveid_update(drive); + } +abort: + + args[0] = tfargs.tfRegister[IDE_COMMAND_OFFSET]; + args[1] = tfargs.tfRegister[IDE_FEATURE_OFFSET]; + args[2] = tfargs.tfRegister[IDE_NSECTOR_OFFSET]; + args[3] = 0; + + if (copy_to_user((void *)arg, argbuf, 4)) + err = -EFAULT; + if (argbuf != NULL) { + if (copy_to_user((void *)arg, argbuf + 4, argsize)) + err = -EFAULT; + kfree(argbuf); + } + return err; + +#endif + +} + +/* + * FIXME : this needs to map into at taskfile. + */ +int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + byte args[7], *argbuf = args; + int argsize = 7; + + if (copy_from_user(args, (void *)arg, 7)) + return -EFAULT; + err = ide_wait_cmd_task(drive, argbuf); + if (copy_to_user((void *)arg, argbuf, argsize)) + err = -EFAULT; return err; } +EXPORT_SYMBOL(drive_is_ready); +EXPORT_SYMBOL(wait_for_ready); + EXPORT_SYMBOL(task_read_24); -EXPORT_SYMBOL(do_rw_taskfile); -EXPORT_SYMBOL(do_taskfile); -// EXPORT_SYMBOL(flagged_taskfile); +EXPORT_SYMBOL(ata_input_data); +EXPORT_SYMBOL(ata_output_data); +EXPORT_SYMBOL(atapi_input_bytes); +EXPORT_SYMBOL(atapi_output_bytes); +EXPORT_SYMBOL(taskfile_input_data); +EXPORT_SYMBOL(taskfile_output_data); -//EXPORT_SYMBOL(ide_end_taskfile); +EXPORT_SYMBOL(ide_wait_stat); +EXPORT_SYMBOL(do_rw_taskfile); +EXPORT_SYMBOL(flagged_taskfile); +EXPORT_SYMBOL(ide_end_taskfile); EXPORT_SYMBOL(set_multmode_intr); EXPORT_SYMBOL(set_geometry_intr); @@ -1574,15 +2349,343 @@ EXPORT_SYMBOL(task_mulin_intr); EXPORT_SYMBOL(pre_task_out_intr); EXPORT_SYMBOL(task_out_intr); +EXPORT_SYMBOL(pre_task_mulout_intr); EXPORT_SYMBOL(task_mulout_intr); EXPORT_SYMBOL(ide_init_drive_taskfile); -EXPORT_SYMBOL(ide_wait_taskfile); EXPORT_SYMBOL(ide_raw_taskfile); EXPORT_SYMBOL(ide_pre_handler_parser); EXPORT_SYMBOL(ide_handler_parser); +EXPORT_SYMBOL(ide_post_handler_parser); EXPORT_SYMBOL(ide_cmd_type_parser); EXPORT_SYMBOL(ide_taskfile_ioctl); +EXPORT_SYMBOL(ide_cmd_ioctl); +EXPORT_SYMBOL(ide_task_ioctl); + +/* + * Beginning of Taskfile OPCODE Library and feature sets. + */ + +/* + * All hosts that use the 80c ribbon must use! + * The name is derived from upper byte of word 93 and the 80c ribbon. + */ +byte eighty_ninty_three (ide_drive_t *drive) +{ +#if 0 + if (!HWIF(drive)->udma_four) + return 0; + + if (drive->id->major_rev_num) { + int hssbd = 0; + int i; + /* + * Determime 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 ((byte) ((HWIF(drive)->udma_four) && +#ifndef CONFIG_IDEDMA_IVB + (drive->id->hw_config & 0x4000) && +#endif /* CONFIG_IDEDMA_IVB */ + (drive->id->hw_config & 0x6000)) ? 1 : 0); +#endif +} + +int ide_ata66_check (ide_drive_t *drive, ide_task_t *args) +{ + if (!HWIF(drive)->udma_four) { + printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", + HWIF(drive)->name); + return 1; + } + if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && + (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) && + (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) { +#ifndef CONFIG_IDEDMA_IVB + if ((drive->id->hw_config & 0x6000) == 0) { +#else /* !CONFIG_IDEDMA_IVB */ + if (((drive->id->hw_config & 0x2000) == 0) || + ((drive->id->hw_config & 0x4000) == 0)) { +#endif /* CONFIG_IDEDMA_IVB */ + printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name); + return 1; + } + } + return 0; +} + +/* + * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER. + * 1 : Safe to update drive->id DMA registers. + * 0 : OOPs not allowed. + */ +int set_transfer (ide_drive_t *drive, ide_task_t *args) +{ + if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && + (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) && + (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) && + (drive->id->dma_ultra || + drive->id->dma_mword || + drive->id->dma_1word)) + return 1; + + return 0; +} + +byte ide_auto_reduce_xfer (ide_drive_t *drive) +{ + if (!drive->crc_count) + return drive->current_speed; + drive->crc_count = 0; + + switch(drive->current_speed) { + case XFER_UDMA_7: return XFER_UDMA_6; + case XFER_UDMA_6: return XFER_UDMA_5; + case XFER_UDMA_5: return XFER_UDMA_4; + case XFER_UDMA_4: return XFER_UDMA_3; + case XFER_UDMA_3: return XFER_UDMA_2; + case XFER_UDMA_2: return XFER_UDMA_1; + case XFER_UDMA_1: return XFER_UDMA_0; + /* + * OOPS we do not goto non Ultra DMA modes + * without iCRC's available we force + * the system to PIO and make the user + * invoke the ATA-1 ATA-2 DMA modes. + */ + case XFER_UDMA_0: + default: return XFER_PIO_4; + } +} + +int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf) +{ + ide_task_t args; + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01; + if (drive->media == ide_disk) + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_IDENTIFY; + else + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_PIDENTIFY; + args.command_type = ide_cmd_type_parser(&args); + return ide_raw_taskfile(drive, &args, buf); +} + +/* + * Update the + */ +int ide_driveid_update (ide_drive_t *drive) +{ +#if 0 + struct hd_driveid *id; + + id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); + if (!id) + return 0; + + taskfile_lib_get_identify(drive, (char *)&id); + + ide_fix_driveid(id); + if (id) { + drive->id->dma_ultra = id->dma_ultra; + drive->id->dma_mword = id->dma_mword; + drive->id->dma_1word = id->dma_1word; + /* anything more ? */ + kfree(id); + } + return 1; +#else + /* + * Re-read drive->id for possible DMA mode + * change (copied from ide-probe.c) + */ + struct hd_driveid *id; + unsigned long timeout, flags; + + SELECT_MASK(HWIF(drive), drive, 1); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + ide_delay_50ms(); + OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG); + timeout = jiffies + WAIT_WORSTCASE; + do { + if (time_after(jiffies, timeout)) { + SELECT_MASK(HWIF(drive), drive, 0); + return 0; /* drive timed-out */ + } + ide_delay_50ms(); /* give drive a breather */ + } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT); + ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ + if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { + SELECT_MASK(HWIF(drive), drive, 0); + printk("%s: CHECK for good STATUS\n", drive->name); + return 0; + } + local_irq_save(flags); + SELECT_MASK(HWIF(drive), drive, 0); + id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); + if (!id) { + local_irq_restore(flags); + return 0; + } + ata_input_data(drive, id, SECTOR_WORDS); + (void) GET_STAT(); /* clear drive IRQ */ + local_irq_enable(); + local_irq_restore(flags); + ide_fix_driveid(id); + if (id) { + drive->id->dma_ultra = id->dma_ultra; + drive->id->dma_mword = id->dma_mword; + drive->id->dma_1word = id->dma_1word; + /* anything more ? */ + kfree(id); + } + + return 1; +#endif +} + + +/* + * Similar to ide_wait_stat(), except it never calls ide_error internally. + * This is a kludge to handle the new ide_config_drive_speed() function, + * and should not otherwise be used anywhere. Eventually, the tuneproc's + * should be updated to return ide_startstop_t, in which case we can get + * rid of this abomination again. :) -ml + * + * It is gone.......... + * + * const char *msg == consider adding for verbose errors. + */ +int ide_config_drive_speed (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); + int i, error = 1; + byte stat; + +#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) + hwif->dmaproc(ide_dma_host_off, drive); +#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ + + /* + * 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 + */ + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ + udelay(1); + SELECT_DRIVE(HWIF(drive), drive); + SELECT_MASK(HWIF(drive), drive, 0); + udelay(1); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + OUT_BYTE(speed, IDE_NSECTOR_REG); + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + if ((IDE_CONTROL_REG) && (drive->quirk_list == 2)) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); + udelay(1); + /* + * Wait for drive to become non-BUSY + */ + if ((stat = GET_STAT()) & BUSY_STAT) { + unsigned long flags, timeout; + local_irq_set(flags); + timeout = jiffies + WAIT_CMD; + while ((stat = GET_STAT()) & BUSY_STAT) { + if (time_after(jiffies, timeout)) + break; + } + local_irq_restore(flags); + } + + /* + * Allow status to settle, then read it again. + * A few rare drives vastly violate the 400ns spec here, + * so we'll wait up to 10usec for a "good" status + * rather than expensively fail things immediately. + * This fix courtesy of Matthew Faupel & Niccolo Rigacci. + */ + for (i = 0; i < 10; i++) { + udelay(1); + if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { + error = 0; + break; + } + } + + SELECT_MASK(HWIF(drive), drive, 0); + + enable_irq(hwif->irq); + + if (error) { + (void) ide_dump_status(drive, "set_drive_speed_status", stat); + return error; + } + + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + +#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) + if (speed >= XFER_SW_DMA_0) + hwif->dmaproc(ide_dma_host_on, drive); +#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ + + switch(speed) { + case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break; + case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break; + case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break; + case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; + case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; + case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; + case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break; + case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break; + case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break; + case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break; + case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break; + case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break; + case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break; + case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; + default: break; + } + if (!drive->init_speed) + drive->init_speed = speed; + drive->current_speed = speed; + return error; +} + +EXPORT_SYMBOL(eighty_ninty_three); +EXPORT_SYMBOL(ide_auto_reduce_xfer); +EXPORT_SYMBOL(set_transfer); +EXPORT_SYMBOL(taskfile_lib_get_identify); +EXPORT_SYMBOL(ide_driveid_update); +EXPORT_SYMBOL(ide_config_drive_speed); #ifdef CONFIG_PKT_TASK_IOCTL diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/it8172.c linux.20pre2-ac1/drivers/ide/it8172.c --- linux.20pre2/drivers/ide/it8172.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/it8172.c 2002-08-06 15:42:11.000000000 +0100 @@ -46,106 +46,134 @@ /* * Prototypes */ +static byte it8172_ratemask (ide_drive_t *drive); +static byte it8172_ratefilter (ide_drive_t *drive, byte speed); static void it8172_tune_drive (ide_drive_t *drive, byte pio); -#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING) static byte it8172_dma_2_pio (byte xfer_rate); -static int it8172_tune_chipset (ide_drive_t *drive, byte speed); +static int it8172_tune_chipset (ide_drive_t *drive, byte xferspeed); +#ifdef CONFIG_BLK_DEV_IDEDMA static int it8172_config_chipset_for_dma (ide_drive_t *drive); static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive); #endif unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name); void __init ide_init_it8172 (ide_hwif_t *hwif); +static byte it8172_ratemask (ide_drive_t *drive) +{ + byte mode = 0x00; +#if 1 + mode |= 0x01; +#endif + return (mode &= ~0xF8); +} -static void it8172_tune_drive (ide_drive_t *drive, byte pio) +static byte it8172_ratefilter (ide_drive_t *drive, byte speed) { - unsigned long flags; - u16 drive_enables; - u32 drive_timing; - int is_slave = (&HWIF(drive)->drives[1] == drive); - - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &drive_enables); - pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &drive_timing); +#ifdef CONFIG_BLK_DEV_IDEDMA + byte mode = it8172_ratemask(drive); - /* - * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44 - * are being left at the default values of 8 PCI clocks (242 nsec - * for a 33 MHz clock). These can be safely shortened at higher - * PIO modes. The DIOR/DIOW pulse width and recovery times only - * apply to PIO modes, not to the DMA modes. - */ - - /* - * Enable port 0x44. The IT8172G spec is confused; it calls - * this register the "Slave IDE Timing Register", but in fact, - * it controls timing for both master and slave drives. - */ - drive_enables |= 0x4000; + switch(mode) { + case 0x04: // while (speed > XFER_UDMA_6) speed--; break; + case 0x03: // while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + +static void it8172_tune_drive (ide_drive_t *drive, byte pio) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int is_slave = (hwif->drives[1] == drive); + unsigned long flags; + u16 drive_enables; + u32 drive_timing; + + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + spin_lock_irqsave(&io_request_lock, flags); + pci_read_config_word(dev, 0x40, &drive_enables); + pci_read_config_dword(dev, 0x44, &drive_timing); + + /* + * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44 + * are being left at the default values of 8 PCI clocks (242 nsec + * for a 33 MHz clock). These can be safely shortened at higher + * PIO modes. The DIOR/DIOW pulse width and recovery times only + * apply to PIO modes, not to the DMA modes. + */ + + /* + * Enable port 0x44. The IT8172G spec is confused; it calls + * this register the "Slave IDE Timing Register", but in fact, + * it controls timing for both master and slave drives. + */ + drive_enables |= 0x4000; + + if (is_slave) { + drive_enables &= 0xc006; + if (pio > 1) + /* enable prefetch and IORDY sample-point */ + drive_enables |= 0x0060; + } else { + drive_enables &= 0xc060; + if (pio > 1) + /* enable prefetch and IORDY sample-point */ + drive_enables |= 0x0006; + } - if (is_slave) { - drive_enables &= 0xc006; - if (pio > 1) - /* enable prefetch and IORDY sample-point */ - drive_enables |= 0x0060; - } else { - drive_enables &= 0xc060; - if (pio > 1) - /* enable prefetch and IORDY sample-point */ - drive_enables |= 0x0006; - } - - save_flags(flags); - cli(); - pci_write_config_word(HWIF(drive)->pci_dev, 0x40, drive_enables); - restore_flags(flags); + pci_write_config_word(dev, 0x40, drive_enables); + spin_unlock_irqrestore(&io_request_lock, flags) } -#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING) -/* - * - */ static byte it8172_dma_2_pio (byte xfer_rate) { - switch(xfer_rate) { - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_PIO_4: - return 4; - case XFER_MW_DMA_1: - case XFER_PIO_3: - return 3; - case XFER_SW_DMA_2: - case XFER_PIO_2: - return 2; - case XFER_MW_DMA_0: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - return 0; - } -} - -static int it8172_tune_chipset (ide_drive_t *drive, byte speed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - int a_speed = 3 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int u_speed = 0; - int err = 0; - byte reg48, reg4a; + switch(xfer_rate) { + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + case XFER_MW_DMA_2: + case XFER_PIO_4: + return 4; + case XFER_MW_DMA_1: + case XFER_PIO_3: + return 3; + case XFER_SW_DMA_2: + case XFER_PIO_2: + return 2; + case XFER_MW_DMA_0: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + case XFER_PIO_1: + case XFER_PIO_0: + case XFER_PIO_SLOW: + default: + return 0; + } +} + +static int it8172_tune_chipset (ide_drive_t *drive, byte xferspeed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte speed = it8172_ratefilter(drive, xferspeed); + int a_speed = 3 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int u_speed = 0; + byte reg48, reg4a; - pci_read_config_byte(dev, 0x48, ®48); - pci_read_config_byte(dev, 0x4a, ®4a); + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x4a, ®4a); /* * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec @@ -157,130 +185,205 @@ * performance. */ - switch(speed) { - case XFER_UDMA_4: - case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_5: - case XFER_UDMA_3: - case XFER_UDMA_1: //u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: break; - default: return -1; - } - - if (speed >= XFER_UDMA_0) { - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - reg4a &= ~a_speed; - pci_write_config_byte(dev, 0x4a, reg4a | u_speed); - } else { - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); - pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); - } - - it8172_tune_drive(drive, it8172_dma_2_pio(speed)); - - if (!drive->init_speed) - drive->init_speed = speed; - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - return err; + switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA + case XFER_UDMA_4: + case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_5: + case XFER_UDMA_3: + case XFER_UDMA_1: //u_speed = 1 << (drive->dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + case XFER_SW_DMA_2: break; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_0: break; + default: return -1; + } + + if (speed >= XFER_UDMA_0) { + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + reg4a &= ~a_speed; + pci_write_config_byte(dev, 0x4a, reg4a | u_speed); + } else { + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); + } + + it8172_tune_drive(drive, it8172_dma_2_pio(speed)); + return (ide_config_drive_speed(drive, speed)); } +#ifdef CONFIG_BLK_DEV_IDEDMA static int it8172_config_chipset_for_dma (ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - byte speed; + struct hd_driveid *id = drive->id; + byte mode = it8172_ratemask(drive); + byte speed, tspeed, dma = 1; + + switch(mode) { + case 0x01: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + default: + tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL); + speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed); + dma = 0; + break; + } + + (void) it8172_tune_chipset(drive, speed); + +// return ((int)(dma) ? ide_dma_on : ide_dma_off_quietly); + return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} - if (id->dma_ultra & 0x0010) { - speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0008) { - speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0004) { - speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0002) { - speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0001) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_mword & 0x0001) { - speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else { - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 4, NULL); - } - - (void) it8172_tune_chipset(drive, speed); - - return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on : - ((id->dma_ultra >> 8) & 7) ? ide_dma_on : - ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : - ide_dma_off_quietly); +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + drive->init_speed = 0; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x007F) { + /* Force if Capable UltraDMA */ + dma_func = it8172_config_chipset_for_dma(drive); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x007)) { + /* Force if Capable regular DMA modes */ + dma_func = it8172_config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = it8172_config_chipset_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + it8172_tune_drive(drive, 5); + } + return HWIF(drive)->dmaproc(dma_func, drive); } static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - switch (func) { - case ide_dma_check: - return ide_dmaproc((ide_dma_action_t)it8172_config_chipset_for_dma(drive), - drive); - default : - break; - } - /* Other cases are done by generic IDE-DMA code. */ - return ide_dmaproc(func, drive); + switch (func) { + case ide_dma_check: + return config_drive_xfer_rate(drive); + default : + break; + } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); } - -#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */ +#endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name) { - unsigned char progif; + unsigned char progif; - /* - * Place both IDE interfaces into PCI "native" mode - */ - (void)pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); - (void)pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05); + /* + * Place both IDE interfaces into PCI "native" mode + */ + pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); + pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05); - return IT8172_IDE_IRQ; + return IT8172_IDE_IRQ; } void __init ide_init_it8172 (ide_hwif_t *hwif) { - struct pci_dev* dev = hwif->pci_dev; - unsigned long cmdBase, ctrlBase; + struct pci_dev* dev = hwif->pci_dev; + unsigned long cmdBase, ctrlBase; - hwif->tuneproc = &it8172_tune_drive; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - - if (!hwif->dma_base) - return; - -#ifndef CONFIG_BLK_DEV_IDEDMA - hwif->autodma = 0; -#else /* CONFIG_BLK_DEV_IDEDMA */ -#ifdef CONFIG_IT8172_TUNING - hwif->autodma = 1; - hwif->dmaproc = &it8172_dmaproc; - hwif->speedproc = &it8172_tune_chipset; -#endif /* CONFIG_IT8172_TUNING */ -#endif /* !CONFIG_BLK_DEV_IDEDMA */ + hwif->autodma = 0; + hwif->tuneproc = &it8172_tune_drive; + hwif->speedproc = &it8172_tune_chipset; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; - cmdBase = dev->resource[0].start; - ctrlBase = dev->resource[1].start; + cmdBase = dev->resource[0].start; + ctrlBase = dev->resource[1].start; - ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL); - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->noprobe = 0; + ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL); + memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); + hwif->noprobe = 0; + + if (!hwif->dma_base) + return; + +#ifdef CONFIG_BLK_DEV_IDEDMA + hwif->dmaproc = &it8172_dmaproc; +# ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +# endif /* CONFIG_IDEDMA_AUTO */ +#endif /* !CONFIG_BLK_DEV_IDEDMA */ +} + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_it8172 (struct pci_dev *dev, ide_pci_device_t *d) +{ + if ((!(PCI_FUNC(dev->devfn) & 1) || + (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))) + return; /* IT8172 is more than only a IDE controller */ + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); } + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/Makefile linux.20pre2-ac1/drivers/ide/Makefile --- linux.20pre2/drivers/ide/Makefile 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/Makefile 2002-08-06 15:42:11.000000000 +0100 @@ -10,7 +10,7 @@ O_TARGET := idedriver.o -export-objs := ide.o ide-features.o ide-probe.o ide-taskfile.o ataraid.o +export-objs := ide-taskfile.o ide.o ide-probe.o ataraid.o list-multi := ide-mod.o ide-probe-mod.o obj-y := @@ -27,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o +ide-obj-$(CONFIG_BLK_DEV_ADMA100) += adma100.o ide-obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o ide-obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o ide-obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o @@ -44,8 +45,8 @@ ide-obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o ide-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o -ide-obj-$(CONFIG_BLK_DEV_ADMA) += ide-adma.o ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI) += ide-dma.o +ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ide-m8xx.o ide-obj-$(CONFIG_BLK_DEV_IDEPCI) += ide-pci.o ide-obj-$(CONFIG_BLK_DEV_ISAPNP) += ide-pnp.o ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += ide-pmac.o @@ -56,7 +57,6 @@ ide-obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o ide-obj-$(CONFIG_BLK_DEV_PDC202XX) += pdc202xx.o ide-obj-$(CONFIG_BLK_DEV_PDC4030) += pdc4030.o -ide-obj-$(CONFIG_BLK_DEV_PDC_ADMA) += pdcadma.o ide-obj-$(CONFIG_BLK_DEV_PIIX) += piix.o ide-obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o @@ -67,7 +67,6 @@ ide-obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o ide-obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o ide-obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o -ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ide-m8xx.o # The virtualised raid layers MUST come after the ide itself or bad stuff # will happen. @@ -77,7 +76,7 @@ ide-obj-$(CONFIG_PROC_FS) += ide-proc.o -ide-mod-objs := ide.o ide-features.o ide-taskfile.o $(ide-obj-y) +ide-mod-objs := ide-taskfile.o ide.o $(ide-obj-y) ide-probe-mod-objs := ide-probe.o ide-geometry.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/ns87415.c linux.20pre2-ac1/drivers/ide/ns87415.c --- linux.20pre2/drivers/ide/ns87415.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/ns87415.c 2002-08-06 15:42:11.000000000 +0100 @@ -24,6 +24,10 @@ #include +#if defined(__hppa__) && defined(CONFIG_SUPERIO) +#include +#endif + static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; /* @@ -38,8 +42,7 @@ struct pci_dev *dev = hwif->pci_dev; unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); new = *old; /* Adjust IRQ enable bit */ @@ -73,7 +76,7 @@ udelay(10); } - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); } static void ns87415_selectproc (ide_drive_t *drive) @@ -90,17 +93,24 @@ switch (func) { case ide_dma_end: /* returns 1 on error, 0 otherwise */ drive->waiting_for_dma = 0; - dma_stat = inb(hwif->dma_base+2); - outb(inb(hwif->dma_base)&~1, hwif->dma_base); /* stop DMA */ - outb(inb(hwif->dma_base)|6, hwif->dma_base); /* from ERRATA: clear the INTR & ERROR bits */ - ide_destroy_dmatable(drive); /* and free any DMA resources */ - return (dma_stat & 7) != 4; /* verify good DMA status */ + dma_stat = IN_BYTE(hwif->dma_base+2); + /* stop DMA */ + OUT_BYTE(IN_BYTE(hwif->dma_base)&~1, hwif->dma_base); + /* from ERRATA: clear the INTR & ERROR bits */ + OUT_BYTE(IN_BYTE(hwif->dma_base)|6, hwif->dma_base); + /* and free any DMA resources */ + ide_destroy_dmatable(drive); + /* verify good DMA status */ + return (dma_stat & 7) != 4; case ide_dma_write: case ide_dma_read: - ns87415_prepare_drive(drive, 1); /* select DMA xfer */ - if (!ide_dmaproc(func, drive)) /* use standard DMA stuff */ + /* select DMA xfer */ + ns87415_prepare_drive(drive, 1); + /* use standard DMA stuff */ + if (!ide_dmaproc(func, drive)) return 0; - ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */ + /* DMA failed: select PIO xfer */ + ns87415_prepare_drive(drive, 0); return 1; case ide_dma_check: if (drive->media != ide_disk) @@ -122,6 +132,9 @@ byte stat; #endif + hwif->autodma = 0; + hwif->selectproc = &ns87415_selectproc; + /* Set a good latency timer and cache line size value. */ (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); #ifdef __sparc_v9__ @@ -164,30 +177,36 @@ * to SELECT_DRIVE() properly during first probe_hwif(). */ timeout = 10000; - outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]); + OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]); udelay(10); - outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]); + OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]); do { udelay(50); - stat = inb(hwif->io_ports[IDE_STATUS_OFFSET]); + stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); if (stat == 0xff) break; } while ((stat & BUSY_STAT) && --timeout); #endif } - if (hwif->dma_base) - outb(0x60, hwif->dma_base + 2); - if (!using_inta) +#if defined(__hppa__) && defined(CONFIG_SUPERIO) + hwif->irq = superio_get_ide_irq(); /* legacy mode */ +#else hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ +#endif else if (!hwif->irq && hwif->mate && hwif->mate->irq) hwif->irq = hwif->mate->irq; /* share IRQ with mate */ + if (!hwif->dma_base) + return; + #ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) - hwif->dmaproc = &ns87415_dmaproc; + OUT_BYTE(0x60, hwif->dma_base + 2); + hwif->dmaproc = &ns87415_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* CONFIG_BLK_DEV_IDEDMA */ - - hwif->selectproc = &ns87415_selectproc; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/opti621.c linux.20pre2-ac1/drivers/ide/opti621.c --- linux.20pre2/drivers/ide/opti621.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/opti621.c 2002-08-06 15:42:11.000000000 +0100 @@ -97,6 +97,7 @@ #include #include #include +#include #include #include @@ -183,11 +184,11 @@ * This is from setupvic.exe program. */ { - inw(reg_base+1); - inw(reg_base+1); - outb(3, reg_base+2); - outb(value, reg_base+reg); - outb(0x83, reg_base+2); + IN_WORD(reg_base+1); + IN_WORD(reg_base+1); + OUT_BYTE(3, reg_base+2); + OUT_BYTE(value, reg_base+reg); + OUT_BYTE(0x83, reg_base+2); } static byte read_reg(int reg) @@ -198,11 +199,11 @@ */ { byte ret; - inw(reg_base+1); - inw(reg_base+1); - outb(3, reg_base+2); - ret=inb(reg_base+reg); - outb(0x83, reg_base+2); + IN_WORD(reg_base+1); + IN_WORD(reg_base+1); + OUT_BYTE(3, reg_base+2); + ret=IN_BYTE(reg_base+reg); + OUT_BYTE(0x83, reg_base+2); return ret; } @@ -276,13 +277,12 @@ hwif->name, ax, second.data_time, second.recovery_time, drdy); #endif - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); reg_base = hwif->io_ports[IDE_DATA_OFFSET]; - outb(0xc0, reg_base+CNTRL_REG); /* allow Register-B */ - outb(0xff, reg_base+5); /* hmm, setupvic.exe does this ;-) */ - inb(reg_base+CNTRL_REG); /* if reads 0xff, adapter not exist? */ + OUT_BYTE(0xc0, reg_base+CNTRL_REG); /* allow Register-B */ + OUT_BYTE(0xff, reg_base+5); /* hmm, setupvic.exe does this ;-) */ + IN_BYTE(reg_base+CNTRL_REG); /* if reads 0xff, adapter not exist? */ read_reg(CNTRL_REG); /* if reads 0xc0, no interface exist? */ read_reg(STRAP_REG); /* read version, probably 0 */ @@ -302,7 +302,7 @@ write_reg(misc, MISC_REG); /* set address setup, DRDY timings, */ /* and read prefetch for both drives */ - restore_flags(flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); } /* @@ -310,7 +310,30 @@ */ void __init ide_init_opti621 (ide_hwif_t *hwif) { + hwif->autodma = 0; hwif->drives[0].drive_data = PIO_DONT_KNOW; hwif->drives[1].drive_data = PIO_DONT_KNOW; hwif->tuneproc = &opti621_tune_drive; + + /* safety call for Anton A */ + hwif->dma_base = 0; +} + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_opti621 (struct pci_dev *dev, ide_pci_device_t *d) +{ +#if 0 + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && + !(PCI_FUNC(dev->devfn) & 1)) +#else + if ((dev->device == PCI_DEVICE_ID_OPTI_82C558) && + (!(PCI_FUNC(dev->devfn) & 1))) +#endif + return; /* OPTI621 is more than only a IDE controller */ + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); } + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/pdc202xx.c linux.20pre2-ac1/drivers/ide/pdc202xx.c --- linux.20pre2/drivers/ide/pdc202xx.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/pdc202xx.c 2002-08-06 15:42:11.000000000 +0100 @@ -1,59 +1,33 @@ /* - * linux/drivers/ide/pdc202xx.c Version 0.32 Feb. 27, 2002 + * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002 * - * Copyright (C) 1998-2000 Andre Hedrick - * May be copied or modified under the terms of the GNU General Public License + * Copyright (C) 1998-2002 Andre Hedrick * - * Promise Ultra66 cards with BIOS v1.11 this + * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this * compiled into the kernel if you have more than one card installed. + * Note that BIOS v1.29 is reported to fix the problem. Since this is + * safe chipset tuning, including this support is harmless * - * Promise Ultra100 cards with BIOS v2.01 this + * Promise Ultra66 cards with BIOS v1.11 this * compiled into the kernel if you have more than one card installed. * - * Promise Ultra100TX2 with BIOS v2.10 & Ultra133TX2 with BIOS v2.20 - * support 8 hard drives on UDMA mode. + * Promise Ultra100 cards. * - * Linux kernel will misunderstand FastTrak ATA-RAID series as Ultra - * IDE Controller, UNLESS you enable "CONFIG_PDC202XX_FORCE" - * That's you can use FastTrak ATA-RAID controllers as IDE controllers. + * The latest chipset code will support the following :: + * Three Ultra33 controllers and 12 drives. + * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. + * The 8/4 ratio is a BIOS code limit by promise. * - * History : - * 05/22/01 v1.20 b1 - * (1) support PDC20268 - * (2) fix cable judge function - * 08/22/01 v1.20 b2 - * (1) support ATA-133 PDC20269/75 - * (2) support UDMA Mode 6 - * (3) fix proc report information - * (4) set ATA133 timing - * (5) fix ultra dma bit 14 selectable - * (6) support 32bit LBA - * 09/11/01 v1.20 b3 - * (1) fix eighty_ninty_three() - * (2) fix offset address 0x1c~0x1f - * 10/30/01 v1.20 b4 - * (1) fix 48bit LBA HOB bit - * (2) force rescan drive under PIO modes if need - * 11/02/01 v1.20.0.5 - * (1) could be patched with ext3 filesystem code - * 11/06/01 v1.20.0.6 - * (1) fix LBA48 drive running without Promise controllers - * (2) fix LBA48 drive running under PIO modes - * 01/28/02 v1.20.0.6 - * (1) release for linux IDE Group kernel 2.4.18 - * (2) add version and controller info to proc - * 05/23/02 v1.20.0.7 - * (1) disable PDC20262 running with 48bit - * (2) Add quirk drive lists for PDC20265/67 + * UNLESS you enable "CONFIG_PDC202XX_BURST" * - * Copyright (C) 1999-2002 Promise Technology, Inc. - * Author: Frank Tiernan - * PROMISE pdc202xx IDE Controller driver MAINTAINERS + */ + +/* + * Portions Copyright (C) 1999 Promise Technology, Inc. + * Author: Frank Tiernan (frankt@promise.com) * Released under terms of General Public License */ - -#define VERSION "1.20.0.7" -#define VERDATE "2002-05-23" + #include #include #include @@ -88,10 +62,60 @@ static int pdc202xx_get_info(char *, char **, off_t, int); extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); -static struct pci_dev *bmide_dev; -static struct hd_driveid *id[4]; -static int speed_rate[4]; + +byte pdc202xx_proc = 0; + +#define PDC202_MAX_DEVS 5 + +static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS]; +static int n_pdc202_devs; + +const char *pdc_quirk_drives[] = { + "QUANTUM FIREBALLlct08 08", + "QUANTUM FIREBALLP KA6.4", + "QUANTUM FIREBALLP KA9.1", + "QUANTUM FIREBALLP LM20.4", + "QUANTUM FIREBALLP KX13.6", + "QUANTUM FIREBALLP KX20.5", + "QUANTUM FIREBALLP KX27.3", + "QUANTUM FIREBALLP LM20.5", + NULL +}; + +char *pdc202xx_pio_verbose (u32 drive_pci) +{ + if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET"); + if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4"); + if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3"); + if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2"); + if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1"); + if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0"); + return("PIO ?"); +} + +char *pdc202xx_dma_verbose (u32 drive_pci) +{ + if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2"); + if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1"); + if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0"); + if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2"); + if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1"); + if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0"); + return("PIO---"); +} + +char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable) +{ + if ((drive_pci & 0x000ff000) == 0x000ff000) + return("NOTSET"); + if ((drive_pci & 0x00012000) == 0x00012000) + return((slow_cable) ? "UDMA 2" : "UDMA 4"); + if ((drive_pci & 0x00024000) == 0x00024000) + return((slow_cable) ? "UDMA 1" : "UDMA 3"); + if ((drive_pci & 0x00036000) == 0x00036000) + return("UDMA 0"); + return(pdc202xx_dma_verbose(drive_pci)); +} static char * pdc202xx_info (char *buf, struct pci_dev *dev) { @@ -99,10 +123,8 @@ u32 bibma = pci_resource_start(dev, 4); u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; - u16 reg50h = 0; - u16 word88 = 0; - int udmasel[4] = {0,0,0,0}, piosel[4] = {0,0,0,0}; - int i = 0, hd = 0; + u16 reg50h = 0, pmask = (1<<10), smask = (1<<11); + u8 hi = 0, lo = 0; /* * at that point bibma+0x2 et bibma+0xa are byte registers @@ -114,10 +136,10 @@ u8 sc11 = inb_p((unsigned short)bibma + 0x11); u8 sc1a = inb_p((unsigned short)bibma + 0x1a); u8 sc1b = inb_p((unsigned short)bibma + 0x1b); - /* u8 sc1c = inb_p((unsigned short)bibma + 0x1c); + u8 sc1c = inb_p((unsigned short)bibma + 0x1c); u8 sc1d = inb_p((unsigned short)bibma + 0x1d); u8 sc1e = inb_p((unsigned short)bibma + 0x1e); - u8 sc1f = inb_p((unsigned short)bibma + 0x1f); */ + u8 sc1f = inb_p((unsigned short)bibma + 0x1f); pci_read_config_word(dev, 0x50, ®50h); pci_read_config_dword(dev, 0x60, ®60h); @@ -125,95 +147,150 @@ pci_read_config_dword(dev, 0x68, ®68h); pci_read_config_dword(dev, 0x6c, ®6ch); - p+=sprintf(p, "\nPROMISE Ultra series driver Ver %s %s Adapter: ", VERSION, VERDATE); + p += sprintf(p, "\n "); switch(dev->device) { - case PCI_DEVICE_ID_PROMISE_20275: - p += sprintf(p, "MBUltra133\n"); - break; - case PCI_DEVICE_ID_PROMISE_20269: - p += sprintf(p, "Ultra133 TX2\n"); - break; - case PCI_DEVICE_ID_PROMISE_20268: - p += sprintf(p, "Ultra100 TX2\n"); - break; case PCI_DEVICE_ID_PROMISE_20267: - p += sprintf(p, "Ultra100\n"); - break; + p += sprintf(p, "Ultra100"); break; case PCI_DEVICE_ID_PROMISE_20265: - p += sprintf(p, "Ultra100 on M/B\n"); - break; + p += sprintf(p, "Ultra100 on M/B"); break; + case PCI_DEVICE_ID_PROMISE_20263: + p += sprintf(p, "FastTrak 66"); break; case PCI_DEVICE_ID_PROMISE_20262: - p += sprintf(p, "Ultra66\n"); - break; + p += sprintf(p, "Ultra66"); break; case PCI_DEVICE_ID_PROMISE_20246: - p += sprintf(p, "Ultra33\n"); + p += sprintf(p, "Ultra33"); reg50h |= 0x0c00; break; default: - p += sprintf(p, "Ultra Series\n"); - break; + p += sprintf(p, "Ultra Series"); break; } + p += sprintf(p, " Chipset.\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, "------------------------------- General Status " + "---------------------------------\n"); + p += sprintf(p, "Burst Mode : %sabled\n", + (sc1f & 0x01) ? "en" : "dis"); + p += sprintf(p, "Host Mode : %s\n", + (sc1f & 0x08) ? "Tri-Stated" : "Normal"); + p += sprintf(p, "Bus Clocking : %s\n", + ((sc1f & 0xC0) == 0xC0) ? "100 External" : + ((sc1f & 0x80) == 0x80) ? "66 External" : + ((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal"); + p += sprintf(p, "IO pad select : %s mA\n", + ((sc1c & 0x03) == 0x03) ? "10" : + ((sc1c & 0x02) == 0x02) ? "8" : + ((sc1c & 0x01) == 0x01) ? "6" : + ((sc1c & 0x00) == 0x00) ? "4" : "??"); + SPLIT_BYTE(sc1e, hi, lo); + p += sprintf(p, "Status Polling Period : %d\n", hi); + p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); p += sprintf(p, " %s %s\n", (c0&0x80)?"disabled":"enabled ", (c1&0x80)?"disabled":"enabled "); p += sprintf(p, "66 Clocking %s %s\n", (sc11&0x02)?"enabled ":"disabled", (sc11&0x08)?"enabled ":"disabled"); - p += sprintf(p, "Mode %s %s\n", + p += sprintf(p, " Mode %s Mode %s\n", (sc1a & 0x01) ? "MASTER" : "PCI ", (sc1b & 0x01) ? "MASTER" : "PCI "); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", - (id[0]!=NULL && (c0&0x20))?"yes":"no ",(id[1]!=NULL && (c0&0x40))?"yes":"no ", - (id[2]!=NULL && (c1&0x20))?"yes":"no ",(id[3]!=NULL && (c1&0x40))?"yes":"no "); - for( hd = 0; hd < 4 ; hd++) { - if (id[hd] == NULL) - continue; - word88 = id[hd]->dma_ultra; - for ( i = 7 ; i >= 0 ; i--) - if (word88 >> (i+8)) { - udmasel[hd] = i; /* get select UDMA mode */ - break; - } - piosel[hd] = (id[hd]->eide_pio_modes >= 0x02) ? 4 : 3; - } - p += sprintf(p, "UDMA Mode: %d %d %d %d\n", - udmasel[0], udmasel[1], udmasel[2], udmasel[3]); - p += sprintf(p, "PIO Mode: %d %d %d %d\n", - piosel[0], piosel[1], piosel[2], piosel[3]); + p += sprintf(p, " %s %s\n", + (sc1d & 0x08) ? "Error " : + ((sc1d & 0x05) == 0x05) ? "Not My INTR " : + (sc1d & 0x04) ? "Interrupting" : + (sc1d & 0x02) ? "FIFO Full " : + (sc1d & 0x01) ? "FIFO Empty " : "????????????", + (sc1d & 0x80) ? "Error " : + ((sc1d & 0x50) == 0x50) ? "Not My INTR " : + (sc1d & 0x40) ? "Interrupting" : + (sc1d & 0x20) ? "FIFO Full " : + (sc1d & 0x10) ? "FIFO Empty " : "????????????"); + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s " + " %s %s\n", + (c0&0x20)?"yes":"no ", (c0&0x40)?"yes":"no ", + (c1&0x20)?"yes":"no ", (c1&0x40)?"yes":"no "); + p += sprintf(p, "DMA Mode: %s %s " + " %s %s\n", + pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)), + pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)), + pdc202xx_ultra_verbose(reg68h, (reg50h & smask)), + pdc202xx_ultra_verbose(reg6ch, (reg50h & smask))); + p += sprintf(p, "PIO Mode: %s %s " + " %s %s\n", + pdc202xx_pio_verbose(reg60h), + pdc202xx_pio_verbose(reg64h), + pdc202xx_pio_verbose(reg68h), + pdc202xx_pio_verbose(reg6ch)); #if 0 p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n"); #endif return (char *)p; } +static char * pdc202xx_info_new (char *buf, struct pci_dev *dev) +{ + char *p = buf; +// u32 bibma = pci_resource_start(dev, 4); + +// u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0; +// u16 reg50h = 0, word88 = 0; +// int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0; + + p += sprintf(p, "\n "); + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + p += sprintf(p, "SBFastTrak 133 Lite"); break; + case PCI_DEVICE_ID_PROMISE_20276: + p += sprintf(p, "MBFastTrak 133 Lite"); break; + case PCI_DEVICE_ID_PROMISE_20275: + p += sprintf(p, "MBUltra133"); break; + case PCI_DEVICE_ID_PROMISE_20271: + p += sprintf(p, "FastTrak TX2000"); break; + case PCI_DEVICE_ID_PROMISE_20270: + p += sprintf(p, "FastTrak LP/TX2/TX4"); break; + case PCI_DEVICE_ID_PROMISE_20269: + p += sprintf(p, "Ultra133 TX2"); break; + case PCI_DEVICE_ID_PROMISE_20268: + p += sprintf(p, "Ultra100 TX2"); break; + default: + p += sprintf(p, "Ultra series"); break; + break; + } + p += sprintf(p, " Chipset.\n"); + return (char *)p; +} + static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - - p = pdc202xx_info(buffer, bmide_dev); + int i; + + for (i = 0; i < n_pdc202_devs; i++) { + struct pci_dev *dev = pdc202_devs[i]; + + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20268: + case PCI_DEVICE_ID_PROMISE_20270: + p = pdc202xx_info_new(buffer, dev); + break; + default: + p = pdc202xx_info(buffer, dev); + break; + } + } return p-buffer; /* => must be less than 4k! */ } #endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ -byte pdc202xx_proc = 0; - -const char *pdc_quirk_drives[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP KA9.1", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP KX13.6", - "QUANTUM FIREBALLP KX20.5", - "QUANTUM FIREBALLP KX27.3", - "QUANTUM FIREBALLP LM20.5", - NULL -}; - -extern char *ide_xfer_verbose (byte xfer_rate); - /* A Register */ #define SYNC_ERRDY_EN 0xC0 @@ -324,6 +401,69 @@ #endif /* PDC202XX_DECODE_REGISTER_INFO */ +#if 0 +static byte pdc202xx_ratemask (ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = 0x00; + + switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20269: + { mode |= 0x04; break; } + case PCI_DEVICE_ID_PROMISE_20270: + case PCI_DEVICE_ID_PROMISE_20268: + { mode |= 0x03; break; } + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + { mode |= 0x03; break; } + case PCI_DEVICE_ID_PROMISE_20263: + case PCI_DEVICE_ID_PROMISE_20262: + { mode |= 0x02; break; } + case PCI_DEVICE_ID_PROMISE_20246: + { mode |= 0x01; break; } + default: + return (mode &= ~0xF8); + } + + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + byte mode = pdc202xx_ratemask(drive); + + switch(mode) { + case 0x04: while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + +#else +static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed) +{ + return speed; +} +#endif + static int check_in_drive_lists (ide_drive_t *drive, const char **list) { struct hd_driveid *id = drive->id; @@ -344,13 +484,13 @@ return 0; } -static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed) +static int pdc202xx_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; + byte speed = pdc202xx_ratefilter(drive, xferspeed); unsigned int drive_conf; - int err = 0, i = 0, j = hwif->channel ? 2 : 0 ; byte drive_pci, AP, BP, CP, DP; byte TA = 0, TB = 0, TC = 0; @@ -362,7 +502,8 @@ default: return -1; } - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return -1; + if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) + return -1; pci_read_config_dword(dev, drive_pci, &drive_conf); pci_read_config_byte(dev, (drive_pci), &AP); @@ -370,59 +511,53 @@ pci_read_config_byte(dev, (drive_pci)|0x02, &CP); pci_read_config_byte(dev, (drive_pci)|0x03, &DP); -#ifdef CONFIG_BLK_DEV_IDEDMA - if (speed >= XFER_SW_DMA_0) { - if ((BP & 0xF0) && (CP & 0x0F)) { - /* clear DMA modes of upper 842 bits of B Register */ - /* clear PIO forced mode upper 1 bit of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - - /* clear DMA modes of lower 8421 bits of C Register */ - pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - } - } else { -#else - { -#endif /* CONFIG_BLK_DEV_IDEDMA */ + if (speed < XFER_SW_DMA_0) { if ((AP & 0x0F) || (BP & 0x07)) { /* clear PIO modes of lower 8421 bits of A Register */ - pci_write_config_byte(dev, (drive_pci), AP & ~0x0F); + pci_write_config_byte(dev, (drive_pci), AP &~0x0F); pci_read_config_byte(dev, (drive_pci), &AP); /* clear PIO modes of lower 421 bits of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07); + pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); } +#ifdef CONFIG_BLK_DEV_IDEDMA + } else { + if ((BP & 0xF0) && (CP & 0x0F)) { + /* clear DMA modes of upper 842 bits of B Register */ + /* clear PIO forced mode upper 1 bit of B Register */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + + /* clear DMA modes of lower 8421 bits of C Register */ + pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + } +#endif /* CONFIG_BLK_DEV_IDEDMA */ } pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - for ( i = 0; i < 2; i++) - if (hwif->drives[i].present) - id[i+j] = hwif->drives[i].id; /* get identify structs */ - switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA /* case XFER_UDMA_6: */ case XFER_UDMA_5: - case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; /* speed 8 == UDMA mode 4 */ - case XFER_UDMA_3: TB = 0x40; TC = 0x02; break; /* speed 7 == UDMA mode 3 */ - case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; /* speed 6 == UDMA mode 2 */ - case XFER_UDMA_1: TB = 0x40; TC = 0x02; break; /* speed 5 == UDMA mode 1 */ - case XFER_UDMA_0: TB = 0x60; TC = 0x03; break; /* speed 4 == UDMA mode 0 */ - case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break; /* speed 4 == MDMA mode 2 */ - case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break; /* speed 3 == MDMA mode 1 */ - case XFER_MW_DMA_0: TB = 0x60; TC = 0x05; break; /* speed 2 == MDMA mode 0 */ - case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break; /* speed 0 == SDMA mode 2 */ - case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break; /* speed 1 == SDMA mode 1 */ - case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break; /* speed 0 == SDMA mode 0 */ + case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; + case XFER_UDMA_3: TB = 0x40; TC = 0x02; break; + case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; + case XFER_UDMA_1: TB = 0x40; TC = 0x02; break; + case XFER_UDMA_0: TB = 0x60; TC = 0x03; break; + case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break; + case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break; + case XFER_MW_DMA_0: TB = 0x60; TC = 0x05; break; + case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break; + case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break; + case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break; #endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: TA = 0x01; TB = 0x04; break; case XFER_PIO_3: TA = 0x02; TB = 0x06; break; @@ -432,16 +567,14 @@ default: TA = 0x09; TB = 0x13; break; } + if (speed < XFER_SW_DMA_0) { + pci_write_config_byte(dev, (drive_pci), AP|TA); + pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); #ifdef CONFIG_BLK_DEV_IDEDMA - if (speed >= XFER_SW_DMA_0) { + } else { pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); - } else { -#else - { #endif /* CONFIG_BLK_DEV_IDEDMA */ - pci_write_config_byte(dev, (drive_pci), AP|TA); - pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); } #if PDC202XX_DECODE_REGISTER_INFO @@ -455,12 +588,6 @@ decode_registers(REG_C, CP); decode_registers(REG_D, DP); #endif /* PDC202XX_DECODE_REGISTER_INFO */ - - if (!drive->init_speed) - drive->init_speed = speed; - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - #if PDC202XX_DEBUG_DRIVE_INFO printk("%s: %s drive%d 0x%08x ", drive->name, ide_xfer_verbose(speed), @@ -468,10 +595,11 @@ pci_read_config_dword(dev, drive_pci, &drive_conf); printk("0x%08x\n", drive_conf); #endif /* PDC202XX_DEBUG_DRIVE_INFO */ - return err; + + return (ide_config_drive_speed(drive, speed)); } -static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed) +static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); #ifdef CONFIG_BLK_DEV_IDEDMA @@ -485,158 +613,139 @@ #endif /* CONFIG_BLK_DEV_IDEDMA */ byte thold = 0x10; byte adj = (drive->dn%2) ? 0x08 : 0x00; - int set_speed = 0, i=0, j=hwif->channel ? 2:0; - int err; + byte speed = pdc202xx_ratefilter(drive, xferspeed); - /* Setting tHOLD bit to 0 if using UDMA mode 2 */ +#ifdef CONFIG_BLK_DEV_IDEDMA if (speed == XFER_UDMA_2) { OUT_BYTE((thold + adj), indexreg); OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg); } - - /* We need to set ATA133 timing if ATA133 drives exist */ - if (speed>=XFER_UDMA_6) - set_speed=1; +#endif /* CONFIG_BLK_DEV_IDEDMA */ - if (!drive->init_speed) - drive->init_speed = speed; -#if PDC202XX_DEBUG_DRIVE_INFO - printk("%s: Before set_feature = %s, word88 = %#x\n", - drive->name, ide_xfer_verbose(speed), drive->id->dma_ultra ); -#endif /* PDC202XX_DEBUG_DRIVE_INFO */ - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - for ( i = 0 ; i < 2 ; i++) - if (hwif->drives[i].present) { - id[i+j] = hwif->drives[i].id; /* get identify structs */ - speed_rate[i+j] = speed; /* get current speed */ - } - if (set_speed) { - for (i=0; i<4; i++) { - if (id[i]==NULL) - continue; - switch(speed_rate[i]) { + switch (speed) { #ifdef CONFIG_BLK_DEV_IDEDMA - case XFER_UDMA_6: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x01, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcb, datareg); - break; - case XFER_UDMA_5: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x02, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcb, datareg); - break; - case XFER_UDMA_4: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x03, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); - break; - case XFER_UDMA_3: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x1a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x05, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); - break; - case XFER_UDMA_2: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x2a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x07, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xcd, datareg); - break; - case XFER_UDMA_1: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x3a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x0a, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xd0, datareg); - break; - case XFER_UDMA_0: - OUT_BYTE((0x10 + adj), indexreg); - OUT_BYTE(0x4a, datareg); - OUT_BYTE((0x11 + adj), indexreg); - OUT_BYTE(0x0f, datareg); - OUT_BYTE((0x12 + adj), indexreg); - OUT_BYTE(0xd5, datareg); - break; - case XFER_MW_DMA_2: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0x69, datareg); - OUT_BYTE((0x0f + adj), indexreg); - OUT_BYTE(0x25, datareg); - break; - case XFER_MW_DMA_1: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0x6b, datareg); - OUT_BYTE((0x0f+ adj), indexreg); - OUT_BYTE(0x27, datareg); - break; - case XFER_MW_DMA_0: - OUT_BYTE((0x0e + adj), indexreg); - OUT_BYTE(0xdf, datareg); - OUT_BYTE((0x0f + adj), indexreg); - OUT_BYTE(0x5f, datareg); - break; + case XFER_UDMA_7: + speed = XFER_UDMA_6; + case XFER_UDMA_6: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x1a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x01, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcb, datareg); + break; + case XFER_UDMA_5: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x1a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x02, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcb, datareg); + break; + case XFER_UDMA_4: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x1a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x03, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcd, datareg); + break; + case XFER_UDMA_3: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x1a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x05, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcd, datareg); + break; + case XFER_UDMA_2: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x2a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x07, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xcd, datareg); + break; + case XFER_UDMA_1: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x3a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x0a, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xd0, datareg); + break; + case XFER_UDMA_0: + OUT_BYTE((0x10 + adj), indexreg); + OUT_BYTE(0x4a, datareg); + OUT_BYTE((0x11 + adj), indexreg); + OUT_BYTE(0x0f, datareg); + OUT_BYTE((0x12 + adj), indexreg); + OUT_BYTE(0xd5, datareg); + break; + case XFER_MW_DMA_2: + OUT_BYTE((0x0e + adj), indexreg); + OUT_BYTE(0x69, datareg); + OUT_BYTE((0x0f + adj), indexreg); + OUT_BYTE(0x25, datareg); + break; + case XFER_MW_DMA_1: + OUT_BYTE((0x0e + adj), indexreg); + OUT_BYTE(0x6b, datareg); + OUT_BYTE((0x0f+ adj), indexreg); + OUT_BYTE(0x27, datareg); + break; + case XFER_MW_DMA_0: + OUT_BYTE((0x0e + adj), indexreg); + OUT_BYTE(0xdf, datareg); + OUT_BYTE((0x0f + adj), indexreg); + OUT_BYTE(0x5f, datareg); + break; #endif /* CONFIG_BLK_DEV_IDEDMA */ - case XFER_PIO_4: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x23, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x09, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x25, datareg); - break; - case XFER_PIO_3: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x27, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x0d, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x35, datareg); - break; - case XFER_PIO_2: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x23, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x26, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0x64, datareg); - break; - case XFER_PIO_1: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0x46, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x29, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0xa4, datareg); - break; - case XFER_PIO_0: - OUT_BYTE((0x0c + adj), indexreg); - OUT_BYTE(0xfb, datareg); - OUT_BYTE((0x0d + adj), indexreg); - OUT_BYTE(0x2b, datareg); - OUT_BYTE((0x13 + adj), indexreg); - OUT_BYTE(0xac, datareg); - break; - default: - } - } + case XFER_PIO_4: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0x23, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x09, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0x25, datareg); + break; + case XFER_PIO_3: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0x27, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x0d, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0x35, datareg); + break; + case XFER_PIO_2: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0x23, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x26, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0x64, datareg); + break; + case XFER_PIO_1: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0x46, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x29, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0xa4, datareg); + break; + case XFER_PIO_0: + OUT_BYTE((0x0c + adj), indexreg); + OUT_BYTE(0xfb, datareg); + OUT_BYTE((0x0d + adj), indexreg); + OUT_BYTE(0x2b, datareg); + OUT_BYTE((0x13 + adj), indexreg); + OUT_BYTE(0xac, datareg); + break; + default: + ; } - return err; + + return (ide_config_drive_speed(drive, speed)); } /* 0 1 2 3 4 5 6 7 8 @@ -662,9 +771,10 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA -static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; +// byte mode = pdc202xx_ratemask(drive); ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; unsigned long high_16 = pci_resource_start(dev, 4); @@ -674,65 +784,68 @@ byte iordy = 0x13; byte adj = (drive->dn%2) ? 0x08 : 0x00; byte cable = 0; - byte new_chip = 0; - byte unit = (drive->select.b.unit & 0x01); + byte jumpbit = 0; unsigned int drive_conf; byte drive_pci = 0; byte test1, test2, speed = -1; byte AP; unsigned short EP; byte CLKSPD = 0; - byte clockreg = high_16 + 0x11; - byte udma_33 = ultra; - byte udma_66 = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0; + byte udma_33 = 1; + byte udma_66 = (eighty_ninty_three(drive)) ? 1 : 0; byte udma_100 = 0; byte udma_133 = 0; - byte mask = hwif->channel ? 0x08 : 0x02; + byte mask = hwif->channel ? 0x08 : 0x02; unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10); byte ultra_66 = ((id->dma_ultra & 0x0010) || (id->dma_ultra & 0x0008)) ? 1 : 0; - byte ultra_100 = ((id->dma_ultra & 0x0020) || - (ultra_66)) ? 1 : 0; - byte ultra_133 = ((id->dma_ultra & 0x0040) || - (ultra_100)) ? 1 : 0; switch(dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20269: udma_133 = (udma_66) ? 1 : 0; udma_100 = (udma_66) ? 1 : 0; OUT_BYTE(0x0b, (hwif->dma_base + 1)); cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04)); - new_chip = 1; + jumpbit = 1; break; - case PCI_DEVICE_ID_PROMISE_20268: case PCI_DEVICE_ID_PROMISE_20270: + udma_100 = 1; + udma_66 = 1; + OUT_BYTE(0x0b, (hwif->dma_base + 1)); + cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04)); + jumpbit = 1; + break; + case PCI_DEVICE_ID_PROMISE_20268: udma_100 = (udma_66) ? 1 : 0; OUT_BYTE(0x0b, (hwif->dma_base + 1)); cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04)); - new_chip = 1; + jumpbit = 1; break; case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: udma_100 = (udma_66) ? 1 : 0; pci_read_config_word(dev, 0x50, &EP); cable = (EP & c_mask); - new_chip = 0; - CLKSPD = IN_BYTE(clockreg); + jumpbit = 0; break; + case PCI_DEVICE_ID_PROMISE_20263: case PCI_DEVICE_ID_PROMISE_20262: pci_read_config_word(dev, 0x50, &EP); cable = (EP & c_mask); - new_chip = 0; - CLKSPD = IN_BYTE(clockreg); + jumpbit = 0; break; default: - udma_100 = 0; udma_133 = 0; cable = 0; new_chip = 1; + udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0; break; } + if (!jumpbit) + CLKSPD = IN_BYTE(high_16 + 0x11); /* * Set the control register to use the 66Mhz system * clock for UDMA 3/4 mode operation. If one drive on @@ -746,41 +859,50 @@ * parameters. */ - if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) { -#ifdef DEBUG - printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary"); + if ((ultra_66) && (cable)) { +//#ifdef DEBUG +#if 1 + printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 " + "requires an 80-pin cable for Ultra66 operation.\n", + hwif->channel ? "Secondary" : "Primary"); printk(" Switching to Ultra33 mode.\n"); #endif /* DEBUG */ /* Primary : zero out second bit */ /* Secondary : zero out fourth bit */ - //if (!new_chip) - OUT_BYTE(CLKSPD & ~mask, clockreg); + if (!jumpbit) + OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary"); printk("%s reduced to Ultra33 mode.\n", drive->name); - udma_66 = 0; udma_100 = 0; udma_133 = 0; + udma_66 = 0; } else { - if ((ultra_66) || (ultra_100) || (ultra_133)) { + if (ultra_66) { /* * check to make sure drive on same channel * is u66 capable */ if (hwif->drives[!(drive->dn%2)].id) { - if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) || - (hwif->drives[!(drive->dn%2)].id->dma_ultra -& 0x0020) || - (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) || - (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) { - OUT_BYTE(CLKSPD | mask, clockreg); + if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) { + if (!jumpbit) + OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } else { - OUT_BYTE(CLKSPD & ~mask, clockreg); + if (!jumpbit) + OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); } } else { /* udma4 drive by itself */ - OUT_BYTE(CLKSPD | mask, clockreg); + if (!jumpbit) + OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } } } - if (new_chip) goto chipset_is_set; + if (jumpbit) { + if (drive->media != ide_disk) return ide_dma_off_quietly; + if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ + OUT_BYTE((iordy + adj), indexreg); + OUT_BYTE((IN_BYTE(datareg)|0x03), datareg); + } + goto jumpbit_is_set; + } switch(drive->dn) { case 0: drive_pci = 0x60; @@ -823,24 +945,20 @@ chipset_is_set: - if (drive->media != ide_disk) + if (drive->media != ide_disk) { + hwif->tuneproc(drive, 5); return ide_dma_off_quietly; - - if (new_chip) { - if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ - OUT_BYTE((iordy + adj), indexreg); - OUT_BYTE((IN_BYTE(datareg)|0x03), datareg); - } - } - else { - pci_read_config_byte(dev, (drive_pci), &AP); - if (id->capability & 4) /* IORDY_EN */ - pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); - pci_read_config_byte(dev, (drive_pci), &AP); - if (drive->media == ide_disk) /* PREFETCH_EN */ - pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); } + pci_read_config_byte(dev, (drive_pci), &AP); + if (id->capability & 4) /* IORDY_EN */ + pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); + pci_read_config_byte(dev, (drive_pci), &AP); + if (drive->media == ide_disk) /* PREFETCH_EN */ + pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); + +jumpbit_is_set: + if ((id->dma_ultra & 0x0040)&&(udma_133)) speed = XFER_UDMA_6; else if ((id->dma_ultra & 0x0020)&&(udma_100)) speed = XFER_UDMA_5; else if ((id->dma_ultra & 0x0010)&&(udma_66)) speed = XFER_UDMA_4; @@ -851,17 +969,17 @@ else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; - else if ((id->dma_1word & 0x0004)&&(!new_chip)) speed = XFER_SW_DMA_2; - else if ((id->dma_1word & 0x0002)&&(!new_chip)) speed = XFER_SW_DMA_1; - else if ((id->dma_1word & 0x0001)&&(!new_chip)) speed = XFER_SW_DMA_0; + else if ((id->dma_1word & 0x0004)&&(!jumpbit)) speed = XFER_SW_DMA_2; + else if ((id->dma_1word & 0x0002)&&(!jumpbit)) speed = XFER_SW_DMA_1; + else if ((id->dma_1word & 0x0001)&&(!jumpbit)) speed = XFER_SW_DMA_0; else { /* restore original pci-config space */ - if (!new_chip) + if (!jumpbit) pci_write_config_dword(dev, drive_pci, drive_conf); + hwif->tuneproc(drive, 5); return ide_dma_off_quietly; } - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); (void) hwif->speedproc(drive, speed); return ((int) ((id->dma_ultra >> 14) & 3) ? ide_dma_on : @@ -874,9 +992,11 @@ static int config_drive_xfer_rate (ide_drive_t *drive) { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - ide_dma_action_t dma_func = ide_dma_off_quietly; + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + ide_dma_action_t dma_func = ide_dma_off_quietly; + + drive->init_speed = 0; if (id && (id->capability & 1) && hwif->autodma) { /* Consult the list of known "bad" drives */ @@ -888,7 +1008,7 @@ if (id->field_valid & 4) { if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; @@ -898,7 +1018,7 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } @@ -907,7 +1027,7 @@ goto no_dma_set; } /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } else { @@ -917,10 +1037,10 @@ fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - (void) config_chipset_for_pio(drive, 5); + hwif->tuneproc(drive, 5); } - return HWIF(drive)->dmaproc(dma_func, drive); + return hwif->dmaproc(dma_func, drive); } int pdc202xx_quirkproc (ide_drive_t *drive) @@ -941,15 +1061,17 @@ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; unsigned long high_16 = pci_resource_start(dev, 4); + unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); unsigned long dma_base = hwif->dma_base; - unsigned long atapi_port= hwif->channel ? high_16+0x24 : high_16+0x20; switch (dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20270: case PCI_DEVICE_ID_PROMISE_20269: case PCI_DEVICE_ID_PROMISE_20268: - case PCI_DEVICE_ID_PROMISE_20270: newchip = 1; break; case PCI_DEVICE_ID_PROMISE_20267: @@ -969,29 +1091,21 @@ * The Promise Ultra33 doesn't work correctly when * we do this part before issuing the drive cmd. */ - /* Enable ATAPI UDMA port for 48bit data on PDC20267 */ - if ((drive->addressing) && (hardware48fix)) { + if ((drive->addressing == 1) && (hardware48fix)) { struct request *rq = HWGROUP(drive)->rq; unsigned long word_count = 0; - unsigned long hankval = 0; - byte clockreg = high_16 + 0x11; - - OUT_BYTE(clock|(hwif->channel ? 0x08:0x02), clockreg); + + OUT_BYTE(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11); word_count = (rq->nr_sectors << 8); - hankval = (rq->cmd == READ) ? 0x05<<24 : 0x06<<24; - hankval = hankval | word_count ; - outl(hankval, atapi_port); - } + word_count = (rq->cmd == READ) ? word_count | 0x05000000 : word_count | 0x06000000; + outl(word_count, atapi_reg); + } break; case ide_dma_end: - /* Disable ATAPI UDMA port for 48bit data on PDC20267 */ - if ((drive->addressing) && (hardware48fix)) { - unsigned long hankval = 0; - byte clockreg = high_16 + 0x11; - - outl(hankval, atapi_port); /* zero out extra */ - clock = IN_BYTE(clockreg); - OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), clockreg); + if ((drive->addressing == 1) && (hardware48fix)) { + outl(0, atapi_reg); /* zero out extra */ + clock = IN_BYTE(high_16 + 0x11); + OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11); } break; case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ @@ -1000,7 +1114,7 @@ return (dma_stat & 4) == 4; sc1d = IN_BYTE(high_16 + 0x001d); - if (HWIF(drive)->channel) { + if (hwif->channel) { if ((sc1d & 0x50) == 0x50) goto somebody_else; else if ((sc1d & 0x40) == 0x40) return (dma_stat & 4) == 4; @@ -1013,8 +1127,8 @@ return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ case ide_dma_lostirq: case ide_dma_timeout: - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); + if (hwif->resetproc != NULL) + hwif->resetproc(drive); default: break; } @@ -1022,16 +1136,38 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ -void pdc202xx_reset (ide_drive_t *drive) +void pdc202xx_new_reset (ide_drive_t *drive) { - OUT_BYTE(0x04,IDE_CONTROL_REG); - mdelay(1000); - OUT_BYTE(0x00,IDE_CONTROL_REG); - mdelay(1000); + /* + * Deleted this because it is redundant from the caller. + */ printk("PDC202XX: %s channel reset.\n", HWIF(drive)->channel ? "Secondary" : "Primary"); } +void pdc202xx_reset_pci (struct pci_dev *dev) +{ + unsigned long high_16 = pci_resource_start(dev, 4); + byte udma_speed_flag = IN_BYTE(high_16 + 0x001f); + + OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); + mdelay(100); + OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); + mdelay(2000); /* 2 seconds ?! */ +} + +void pdc202xx_reset_host (ide_hwif_t *hwif) +{ + pdc202xx_reset_pci(hwif->pci_dev); + printk("PDC202XX: %s channel reset.\n", + hwif->channel ? "Secondary" : "Primary"); +} + +void pdc202xx_reset (ide_drive_t *drive) +{ + pdc202xx_reset_host(HWIF(drive)); +} + /* * Since SUN Cobalt is attempting to do this operation, I should disclose * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date @@ -1042,7 +1178,7 @@ #if 0 ide_hwif_t *hwif = HWIF(drive); unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); - byte sc1f = inb(high_16 + 0x001f); + byte sc1f = IN_BYTE(high_16 + 0x001f); if (!hwif) return -EINVAL; @@ -1050,9 +1186,9 @@ // hwif->bus_state = state; if (state) { - outb(sc1f | 0x08, high_16 + 0x001f); + OUT_BYTE(sc1f | 0x08, high_16 + 0x001f); } else { - outb(sc1f & ~0x08, high_16 + 0x001f); + OUT_BYTE(sc1f & ~0x08, high_16 + 0x001f); } #endif return 0; @@ -1064,17 +1200,58 @@ byte udma_speed_flag = IN_BYTE(high_16 + 0x001f); byte primary_mode = IN_BYTE(high_16 + 0x001a); byte secondary_mode = IN_BYTE(high_16 + 0x001b); - - OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f); - mdelay(100); - OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f); - mdelay(2000); /* 2 seconds ?! */ + byte newchip = 0; if (dev->resource[PCI_ROM_RESOURCE].start) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); + pci_write_config_dword(dev, PCI_ROM_ADDRESS, + dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + printk("%s: ROM enabled at 0x%08lx\n", + name, dev->resource[PCI_ROM_RESOURCE].start); } - + + switch (dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20269: + case PCI_DEVICE_ID_PROMISE_20270: + case PCI_DEVICE_ID_PROMISE_20268: + newchip = 1; + break; + case PCI_DEVICE_ID_PROMISE_20267: + case PCI_DEVICE_ID_PROMISE_20265: + pdc202xx_reset_pci(dev); + break; + case PCI_DEVICE_ID_PROMISE_20263: + case PCI_DEVICE_ID_PROMISE_20262: + /* + * software reset - this is required because the bios + * will set UDMA timing on if the hdd supports it. The + * user may want to turn udma off. A bug in the pdc20262 + * is that it cannot handle a downgrade in timing from + * UDMA to DMA. Disk accesses after issuing a set + * feature command will result in errors. A software + * reset leaves the timing registers intact, + * but resets the drives. + */ + pdc202xx_reset_pci(dev); + default: + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { + byte irq = 0, irq2 = 0; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); /* 0xbc */ + if (irq != irq2) { + pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ + printk("%s: pci-config space interrupt mirror fixed.\n", name); + } + } + break; + } + + if (newchip) + goto fttk_tx_series; + printk("%s: (U)DMA Burst Bit %sABLED " \ "Primary %s Mode " \ "Secondary %s Mode.\n", @@ -1107,13 +1284,17 @@ } #endif /* CONFIG_PDC202XX_MASTER */ +fttk_tx_series: + + pdc202_devs[n_pdc202_devs++] = dev; + #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) if (!pdc202xx_proc) { pdc202xx_proc = 1; - bmide_dev = dev; pdc202xx_display_info = &pdc202xx_get_info; } #endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } @@ -1122,19 +1303,21 @@ unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10); unsigned short CIS; - switch(hwif->pci_dev->device) { + switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20269: case PCI_DEVICE_ID_PROMISE_20268: case PCI_DEVICE_ID_PROMISE_20270: OUT_BYTE(0x0b, (hwif->dma_base + 1)); return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04)); - /* check 80pin cable */ + case PCI_DEVICE_ID_PROMISE_20267: + hwif->addressing = (hwif->channel) ? 0 : 1; default: pci_read_config_word(hwif->pci_dev, 0x50, &CIS); return (!(CIS & mask)); - /* check 80pin cable */ } } @@ -1142,47 +1325,98 @@ { hwif->tuneproc = &pdc202xx_tune_drive; hwif->quirkproc = &pdc202xx_quirkproc; - hwif->resetproc = &pdc202xx_reset; + + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + hwif->autodma = 0; + +#undef CONFIG_PDC202XX_32_UNMASK +#ifdef CONFIG_PDC202XX_32_UNMASK + hwif->drives[0].io_32bit = 1; + hwif->drives[1].io_32bit = 1; + hwif->drives[0].unmask = 1; + hwif->drives[1].unmask = 1; +#endif /* CONFIG_PDC202XX_32_UNMASK */ switch(hwif->pci_dev->device) { + case PCI_DEVICE_ID_PROMISE_20277: case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20269: case PCI_DEVICE_ID_PROMISE_20268: case PCI_DEVICE_ID_PROMISE_20270: hwif->speedproc = &pdc202xx_new_tune_chipset; + hwif->resetproc = &pdc202xx_new_reset; break; case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: + case PCI_DEVICE_ID_PROMISE_20263: case PCI_DEVICE_ID_PROMISE_20262: hwif->busproc = &pdc202xx_tristate; + hwif->resetproc = &pdc202xx_reset; case PCI_DEVICE_ID_PROMISE_20246: hwif->speedproc = &pdc202xx_tune_chipset; default: break; } -#undef CONFIG_PDC202XX_32_UNMASK -#ifdef CONFIG_PDC202XX_32_UNMASK - hwif->drives[0].io_32bit = 1; - hwif->drives[1].io_32bit = 1; - hwif->drives[0].unmask = 1; - hwif->drives[1].unmask = 1; -#endif /* CONFIG_PDC202XX_32_UNMASK */ + if (!hwif->dma_base) + return; #ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) { - hwif->dmaproc = &pdc202xx_dmaproc; - if (!noautodma) - hwif->autodma = 1; - } else { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - hwif->autodma = 0; - } -#else /* !CONFIG_BLK_DEV_IDEDMA */ - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - hwif->autodma = 0; + hwif->dmaproc = &pdc202xx_dmaproc; +# ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +# endif /* CONFIG_IDEDMA_AUTO */ #endif /* CONFIG_BLK_DEV_IDEDMA */ } + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d) +{ + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); +} + +void __init fixup_device_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d) +{ + struct pci_dev *dev2 = NULL, *findev; + ide_pci_device_t *d2; + + if ((dev->bus->self && + dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && + (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) { + if (PCI_SLOT(dev->devfn) & 2) { + return; + } + d->extra = 0; + pci_for_each_dev(findev) { + if ((findev->vendor == dev->vendor) && + (findev->device == dev->device) && + (PCI_SLOT(findev->devfn) & 2)) { + byte irq = 0, irq2 = 0; + dev2 = findev; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2); + if (irq != irq2) { + dev2->irq = dev->irq; + pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq); + } + } + } + } + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); + if (!dev2) + return; + d2 = d; + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d2->name, dev2->bus->number, dev2->devfn); + ide_setup_pci_device(dev2, d2); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/pdc4030.c linux.20pre2-ac1/drivers/ide/pdc4030.c --- linux.20pre2/drivers/ide/pdc4030.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/pdc4030.c 2002-08-06 15:42:11.000000000 +0100 @@ -89,12 +89,6 @@ #include "pdc4030.h" -#ifdef CONFIG_IDE_TASKFILE_IO -# define __TASKFILE__IO -#else /* CONFIG_IDE_TASKFILE_IO */ -# undef __TASKFILE__IO -#endif /* CONFIG_IDE_TASKFILE_IO */ - /* * promise_selectproc() is invoked by ide.c * in preparation for access to the specified drive. @@ -174,7 +168,8 @@ if (hwif->chipset == ide_pdc4030) /* we've already been found ! */ return 1; - if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) { + if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || + IN_BYTE(IDE_SECTOR_REG) == 0xFF) { return 0; } if (IDE_CONTROL_REG) @@ -187,7 +182,7 @@ "%s: Failed Promise read config!\n",hwif->name); return 0; } - ide_input_data(drive,&ident,SECTOR_WORDS); + ata_input_data(drive, &ident, SECTOR_WORDS); if (ident.id[1] != 'P' || ident.id[0] != 'T') { return 0; } @@ -240,7 +235,7 @@ #ifdef DEBUG printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i); -#endif +#endif /* DEBUG */ ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL); memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports)); h->noprobe = (h-1)->noprobe; @@ -313,10 +308,13 @@ int total_remaining; unsigned int sectors_left, sectors_avail, nsect; struct request *rq; +#ifdef CONFIG_IDE_TASKFILE_IO + unsigned long flags; + char *to; +#endif /* CONFIG_IDE_TASKFILE_IO */ - if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { - return ide_error(drive, "promise_read_intr", stat); - } + if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) + return DRIVER(drive)->error(drive, "promise_read_intr", stat); read_again: do { @@ -334,20 +332,36 @@ if (nsect > sectors_avail) nsect = sectors_avail; sectors_avail -= nsect; - ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); +#ifdef CONFIG_IDE_TASKFILE_IO + to = ide_map_buffer(rq, &flags); + ata_input_data(drive, to, nsect * SECTOR_WORDS); +#else /* !CONFIG_IDE_TASKFILE_IO */ + ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); +#endif /* CONFIG_IDE_TASKFILE_IO */ + #ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), " "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector, - rq->sector+nsect-1, (unsigned long) rq->buffer, + rq->sector+nsect-1, +#ifdef CONFIG_IDE_TASKFILE_IO + (unsigned long) to, +#else /* !CONFIG_IDE_TASKFILE_IO */ + (unsigned long) rq->buffer, +#endif /* CONFIG_IDE_TASKFILE_IO */ rq->nr_sectors-nsect); -#endif - rq->sector += nsect; +#endif /* DEBUG_READ */ + +#ifdef CONFIG_IDE_TASKFILE_IO + ide_unmap_buffer(to, &flags); +#else /* !CONFIG_IDE_TASKFILE_IO */ rq->buffer += nsect<<9; +#endif /* CONFIG_IDE_TASKFILE_IO */ + rq->sector += nsect; rq->errors = 0; rq->nr_sectors -= nsect; total_remaining = rq->nr_sectors; if ((rq->current_nr_sectors -= nsect) <= 0) { - ide_end_request(1, HWGROUP(drive)); + DRIVER(drive)->end_request(drive, 1); } /* * Now the data has been read in, do the following: @@ -367,16 +381,18 @@ if (stat & DRQ_STAT) goto read_again; if (stat & BUSY_STAT) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL); #ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: waiting for" "interrupt\n", drive->name); -#endif +#endif /* DEBUG_READ */ return ide_started; } printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left " "!DRQ !BUSY\n", drive->name); - return ide_error(drive, "promise read intr", stat); + return DRIVER(drive)->error(drive, "promise read intr", stat); } return ide_stopped; } @@ -397,27 +413,95 @@ if (GET_STAT() & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); return ide_started; /* continue polling... */ } hwgroup->poll_timeout = 0; printk(KERN_ERR "%s: completion timeout - still busy!\n", drive->name); - return ide_error(drive, "busy timeout", GET_STAT()); + return DRIVER(drive)->error(drive, "busy timeout", GET_STAT()); } hwgroup->poll_timeout = 0; #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name); -#endif +#endif /* DEBUG_WRITE */ for (i = rq->nr_sectors; i > 0; ) { i -= rq->current_nr_sectors; - ide_end_request(1, hwgroup); + DRIVER(drive)->end_request(drive, 1); } return ide_stopped; } /* + * promise_multwrite() transfers a block of up to mcount sectors of data + * to a drive as part of a disk multiple-sector write operation. + * + * Returns 0 on success. + * + * Note that we may be called from two contexts - the do_rw_disk context + * and IRQ context. The IRQ can happen any time after we've output the + * full "mcount" number of sectors, so we must make sure we update the + * state _before_ we output the final part of the data! + */ +int promise_multwrite (ide_drive_t *drive, unsigned int mcount) +{ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq = &hwgroup->wrq; + + do { + char *buffer; + int nsect = rq->current_nr_sectors; +#ifdef CONFIG_IDE_TASKFILE_IO + unsigned long flags; +#endif /* CONFIG_IDE_TASKFILE_IO */ + + if (nsect > mcount) + nsect = mcount; + mcount -= nsect; +#ifdef CONFIG_IDE_TASKFILE_IO + buffer = ide_map_buffer(rq, &flags); + rq->sector += nsect; +#else /* !CONFIG_IDE_TASKFILE_IO */ + buffer = rq->buffer; + + rq->sector += nsect; + rq->buffer += nsect << 9; +#endif /* CONFIG_IDE_TASKFILE_IO */ + rq->nr_sectors -= nsect; + rq->current_nr_sectors -= nsect; + + /* Do we move to the next bh after this? */ + if (!rq->current_nr_sectors) { + struct buffer_head *bh = rq->bh->b_reqnext; + + /* end early early we ran out of requests */ + if (!bh) { + mcount = 0; + } else { + rq->bh = bh; + rq->current_nr_sectors = bh->b_size >> 9; + rq->hard_cur_sectors = rq->current_nr_sectors; + rq->buffer = bh->b_data; + } + } + + /* + * Ok, we're all setup for the interrupt + * re-entering us on the last transfer. + */ + taskfile_output_data(drive, buffer, nsect<<7); +#ifdef CONFIG_IDE_TASKFILE_IO + ide_unmap_buffer(buffer, &flags); +#endif /* CONFIG_IDE_TASKFILE_IO */ + } while (mcount); + + return 0; +} + +/* * promise_write_pollfunc() is the handler for disk write completion polling. */ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive) @@ -426,24 +510,28 @@ if (IN_BYTE(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); return ide_started; /* continue polling... */ } hwgroup->poll_timeout = 0; printk(KERN_ERR "%s: write timed-out!\n",drive->name); - return ide_error (drive, "write timeout", GET_STAT()); + return DRIVER(drive)->error(drive, "write timeout", GET_STAT()); } /* * Now write out last 4 sectors and poll for not BUSY */ - ide_multwrite(drive, 4); + promise_multwrite(drive, 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n", drive->name, GET_STAT()); -#endif +#endif /* DEBUG_WRITE */ return ide_started; } @@ -463,16 +551,18 @@ printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), " "buffer=%p\n", drive->name, rq->sector, rq->sector + rq->nr_sectors - 1, rq->buffer); -#endif +#endif /* DEBUG_WRITE */ /* * If there are more than 4 sectors to transfer, do n-4 then go into * the polling strategy as defined above. */ if (rq->nr_sectors > 4) { - if (ide_multwrite(drive, rq->nr_sectors - 4)) + if (promise_multwrite(drive, rq->nr_sectors - 4)) return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); return ide_started; } else { @@ -480,14 +570,16 @@ * There are 4 or fewer sectors to transfer, do them all in one go * and wait for NOT BUSY. */ - if (ide_multwrite(drive, rq->nr_sectors)) + if (promise_multwrite(drive, rq->nr_sectors)) return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, " "status = %02x\n", drive->name, GET_STAT()); -#endif +#endif /* DEBUG_WRITE */ return ide_started; } } @@ -497,17 +589,40 @@ * already set up. It issues a READ or WRITE command to the Promise * controller, assuming LBA has been used to set up the block number. */ +#ifndef CONFIG_IDE_TASKFILE_IO ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq) { +#else /* CONFIG_IDE_TASKFILE_IO */ +ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task) +{ + struct request *rq = HWGROUP(drive)->rq; + task_struct_t *taskfile = (task_struct_t *) task->tfRegister; +#endif /* CONFIG_IDE_TASKFILE_IO */ ide_startstop_t startstop; unsigned long timeout; byte stat; +#ifdef CONFIG_IDE_TASKFILE_IO + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive), drive, 0); + + OUT_BYTE(taskfile->feature, IDE_FEATURE_REG); + OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG); + /* refers to number of sectors to transfer */ + OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG); + /* refers to sector offset or start sector */ + OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG); + OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG); + OUT_BYTE(taskfile->device_head, IDE_SELECT_REG); + OUT_BYTE(taskfile->command, IDE_COMMAND_REG); +#endif /* CONFIG_IDE_TASKFILE_IO */ + switch(rq->cmd) { - case READ: -#ifndef __TASKFILE__IO - OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); -#endif + case READ: +#ifndef CONFIG_IDE_TASKFILE_IO + OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); +#endif /* CONFIG_IDE_TASKFILE_IO */ /* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be @@ -518,49 +633,55 @@ * If neither of these is the case, we wait for up to 50ms (badly I'm * afraid!) until one of them is. */ - timeout = jiffies + HZ/20; /* 50ms wait */ - do { - stat=GET_STAT(); - if (stat & DRQ_STAT) { - udelay(1); - return promise_read_intr(drive); - } - if (IN_BYTE(IDE_SELECT_REG) & 0x01) { -#ifdef DEBUG_READ - printk(KERN_DEBUG "%s: read: waiting for interrupt\n", drive->name); -#endif - ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); - return ide_started; - } + timeout = jiffies + HZ/20; /* 50ms wait */ + do { + stat=GET_STAT(); + if (stat & DRQ_STAT) { udelay(1); - } while (time_before(jiffies, timeout)); + return promise_read_intr(drive); + } + if (IN_BYTE(IDE_SELECT_REG) & 0x01) { +#ifdef DEBUG_READ + printk(KERN_DEBUG "%s: read: waiting for " + "interrupt\n", drive->name); +#endif /* DEBUG_READ */ + ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); + return ide_started; + } + udelay(1); + } while (time_before(jiffies, timeout)); - printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", drive->name); - return ide_stopped; - case WRITE: -#ifndef __TASKFILE__IO - OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); -#endif - if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing PROMISE_WRITE\n", drive->name); - return startstop; - } - if (!drive->unmask) - __cli(); /* local CPU only */ - HWGROUP(drive)->wrq = *rq; /* scratchpad */ - return promise_write(drive); - default: - printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd); - ide_end_request(0, HWGROUP(drive)); - return ide_stopped; + printk(KERN_ERR "%s: reading: No DRQ and not " + "waiting - Odd!\n", drive->name); + return ide_stopped; + case WRITE: +#ifndef CONFIG_IDE_TASKFILE_IO + OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); +#endif /* CONFIG_IDE_TASKFILE_IO */ + if (ide_wait_stat(&startstop, drive, DATA_READY, + drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing " + "PROMISE_WRITE\n", drive->name); + return startstop; + } + if (!drive->unmask) + local_irq_disable(); + HWGROUP(drive)->wrq = *rq; /* scratchpad */ + return promise_write(drive); + default: + printk("KERN_WARNING %s: bad command: %d\n", + drive->name, rq->cmd); + DRIVER(drive)->end_request(drive, 0); + return ide_stopped; } } -#ifdef __TASKFILE__IO +#ifdef CONFIG_IDE_TASKFILE_IO ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { - struct hd_drive_task_hdr taskfile; + struct hd_drive_task_hdr taskfile; + ide_task_t args; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); @@ -571,8 +692,17 @@ taskfile.device_head = ((block>>8)&0x0f)|drive->select.all; taskfile.command = (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE; - do_taskfile(drive, &taskfile, NULL, NULL); - return do_pdc4030_io(drive, rq); + memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); + memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr)); + args.command_type = ide_cmd_type_parser(&args); + args.prehandler = NULL; + args.handler = NULL; + args.posthandler = NULL; + args.rq = (struct request *) rq; + rq->special = NULL; + rq->special = (ide_task_t *)&args; + + return do_pdc4030_io(drive, &args); } -#endif +#endif /* CONFIG_IDE_TASKFILE_IO */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/pdcadma.c linux.20pre2-ac1/drivers/ide/pdcadma.c --- linux.20pre2/drivers/ide/pdcadma.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/pdcadma.c 2002-08-06 15:42:11.000000000 +0100 @@ -0,0 +1,106 @@ +/* + * linux/drivers/ide/pdcadma.c Version 0.01 June 21, 2001 + * + * Copyright (C) 1999-2000 Andre Hedrick + * May be copied or modified under the terms of the GNU General Public License + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +#undef DISPLAY_PDCADMA_TIMINGS + +#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int pdcadma_get_info(char *, char **, off_t, int); +extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +static struct pci_dev *bmide_dev; + +static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = pci_resource_start(bmide_dev, 4); + + p += sprintf(p, "\n PDC ADMA %04X Chipset.\n", bmide_dev->device); + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte pdcadma_proc = 0; + +#ifdef CONFIG_BLK_DEV_IDEDMA +/* + * pdcadma_dmaproc() initiates/aborts (U)DMA read/write operations on a drive. + */ + +int pdcadma_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + func = ide_dma_off_quietly; + default: + break; + } + return ide_dmaproc(func, drive); /* use standard DMA stuff */ +} +#endif /* CONFIG_BLK_DEV_IDEDMA */ + +unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name) +{ +#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) + if (!pdcadma_proc) { + pdcadma_proc = 1; + bmide_dev = dev; + pdcadma_display_info = &pdcadma_get_info; + } +#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */ + return 0; +} + +unsigned int __init ata66_pdcadma (ide_hwif_t *hwif) +{ + return 1; +} + +void __init ide_init_pdcadma (ide_hwif_t *hwif) +{ + hwif->autodma = 0; + hwif->dma_base = 0; + +// hwif->tuneproc = &pdcadma_tune_drive; +// hwif->speedproc = &pdcadma_tune_chipset; + +// if (hwif->dma_base) { +// hwif->dmaproc = &pdcadma_dmaproc; +// hwif->autodma = 1; +// } +} + +void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase) +{ +// ide_setup_dma(hwif, dmabase, 8); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/piix.c linux.20pre2-ac1/drivers/ide/piix.c --- linux.20pre2/drivers/ide/piix.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/piix.c 2002-08-06 15:42:11.000000000 +0100 @@ -77,7 +77,6 @@ static int piix_get_info(char *, char **, off_t, int); extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int piix_get_info (char *buffer, char **addr, off_t offset, int count) @@ -88,35 +87,36 @@ u8 c0 = 0, c1 = 0; u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0; + p += sprintf(p, "\n "); switch(bmide_dev->device) { case PCI_DEVICE_ID_INTEL_82801BA_8: case PCI_DEVICE_ID_INTEL_82801BA_9: - case PCI_DEVICE_ID_INTEL_82801CA_10: - case PCI_DEVICE_ID_INTEL_82801CA_11: - case PCI_DEVICE_ID_INTEL_82801DB_11: - case PCI_DEVICE_ID_INTEL_82801E_11: - p += sprintf(p, "\n Intel PIIX4 Ultra 100 Chipset.\n"); + case PCI_DEVICE_ID_INTEL_82801CA_10: + case PCI_DEVICE_ID_INTEL_82801CA_11: + case PCI_DEVICE_ID_INTEL_82801DB_11: + case PCI_DEVICE_ID_INTEL_82801E_11: + p += sprintf(p, "Intel PIIX4 Ultra 100 Chipset.\n"); break; case PCI_DEVICE_ID_INTEL_82372FB_1: case PCI_DEVICE_ID_INTEL_82801AA_1: - p += sprintf(p, "\n Intel PIIX4 Ultra 66 Chipset.\n"); + p += sprintf(p, "Intel PIIX4 Ultra 66 Chipset.\n"); break; case PCI_DEVICE_ID_INTEL_82451NX: case PCI_DEVICE_ID_INTEL_82801AB_1: case PCI_DEVICE_ID_INTEL_82443MX_1: case PCI_DEVICE_ID_INTEL_82371AB: - p += sprintf(p, "\n Intel PIIX4 Ultra 33 Chipset.\n"); + p += sprintf(p, "Intel PIIX4 Ultra 33 Chipset.\n"); break; case PCI_DEVICE_ID_INTEL_82371SB_1: - p += sprintf(p, "\n Intel PIIX3 Chipset.\n"); + p += sprintf(p, "Intel PIIX3 Chipset.\n"); break; case PCI_DEVICE_ID_INTEL_82371MX: - p += sprintf(p, "\n Intel MPIIX Chipset.\n"); + p += sprintf(p, "Intel MPIIX Chipset.\n"); return p-buffer; /* => must be less than 4k! */ case PCI_DEVICE_ID_INTEL_82371FB_1: case PCI_DEVICE_ID_INTEL_82371FB_0: default: - p += sprintf(p, "\n Intel PIIX Chipset.\n"); + p += sprintf(p, "Intel PIIX Chipset.\n"); break; } @@ -139,22 +139,29 @@ c0 = inb_p((unsigned short)bibma + 0x02); c1 = inb_p((unsigned short)bibma + 0x0a); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", (c0&0x80) ? "dis" : " en", (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s " + " %s %s\n", (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + p += sprintf(p, "UDMA enabled: %s %s " + " %s %s\n", (reg48&0x01) ? "yes" : "no ", (reg48&0x02) ? "yes" : "no ", (reg48&0x04) ? "yes" : "no ", (reg48&0x08) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + p += sprintf(p, "UDMA enabled: %s %s " + " %s %s\n", ((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" : ((reg54&0x11) && (reg4a&0x02)) ? "4" : ((reg54&0x11) && (reg4a&0x01)) ? "3" : @@ -198,12 +205,65 @@ byte piix_proc = 0; -extern char *ide_xfer_verbose (byte xfer_rate); -#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING) -/* - * - */ +static byte piix_ratemask (ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = 0x00; + + switch(dev->device) { + case PCI_DEVICE_ID_INTEL_82801BA_8: + case PCI_DEVICE_ID_INTEL_82801BA_9: + case PCI_DEVICE_ID_INTEL_82801CA_10: + case PCI_DEVICE_ID_INTEL_82801CA_11: + case PCI_DEVICE_ID_INTEL_82801E_11: + case PCI_DEVICE_ID_INTEL_82801DB_11: + mode |= 0x03; + break; + case PCI_DEVICE_ID_INTEL_82801AA_1: + case PCI_DEVICE_ID_INTEL_82372FB_1: + mode |= 0x02; + break; + case PCI_DEVICE_ID_INTEL_82371AB: + case PCI_DEVICE_ID_INTEL_82443MX_1: + case PCI_DEVICE_ID_INTEL_82451NX: + case PCI_DEVICE_ID_INTEL_82801AB_1: + mode |= 0x01; + case PCI_DEVICE_ID_INTEL_82371SB_1: + case PCI_DEVICE_ID_INTEL_82371FB_1: + case PCI_DEVICE_ID_INTEL_82371FB_0: + case PCI_DEVICE_ID_INTEL_82371MX: + default: + return (mode &= ~0xF8); + } + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte piix_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + byte mode = piix_ratemask(drive); + + switch(mode) { + case 0x04: while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + static byte piix_dma_2_pio (byte xfer_rate) { switch(xfer_rate) { case XFER_UDMA_5: @@ -231,7 +291,6 @@ return 0; } } -#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */ /* * Based on settings done by AMI BIOS @@ -239,12 +298,14 @@ */ static void piix_tune_drive (ide_drive_t *drive, byte pio) { + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int is_slave = (&hwif->drives[1] == drive); + int master_port = hwif->channel ? 0x42 : 0x40; + int slave_port = 0x44; unsigned long flags; u16 master_data; byte slave_data; - int is_slave = (&HWIF(drive)->drives[1] == drive); - int master_port = HWIF(drive)->index ? 0x42 : 0x40; - int slave_port = 0x44; /* ISP RTC */ byte timings[][2] = { { 0, 0 }, { 0, 0 }, @@ -253,44 +314,40 @@ { 2, 3 }, }; pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); + spin_lock_irqsave(&io_request_lock, flags); + pci_read_config_word(dev, master_port, &master_data); if (is_slave) { master_data = master_data | 0x4000; if (pio > 1) /* enable PPE, IE and TIME */ master_data = master_data | 0x0070; - pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data); - slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0); - slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) - << (HWIF(drive)->index ? 4 : 0)); + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); + slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); } else { master_data = master_data & 0xccf8; if (pio > 1) /* enable PPE, IE and TIME */ master_data = master_data | 0x0007; - master_data = master_data | (timings[pio][0] << 12) | - (timings[pio][1] << 8); + master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); } - save_flags(flags); - cli(); - pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data); + pci_write_config_word(dev, master_port, master_data); if (is_slave) - pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data); - restore_flags(flags); + pci_write_config_byte(dev, slave_port, slave_data); + spin_unlock_irqrestore(&io_request_lock, flags); } -#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING) -static int piix_tune_chipset (ide_drive_t *drive, byte speed) +static int piix_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; byte maslave = hwif->channel ? 0x42 : 0x40; + byte speed = piix_ratefilter(drive, xferspeed); int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; int v_flag = 0x01 << drive->dn; int w_flag = 0x10 << drive->dn; int u_speed = 0; - int err = 0; int sitre; short reg4042, reg44, reg48, reg4a, reg54; byte reg55; @@ -304,6 +361,7 @@ pci_read_config_byte(dev, 0x55, ®55); switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_4: case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; case XFER_UDMA_5: @@ -313,6 +371,11 @@ case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; +#endif /* CONFIG_BLK_DEV_IDEDMA */ + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_0: break; default: return -1; } @@ -335,8 +398,7 @@ } else { pci_write_config_word(dev, 0x54, reg54 & ~v_flag); } - } - if (speed < XFER_UDMA_0) { + } else { if (reg48 & u_flag) pci_write_config_word(dev, 0x48, reg48 & ~u_flag); if (reg4a & a_speed) @@ -348,64 +410,51 @@ } piix_tune_drive(drive, piix_dma_2_pio(speed)); - -#if PIIX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); -#endif /* PIIX_DEBUG_DRIVE_INFO */ - if (!drive->init_speed) - drive->init_speed = speed; - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - return err; + return (ide_config_drive_speed(drive, speed)); } +#ifdef CONFIG_BLK_DEV_IDEDMA static int piix_config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - byte speed; + byte mode = piix_ratemask(drive); + byte speed, tspeed, dma = 1; - byte udma_66 = eighty_ninty_three(drive); - int ultra100 = ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) || - (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) || - (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10) || - (dev->device == PCI_DEVICE_ID_INTEL_82801CA_11) || - (dev->device == PCI_DEVICE_ID_INTEL_82801DB_11) || - (dev->device == PCI_DEVICE_ID_INTEL_82801E_11)) ? 1 : 0; - int ultra66 = ((ultra100) || - (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || - (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; - int ultra = ((ultra66) || - (dev->device == PCI_DEVICE_ID_INTEL_82371AB) || - (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) || - (dev->device == PCI_DEVICE_ID_INTEL_82451NX) || - (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0; - - if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) { - speed = XFER_UDMA_5; - } else if ((id->dma_ultra & 0x0010) && (ultra)) { - speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0008) && (ultra)) { - speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0004) && (ultra)) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (ultra)) { - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (ultra)) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else { - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + switch(mode) { + case 0x03: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_5; break; } + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + default: + tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); + speed = piix_dma_2_pio(XFER_PIO_0 + tspeed); + dma = 0; + break; } (void) piix_tune_chipset(drive, speed); +// return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly); return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : @@ -413,16 +462,13 @@ ide_dma_off_quietly); } -static void config_chipset_for_pio (ide_drive_t *drive) -{ - piix_tune_drive(drive, ide_get_best_pio_mode(drive, 255, 5, NULL)); -} - static int config_drive_xfer_rate (ide_drive_t *drive) { struct hd_driveid *id = drive->id; ide_dma_action_t dma_func = ide_dma_on; + drive->init_speed = 0; + if (id && (id->capability & 1) && HWIF(drive)->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { @@ -431,7 +477,7 @@ } dma_func = ide_dma_off_quietly; if (id->field_valid & 4) { - if (id->dma_ultra & 0x003F) { + if (id->dma_ultra & 0x007F) { /* Force if Capable UltraDMA */ dma_func = piix_config_drive_for_dma(drive); if ((id->field_valid & 2) && @@ -462,7 +508,7 @@ fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - config_chipset_for_pio(drive); + piix_tune_drive(drive, 255); } return HWIF(drive)->dmaproc(dma_func, drive); } @@ -478,10 +524,28 @@ /* Other cases are done by generic IDE-DMA code. */ return ide_dmaproc(func, drive); } -#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */ +#endif /* CONFIG_BLK_DEV_IDEDMA */ unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name) { + switch(dev->device) { + case PCI_DEVICE_ID_INTEL_82801AA_1: + case PCI_DEVICE_ID_INTEL_82801AB_1: + case PCI_DEVICE_ID_INTEL_82801BA_8: + case PCI_DEVICE_ID_INTEL_82801BA_9: + case PCI_DEVICE_ID_INTEL_82801CA_10: + case PCI_DEVICE_ID_INTEL_82801CA_11: + case PCI_DEVICE_ID_INTEL_82801E_11: + case PCI_DEVICE_ID_INTEL_82801DB_11: + { + unsigned int extra = 0; + pci_read_config_dword(dev, 0x54, &extra); + pci_write_config_dword(dev, 0x54, extra|0x400); + } + default: + break; + } + #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) if (!piix_proc) { piix_proc = 1; @@ -522,21 +586,32 @@ return; } + hwif->autodma = 0; hwif->tuneproc = &piix_tune_drive; + hwif->speedproc = &piix_tune_chipset; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; if (!hwif->dma_base) return; -#ifndef CONFIG_BLK_DEV_IDEDMA - hwif->autodma = 0; -#else /* CONFIG_BLK_DEV_IDEDMA */ -#ifdef CONFIG_PIIX_TUNING +#ifdef CONFIG_BLK_DEV_IDEDMA + hwif->dmaproc = &piix_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO if (!noautodma) hwif->autodma = 1; - hwif->dmaproc = &piix_dmaproc; - hwif->speedproc = &piix_tune_chipset; -#endif /* CONFIG_PIIX_TUNING */ +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* !CONFIG_BLK_DEV_IDEDMA */ } + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_piix (struct pci_dev *dev, ide_pci_device_t *d) +{ + if (dev->resource[0].start != 0x01F1) + ide_register_xp_fix(dev); + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/qd65xx.c linux.20pre2-ac1/drivers/ide/qd65xx.c --- linux.20pre2/drivers/ide/qd65xx.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/qd65xx.c 2002-08-06 15:42:11.000000000 +0100 @@ -94,10 +94,9 @@ { unsigned long flags; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - outb(content,reg); - restore_flags(flags); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); + OUT_BYTE(content,reg); + spin_unlock_irqrestore(&io_request_lock, flags); } byte __init qd_read_reg (byte reg) @@ -105,10 +104,9 @@ unsigned long flags; byte read; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - read = inb(reg); - restore_flags(flags); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); + read = IN_BYTE(reg); + spin_unlock_irqrestore(&io_request_lock, flags); return read; } @@ -313,13 +311,12 @@ byte readreg; unsigned long flags; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ + spin_lock_irqsave(&io_request_lock, flags); savereg = inb_p(port); outb_p(QD_TESTVAL,port); /* safe value */ readreg = inb_p(port); - outb(savereg,port); - restore_flags(flags); /* all CPUs */ + OUT_BYTE(savereg,port); + spin_unlock_irqrestore(&io_request_lock, flags); if (savereg == QD_TESTVAL) { printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/rz1000.c linux.20pre2-ac1/drivers/ide/rz1000.c --- linux.20pre2/drivers/ide/rz1000.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/rz1000.c 2002-08-06 15:42:11.000000000 +0100 @@ -40,15 +40,16 @@ struct pci_dev *dev = hwif->pci_dev; hwif->chipset = ide_rz1000; - if (!pci_read_config_word (dev, 0x40, ®) - && !pci_write_config_word(dev, 0x40, reg & 0xdfff)) - { - printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name); + if (!pci_read_config_word (dev, 0x40, ®) && + !pci_write_config_word(dev, 0x40, reg & 0xdfff)) { + printk("%s: disabled chipset read-ahead " + "(buggy RZ1000/RZ1001)\n", hwif->name); } else { hwif->serialized = 1; hwif->drives[0].no_unmask = 1; hwif->drives[1].no_unmask = 1; - printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name); + printk("%s: serialized, disabled unmasking " + "(buggy RZ1000/RZ1001)\n", hwif->name); } } @@ -58,27 +59,29 @@ { unsigned short reg, h; - if (!pci_read_config_word (dev, PCI_COMMAND, ®) && !(reg & PCI_COMMAND_IO)) { + if (!pci_read_config_word (dev, PCI_COMMAND, ®) && + !(reg & PCI_COMMAND_IO)) { printk("%s: buggy IDE controller disabled (BIOS)\n", name); return; } - if (!pci_read_config_word (dev, 0x40, ®) - && !pci_write_config_word(dev, 0x40, reg & 0xdfff)) - { + if (!pci_read_config_word (dev, 0x40, ®) && + !pci_write_config_word(dev, 0x40, reg & 0xdfff)) { printk("IDE: disabled chipset read-ahead (buggy %s)\n", name); } else { for (h = 0; h < MAX_HWIFS; ++h) { ide_hwif_t *hwif = &ide_hwifs[h]; - if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170) - && (hwif->chipset == ide_unknown || hwif->chipset == ide_generic)) - { + if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || + hwif->io_ports[IDE_DATA_OFFSET] == 0x170) && + (hwif->chipset == ide_unknown || + hwif->chipset == ide_generic)) { hwif->chipset = ide_rz1000; hwif->serialized = 1; hwif->drives[0].no_unmask = 1; hwif->drives[1].no_unmask = 1; if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170) hwif->channel = 1; - printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name); + printk("%s: serialized, disabled unmasking " + "(buggy %s)\n", hwif->name, name); } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/serverworks.c linux.20pre2-ac1/drivers/ide/serverworks.c --- linux.20pre2/drivers/ide/serverworks.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/serverworks.c 2002-08-06 15:42:11.000000000 +0100 @@ -1,7 +1,5 @@ /* - * linux/drivers/ide/serverworks.c Version 0.3 26 Oct 2001 - * - * May be copied or modified under the terms of the GNU General Public License + * linux/drivers/ide/serverworks.c Version 0.6 05 April 2002 * * Copyright (C) 1998-2000 Michel Aubry * Copyright (C) 1998-2000 Andrzej Krzysztofowicz @@ -21,61 +19,7 @@ * *** The CSB5 does not provide ANY register *** * *** to detect 80-conductor cable presence. *** * - * - * here's the default lspci: - * - * 00:0f.1 IDE interface: ServerWorks: Unknown device 0211 (prog-if 8a [Master SecP PriP]) - * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- - * Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- SERR- TAbort- SERR- #include -static struct pci_dev *bmide_dev; +#define SVWKS_MAX_DEVS 2 +static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS]; +static int n_svwks_devs; + static byte svwks_revision = 0; static int svwks_get_info(char *, char **, off_t, int); extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static int svwks_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - u32 bibma = pci_resource_start(bmide_dev, 4); - u32 reg40, reg44; - u16 reg48, reg56; - u8 reg54, c0=0, c1=0; - - pci_read_config_dword(bmide_dev, 0x40, ®40); - pci_read_config_dword(bmide_dev, 0x44, ®44); - pci_read_config_word(bmide_dev, 0x48, ®48); - pci_read_config_byte(bmide_dev, 0x54, ®54); - pci_read_config_word(bmide_dev, 0x56, ®56); - - /* - * at that point bibma+0x2 et bibma+0xa are byte registers - * to investigate: - */ - c0 = inb_p((unsigned short)bibma + 0x02); - c1 = inb_p((unsigned short)bibma + 0x0a); + int i; - switch(bmide_dev->device) { - case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: - p += sprintf(p, "\n " - "ServerWorks CSB5 Chipset (rev %02x)\n", - svwks_revision); - break; - case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: - p += sprintf(p, "\n " - "ServerWorks OSB4 Chipset (rev %02x)\n", - svwks_revision); - break; - default: - p += sprintf(p, "\n " - "ServerWorks %04x Chipset (rev %02x)\n", - bmide_dev->device, svwks_revision); - break; - } + p += sprintf(p, "\n " + "ServerWorks OSB4/CSB5/CSB6\n"); - p += sprintf(p, "------------------------------- General Status ---------------------------------\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", - (c0&0x80) ? "dis" : " en", - (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", + for (i = 0; i < n_svwks_devs; i++) { + struct pci_dev *dev = svwks_devs[i]; + u32 bibma = pci_resource_start(dev, 4); + u32 reg40, reg44; + u16 reg48, reg56; + u8 reg54, c0=0, c1=0; + + pci_read_config_dword(dev, 0x40, ®40); + pci_read_config_dword(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_word(dev, 0x56, ®56); + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + switch(dev->device) { + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: + p += sprintf(p, "\n " + "ServerWorks CSB6 Chipset (rev %02x)\n", + svwks_revision); + break; + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + p += sprintf(p, "\n " + "ServerWorks CSB5 Chipset (rev %02x)\n", + svwks_revision); + break; + case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: + p += sprintf(p, "\n " + "ServerWorks OSB4 Chipset (rev %02x)\n", + svwks_revision); + break; + default: + p += sprintf(p, "\n " + "ServerWorks %04x Chipset (rev %02x)\n", + dev->device, svwks_revision); + break; + } + + p += sprintf(p, "------------------------------- " + "General Status " + "---------------------------------\n"); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s" + " %s %s\n", (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + p += sprintf(p, "UDMA enabled: %s %s" + " %s %s\n", (reg54 & 0x01) ? "yes" : "no ", (reg54 & 0x02) ? "yes" : "no ", (reg54 & 0x04) ? "yes" : "no ", (reg54 & 0x08) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + p += sprintf(p, "UDMA enabled: %s %s" + " %s %s\n", ((reg56&0x0005)==0x0005)?"5": ((reg56&0x0004)==0x0004)?"4": ((reg56&0x0003)==0x0003)?"3": @@ -187,7 +153,8 @@ ((reg56&0x2000)==0x2000)?"2": ((reg56&0x1000)==0x1000)?"1": ((reg56&0xF000))?"?":"0"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", + p += sprintf(p, "DMA enabled: %s %s" + " %s %s\n", ((reg44&0x00002000)==0x00002000)?"2": ((reg44&0x00002100)==0x00002100)?"1": ((reg44&0x00007700)==0x00007700)?"0": @@ -205,7 +172,8 @@ ((reg44&0x00770000)==0x00770000)?"0": ((reg44&0x00FF0000)==0x00FF0000)?"X":"?"); - p += sprintf(p, "PIO enabled: %s %s %s %s\n", + p += sprintf(p, "PIO enabled: %s %s" + " %s %s\n", ((reg40&0x00002000)==0x00002000)?"4": ((reg40&0x00002200)==0x00002200)?"3": ((reg40&0x00003400)==0x00003400)?"2": @@ -226,19 +194,83 @@ ((reg40&0x00340000)==0x00340000)?"2": ((reg40&0x00470000)==0x00470000)?"1": ((reg40&0x005D0000)==0x005D0000)?"0":"?"); + + } + p += sprintf(p, "\n"); + return p-buffer; /* => must be less than 4k! */ } #endif /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */ #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ -byte svwks_proc = 0; +#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ -extern char *ide_xfer_verbose (byte xfer_rate); +byte svwks_proc = 0; static struct pci_dev *isa_dev; -static int svwks_tune_chipset (ide_drive_t *drive, byte speed) +static byte svwks_ratemask (ide_drive_t *drive) +{ + struct pci_dev *dev = HWIF(drive)->pci_dev; + byte mode = 0; + + if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { + u32 reg = 0; + mode &= ~0x01; + if (isa_dev) + pci_read_config_dword(isa_dev, 0x64, ®); + if ((reg & 0x00004000) == 0x00004000) + mode |= 0x01; + } else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) { + mode |= 0x01; + } else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) { + u8 btr =0; + pci_read_config_byte(dev, 0x5A, &btr); + mode |= btr; + if (!eighty_ninty_three(drive)) + mode &= ~0x02; + } + if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) && + (!(PCI_FUNC(dev->devfn) & 1))) + mode = 0x02; + mode &= ~0xFC; + return (mode); +} + +static byte svwks_ratefilter (ide_drive_t *drive, byte speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + byte mode = svwks_ratemask(drive); + + switch(mode) { + case 0x04: while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + +static byte svwks_csb_check (struct pci_dev *dev) +{ + switch (dev->device) { + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: + return 1; + default: + break; + } + return 0; +} +static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed) { byte udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; byte dma_modes[] = { 0x77, 0x21, 0x20 }; @@ -247,12 +279,7 @@ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; byte unit = (drive->select.b.unit & 0x01); - byte csb5 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0; - -#ifdef CONFIG_BLK_DEV_IDEDMA - unsigned long dma_base = hwif->dma_base; -#endif /* CONFIG_BLK_DEV_IDEDMA */ - int err; + byte csb5 = svwks_csb_check(dev); byte drive_pci = 0x00; byte drive_pci2 = 0x00; @@ -265,6 +292,7 @@ unsigned short csb5_pio = 0x00; byte pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + byte speed = svwks_ratefilter(drive, xferspeed); switch (drive->dn) { case 0: drive_pci = 0x41; drive_pci2 = 0x45; break; @@ -281,11 +309,6 @@ pci_read_config_word(dev, 0x4A, &csb5_pio); pci_read_config_byte(dev, 0x54, &ultra_enable); -#ifdef DEBUG - printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", - drive->name, ultra_timing, dma_timing, pio_timing); -#endif - pio_timing &= ~0xFF; dma_timing &= ~0xFF; ultra_timing &= ~(0x0F << (4*unit)); @@ -327,18 +350,6 @@ break; } -#ifdef DEBUG - printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", - drive->name, ultra_timing, dma_timing, pio_timing); -#endif - -#if SVWKS_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); -#endif /* SVWKS_DEBUG_DRIVE_INFO */ - - if (!drive->init_speed) - drive->init_speed = speed; - pci_write_config_byte(dev, drive_pci, pio_timing); if (csb5) pci_write_config_word(dev, 0x4A, csb5_pio); @@ -347,16 +358,9 @@ pci_write_config_byte(dev, drive_pci2, dma_timing); pci_write_config_byte(dev, drive_pci3, ultra_timing); pci_write_config_byte(dev, 0x54, ultra_enable); - - if (speed > XFER_PIO_4) - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - else - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); #endif /* CONFIG_BLK_DEV_IDEDMA */ - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - return err; + return (ide_config_drive_speed(drive, speed)); } static void config_chipset_for_pio (ide_drive_t *drive) @@ -414,36 +418,54 @@ static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - struct pci_dev *dev = HWIF(drive)->pci_dev; - byte udma_66 = eighty_ninty_three(drive); - int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0; - int ultra100 = (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0; - byte speed; + byte mode = svwks_ratemask(drive); + byte speed, dma = 1; + + if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) + mode = 0; - if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) { - speed = XFER_UDMA_5; - } else if (id->dma_ultra & 0x0010) { - speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2; - } else if (id->dma_ultra & 0x0008) { - speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1; - } else if (id->dma_ultra & 0x0004) { - speed = XFER_UDMA_2; - } else if (id->dma_ultra & 0x0002) { - speed = XFER_UDMA_1; - } else if (id->dma_ultra & 0x0001) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else { - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + switch(mode) { + case 0x04: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_6; break; } + case 0x03: + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } +#if 0 + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + if (id->dma_1word & 0x0002) + { speed = XFER_SW_DMA_1; break; } + if (id->dma_1word & 0x0001) + { speed = XFER_SW_DMA_0; break; } +#endif + default: + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + dma = 0; + break; } (void) svwks_tune_chipset(drive, speed); +// return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly); return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : @@ -456,6 +478,8 @@ struct hd_driveid *id = drive->id; ide_dma_action_t dma_func = ide_dma_on; + drive->init_speed = 0; + if (id && (id->capability & 1) && HWIF(drive)->autodma) { /* Consult the list of known "bad" drives */ if (ide_dmaproc(ide_dma_bad_drive, drive)) { @@ -496,6 +520,7 @@ dma_func = ide_dma_off_quietly; no_dma_set: config_chipset_for_pio(drive); + // HWIF(drive)->tuneproc(drive, 5); } return HWIF(drive)->dmaproc(dma_func, drive); } @@ -510,14 +535,14 @@ ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; - if(inb(dma_base+0x02)&1) + if(IN_BYTE(dma_base+0x02)&1) { #if 0 int i; printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n"); for(i=0;i<10;i++) { - if(!(inb(dma_base+0x02)&1)) + if(!(IN_BYTE(dma_base+0x02)&1)) { printk(KERN_ERR "OSB4 now finished.\n"); break; @@ -570,35 +595,83 @@ } } - /* setup CSB5 : South Bridge and IDE */ - else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) { + /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ + else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || + (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) { + /* Third Channel Test */ + if (!(PCI_FUNC(dev->devfn) & 1)) { +#if 1 + struct pci_dev * findev = NULL; + unsigned int reg4c = 0; + findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); + if (findev) { + pci_read_config_dword(findev, 0x4C, ®4c); + reg4c &= ~0x000007FF; + reg4c |= 0x00000040; + reg4c |= 0x00000020; + pci_write_config_dword(findev, 0x4C, reg4c); + } +#endif + outb_p(0x06, 0x0c00); + dev->irq = inb_p(0x0c01); +#if 1 + /* 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 + } else { + /* + * This is a device pin issue on CSB6. + * Since there will be a future raid mode, + * early versions of the chipset require the + * interrupt pin to be set, and it is a compatablity + * mode issue. + */ + dev->irq = 0; + } + pci_write_config_dword(dev, 0x40, 0x99999999); + pci_write_config_dword(dev, 0x44, 0xFFFFFFFF); /* setup the UDMA Control register * * 1. clear bit 6 to enable DMA * 2. enable DMA modes with bits 0-1 - * 00 : legacy - * 01 : udma2 - * 10 : udma2/udma4 - * 11 : udma2/udma4/udma5 + * 00 : legacy + * 01 : udma2 + * 10 : udma2/udma4 + * 11 : udma2/udma4/udma5 */ pci_read_config_byte(dev, 0x5A, &btr); btr &= ~0x40; - btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; + if (!(PCI_FUNC(dev->devfn) & 1)) + btr |= 0x2; + else + btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; pci_write_config_byte(dev, 0x5A, btr); } + svwks_devs[n_svwks_devs++] = dev; + #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) if (!svwks_proc) { svwks_proc = 1; - bmide_dev = dev; svwks_display_info = &svwks_get_info; } #endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */ - return 0; + + return (dev->irq) ? dev->irq : 0; +} + +static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif) +{ +// struct pci_dev *dev = hwif->pci_dev; +// return 0; + return 1; } -/* On Dell PowerEdge servers with a CSB5, the top two bits of the subsystem - * device ID indicate presence of an 80-pin cable. +/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits + * of the subsystem device ID indicate presence of an 80-pin cable. * Bit 15 clear = secondary IDE channel does not have 80-pin cable. * Bit 15 set = secondary IDE channel has 80-pin cable. * Bit 14 clear = primary IDE channel does not have 80-pin cable. @@ -609,7 +682,8 @@ struct pci_dev *dev = hwif->pci_dev; if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL && dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) + (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE || + dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) return ((1 << (hwif->channel + 14)) & dev->subsystem_device) ? 1 : 0; return 0; @@ -636,6 +710,10 @@ { struct pci_dev *dev = hwif->pci_dev; + /* Server Works */ + if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS) + return ata66_svwks_svwks (hwif); + /* Dell PowerEdge */ if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL) return ata66_svwks_dell (hwif); @@ -654,22 +732,58 @@ hwif->tuneproc = &svwks_tune_drive; hwif->speedproc = &svwks_tune_chipset; - -#ifndef CONFIG_BLK_DEV_IDEDMA hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0; -#else /* CONFIG_BLK_DEV_IDEDMA */ - if (hwif->dma_base) { -#ifdef CONFIG_IDEDMA_AUTO - if (!noautodma) - hwif->autodma = 1; -#endif - hwif->dmaproc = &svwks_dmaproc; - } else { - hwif->autodma = 0; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - } + + if (!hwif->dma_base) + return; + +#ifdef CONFIG_BLK_DEV_IDEDMA + hwif->dmaproc = &svwks_dmaproc; +# ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +# endif /* CONFIG_IDEDMA_AUTO */ #endif /* !CONFIG_BLK_DEV_IDEDMA */ } + +/* + * We allow the BM-DMA driver to only work on enabled interfaces. + */ +void __init ide_dmacapable_svwks (ide_hwif_t *hwif, unsigned long dmabase) +{ + struct pci_dev *dev = hwif->pci_dev; + if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) && + (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel)) + return; +#if 0 + if (svwks_revision == (SVWKS_CSB5_REVISION_NEW + 1)) { + if (hwif->mate && hwif->mate->dma_base) { + dmabase = hwif->mate->dma_base - (hwif->channel ? 0 : 8); + } else { + dmabase = pci_resource_start(dev, 4); + if (!dmabase) { + printk("%s: dma_base is invalid (0x%04lx)\n", + hwif->name, dmabase); + dmabase = 0; + } + } + } +#endif + ide_setup_dma(hwif, dmabase, 8); +} + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_csb6 (struct pci_dev *dev, ide_pci_device_t *d) +{ + if (!(PCI_FUNC(dev->devfn) & 1)) { + d->bootable = NEVER_BOARD; + } + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/sis5513.c linux.20pre2-ac1/drivers/ide/sis5513.c --- linux.20pre2/drivers/ide/sis5513.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/sis5513.c 2002-08-06 15:42:11.000000000 +0100 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/sis5513.c Version 0.13 March 6, 2002 + * linux/drivers/ide/sis5513.c Version 0.14 July 24, 2002 * * Copyright (C) 1999-2000 Andre Hedrick * Copyright (C) 2002 Lionel Bouton , Maintainer @@ -16,13 +16,13 @@ * * Original tests and design on the SiS620/5513 chipset. * ATA100 tests and design on the SiS735/5513 chipset. - * ATA16/33 design from specs + * ATA16/33 support from specs + * ATA133 support for SiS961/962 by L.C. Chang */ /* * TODO: * - Get ridden of SisHostChipInfo[] completness dependancy. - * - Get ATA-133 datasheets, implement ATA-133 init code. * - Study drivers/ide/ide-timing.h. * - Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them * or remove ATA_00 define @@ -53,7 +53,7 @@ #include "ide_modes.h" /* When DEBUG is defined it outputs initial PCI config register - values and changes made to them by the driver */ + values and changes made to them by the driver */ // #define DEBUG /* When BROKEN_LEVEL is defined it limits the DMA mode at boot time to its value */ @@ -71,44 +71,33 @@ #define ATA_66 0x03 #define ATA_100a 0x04 // SiS730 is ATA100 with ATA66 layout #define ATA_100 0x05 -#define ATA_133 0x06 +#define ATA_133a 0x06 // SiS961b with 133 support +#define ATA_133 0x07 // SiS962 /* 2/ variable holding the controller chipset family value */ -static unsigned char chipset_family; +static u8 chipset_family; /* * Debug code: following IDE config registers' changes */ #ifdef DEBUG -/* Copy of IDE Config registers 0x00 -> 0x57 - Fewer might be used depending on the actual chipset */ -static unsigned char ide_regs_copy[0x58]; - -static byte sis5513_max_config_register(void) { - switch(chipset_family) { - case ATA_00: - case ATA_16: return 0x4f; - case ATA_33: return 0x52; - case ATA_66: - case ATA_100a: - case ATA_100: - case ATA_133: - default: return 0x57; - } -} +/* Copy of IDE Config registers fewer will be used + * Some odd chipsets hang if unused registers are accessed + * -> We only access them in #DEBUG code (then we'll see if SiS did + * it right from day one) */ +static u8 ide_regs_copy[0xff]; /* Read config registers, print differences from previous read */ static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) { int i; - byte reg_val; - byte changed=0; - byte max = sis5513_max_config_register(); + u8 reg_val; + u8 changed=0; printk("SIS5513: %s, changed registers:\n", info); - for(i=0; i<=max; i++) { + for(i=0; i<=0xff; i++) { pci_read_config_byte(dev, i, ®_val); if (reg_val != ide_regs_copy[i]) { - printk("%0#x: %0#x -> %0#x\n", + printk("%02x: %02x -> %02x\n", i, ide_regs_copy[i], reg_val); ide_regs_copy[i]=reg_val; changed=1; @@ -123,39 +112,26 @@ /* Load config registers, no printing */ static void sis5513_load_registers(struct pci_dev* dev) { int i; - byte max = sis5513_max_config_register(); - for(i=0; i<=max; i++) { + for(i=0; i<=0xff; i++) { pci_read_config_byte(dev, i, &(ide_regs_copy[i])); } } -/* Print a register */ -static void sis5513_print_register(int reg) { - printk(" %0#x:%0#x", reg, ide_regs_copy[reg]); -} - -/* Print valuable registers */ +/* Print config space registers a la "lspci -vxxx" */ static void sis5513_print_registers(struct pci_dev* dev, char* marker) { - int i; - byte max = sis5513_max_config_register(); + int i,j; sis5513_load_registers(dev); printk("SIS5513 %s\n", marker); - printk("SIS5513 dump:"); - for(i=0x00; i<0x40; i++) { - if ((i % 0x10)==0) printk("\n "); - sis5513_print_register(i); - } - for(; i<49; i++) { - sis5513_print_register(i); - } - printk("\n "); - for(; i<=max; i++) { - sis5513_print_register(i); + for(i=0; i<=0xf; i++) { + printk("SIS5513 dump: %d" "0:", i); + for(j=0; j<=0xf; j++) { + printk(" %02x", ide_regs_copy[(i<<16)+j]); + } + printk("\n"); } - printk("\n"); } #endif @@ -165,21 +141,30 @@ */ static const struct { const char *name; - unsigned short host_id; - unsigned char chipset_family; - unsigned char flags; + u16 host_id; + u8 chipset_family; + u8 flags; } SiSHostChipInfo[] = { -// { "SiS750", PCI_DEVICE_ID_SI_750, ATA_100, SIS5513_LATENCY }, -// { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100, SIS5513_LATENCY }, - { "SiS740", PCI_DEVICE_ID_SI_740, ATA_100, SIS5513_LATENCY }, + { "SiS752", PCI_DEVICE_ID_SI_752, ATA_133, 0 }, + { "SiS751", PCI_DEVICE_ID_SI_751, ATA_133, 0 }, + { "SiS750", PCI_DEVICE_ID_SI_750, ATA_133, 0 }, + { "SiS748", PCI_DEVICE_ID_SI_748, ATA_133, 0 }, + { "SiS746", PCI_DEVICE_ID_SI_746, ATA_133, 0 }, + { "SiS745", PCI_DEVICE_ID_SI_745, ATA_133, 0 }, + { "SiS740", PCI_DEVICE_ID_SI_740, ATA_100, 0 }, { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100, SIS5513_LATENCY }, { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a, SIS5513_LATENCY }, -// { "SiS650", PCI_DEVICE_ID_SI_650, ATA_100, SIS5513_LATENCY }, -// { "SiS645", PCI_DEVICE_ID_SI_645, ATA_100, SIS5513_LATENCY }, + { "SiS652", PCI_DEVICE_ID_SI_652, ATA_133, 0 }, + { "SiS651", PCI_DEVICE_ID_SI_651, ATA_133, 0 }, + { "SiS650", PCI_DEVICE_ID_SI_650, ATA_133, 0 }, + { "SiS648", PCI_DEVICE_ID_SI_648, ATA_133, 0 }, + { "SiS646", PCI_DEVICE_ID_SI_646, ATA_133, 0 }, + { "SiS645", PCI_DEVICE_ID_SI_645, ATA_133, 0 }, { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100, SIS5513_LATENCY }, { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66, SIS5513_LATENCY }, { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66, SIS5513_LATENCY }, { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66, SIS5513_LATENCY }, + { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a, 0}, { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66, 0}, { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66, 0}, { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33, 0}, @@ -193,16 +178,64 @@ /* Cycle time bits and values vary accross chip dma capabilities These three arrays hold the register layout and the values to set. Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */ -static byte cycle_time_offset[] = {0,0,5,4,4,0,0}; -static byte cycle_time_range[] = {0,0,2,3,3,4,4}; -static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = { - {0,0,0,0,0,0}, /* no udma */ - {0,0,0,0,0,0}, /* no udma */ - {3,2,1,0,0,0}, - {7,5,3,2,1,0}, - {7,5,3,2,1,0}, - {11,7,5,4,2,1}, - {0,0,0,0,0,0} /* not yet known, ask SiS */ + +/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ +static u8 cycle_time_offset[] = {0,0,5,4,4,0,0}; +static u8 cycle_time_range[] = {0,0,2,3,3,4,4}; +static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { + {0,0,0,0,0,0,0}, /* no udma */ + {0,0,0,0,0,0,0}, /* no udma */ + {3,2,1,0,0,0,0}, /* ATA_33 */ + {7,5,3,2,1,0,0}, /* ATA_66 */ + {7,5,3,2,1,0,0}, /* ATA_100a (730 specific), differences are on cycle_time range and offset */ + {11,7,5,4,2,1,0}, /* ATA_100 */ + {15,10,7,5,3,2,1}, /* ATA_133a (earliest 691 southbridges) */ + {15,10,7,5,3,2,1}, /* ATA_133 */ +}; +/* CRC Valid Setup Time vary accross IDE clock setting 33/66/100/133 + See SiS962 data sheet for more detail */ +static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { + {0,0,0,0,0,0,0}, /* no udma */ + {0,0,0,0,0,0,0}, /* no udma */ + {2,1,1,0,0,0,0}, + {4,3,2,1,0,0,0}, + {4,3,2,1,0,0,0}, + {6,4,3,1,1,1,0}, + {9,6,4,2,2,2,2}, + {9,6,4,2,2,2,2}, +}; +/* Initialize time, Active time, Recovery time vary accross + IDE clock settings. These 3 arrays hold the register value + for PIO0/1/2/3/4 and DMA0/1/2 mode in order */ +static u8 ini_time_value[][8] = { + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {2,1,0,0,0,1,0,0}, + {4,3,1,1,1,3,1,1}, + {4,3,1,1,1,3,1,1}, + {6,4,2,2,2,4,2,2}, + {9,6,3,3,3,6,3,3}, + {9,6,3,3,3,6,3,3}, +}; +static u8 act_time_value[][8] = { + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {9,9,9,2,2,7,2,2}, + {19,19,19,5,4,14,5,4}, + {19,19,19,5,4,14,5,4}, + {28,28,28,7,6,21,7,6}, + {38,38,38,10,9,28,10,9}, + {38,38,38,10,9,28,10,9}, +}; +static u8 rco_time_value[][8] = { + {0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0}, + {9,2,0,2,0,7,1,1}, + {19,5,1,5,2,16,3,2}, + {19,5,1,5,2,16,3,2}, + {30,9,3,9,4,25,6,4}, + {40,12,4,12,5,34,12,5}, + {40,12,4,12,5,34,12,5}, }; static struct pci_dev *host_dev = NULL; @@ -249,29 +282,38 @@ "7 CLK", "8 CLK", "9 CLK", "10 CLK", "11 CLK", "12 CLK", - "Reserved", "Reserved", - "Reserved", "Reserved" + "13 CLK", "14 CLK", + "15 CLK", "16 CLK" +}; + +static char* chipset_capability[] = { + "ATA", "ATA 16", + "ATA 33", "ATA 66", + "ATA 100", "ATA 100", + "ATA 133", "ATA 133" }; /* Generic add master or slave info function */ -static char* get_drives_info (char *buffer, byte pos) +static char* get_drives_info (char *buffer, u8 pos) { - byte reg00, reg01, reg10, reg11; /* timing registers */ + u8 reg00, reg01, reg10, reg11; /* timing registers */ char* p = buffer; /* Postwrite/Prefetch */ - pci_read_config_byte(bmide_dev, 0x4b, ®00); - p += sprintf(p, "Drive %d: Postwrite %s \t \t Postwrite %s\n", - pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled", - (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled"); - p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", - (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled", - (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled"); - - pci_read_config_byte(bmide_dev, 0x40+2*pos, ®00); - pci_read_config_byte(bmide_dev, 0x41+2*pos, ®01); - pci_read_config_byte(bmide_dev, 0x44+2*pos, ®10); - pci_read_config_byte(bmide_dev, 0x45+2*pos, ®11); + if (chipset_family < ATA_133) { + pci_read_config_byte(bmide_dev, 0x4b, ®00); + p += sprintf(p, "Drive %d: Postwrite %s \t \t Postwrite %s\n", + pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled", + (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled"); + p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", + (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled", + (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled"); + pci_read_config_byte(bmide_dev, 0x40+2*pos, ®00); + pci_read_config_byte(bmide_dev, 0x41+2*pos, ®01); + pci_read_config_byte(bmide_dev, 0x44+2*pos, ®10); + pci_read_config_byte(bmide_dev, 0x45+2*pos, ®11); + } + /* UDMA */ if (chipset_family >= ATA_33) { @@ -284,7 +326,8 @@ case ATA_33: p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break; case ATA_66: case ATA_100a: p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break; - case ATA_100: p += sprintf(p, cycle_time[reg01 & 0x0F]); break; + case ATA_100: + case ATA_133a: p += sprintf(p, cycle_time[reg01 & 0x0F]); break; case ATA_133: default: p += sprintf(p, "133+ ?"); break; } @@ -293,7 +336,8 @@ case ATA_33: p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break; case ATA_66: case ATA_100a: p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break; - case ATA_100: p += sprintf(p, cycle_time[reg11 & 0x0F]); break; + case ATA_100: + case ATA_133a: p += sprintf(p, cycle_time[reg11 & 0x0F]); break; case ATA_133: default: p += sprintf(p, "133+ ?"); break; } @@ -308,7 +352,8 @@ case ATA_33: case ATA_66: case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break; - case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break; + case ATA_100: + case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break; case ATA_133: default: p += sprintf(p, "133+ ?"); break; } @@ -319,7 +364,8 @@ case ATA_33: case ATA_66: case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break; - case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break; + case ATA_100: + case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break; case ATA_133: default: p += sprintf(p, "133+ ?"); break; } @@ -327,8 +373,10 @@ /* Data Recovery */ /* warning: may need (reg&0x07) for pre ATA66 chips */ - p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", - recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]); + if (chipset_family < ATA_133) { + p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", + recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]); + } return p; } @@ -347,7 +395,7 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - byte reg; + u8 reg; u16 reg2, reg3; p += sprintf(p, "\nSiS 5513 "); @@ -358,23 +406,34 @@ case ATA_66: p += sprintf(p, "Ultra 66"); break; case ATA_100a: case ATA_100: p += sprintf(p, "Ultra 100"); break; - case ATA_133: - default: p+= sprintf(p, "Ultra 133+"); break; + case ATA_133a: + case ATA_133: p += sprintf(p, "Ultra 133"); break; + default: p+= sprintf(p, "Unknown???"); break; } p += sprintf(p, " chipset\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); /* Status */ pci_read_config_byte(bmide_dev, 0x4a, ®); + if (chipset_family == ATA_133) { + pci_read_config_word(bmide_dev, 0x50, ®2); + pci_read_config_word(bmide_dev, 0x52, ®3); + } p += sprintf(p, "Channel Status: "); if (chipset_family < ATA_66) { p += sprintf(p, "%s \t \t \t \t %s\n", (reg & 0x04) ? "On" : "Off", (reg & 0x02) ? "On" : "Off"); - } else { + } else if (chipset_family < ATA_133) { p += sprintf(p, "%s \t \t \t \t %s \n", (reg & 0x02) ? "On" : "Off", (reg & 0x04) ? "On" : "Off"); + } else { /* ATA_133 */ + p += sprintf(p, "%s \t \t \t \t %s \n", + (reg2 & 0x02) ? "On" : "Off", + (reg3 & 0x02) ? "On" : "Off"); } /* Operation Mode */ @@ -384,7 +443,11 @@ (reg & 0x04) ? "Native" : "Compatible"); /* 80-pin cable ? */ - if (chipset_family > ATA_33) { + if (chipset_family >= ATA_133) { + p += sprintf(p, "Cable Type: %s \t \t \t %s\n", + (reg2 & 0x01) ? cable_type[1] : cable_type[0], + (reg3 & 0x01) ? cable_type[1] : cable_type[0]); + } else if (chipset_family > ATA_33) { pci_read_config_byte(bmide_dev, 0x48, ®); p += sprintf(p, "Cable Type: %s \t \t \t %s\n", (reg & 0x10) ? cable_type[1] : cable_type[0], @@ -392,10 +455,12 @@ } /* Prefetch Count */ - pci_read_config_word(bmide_dev, 0x4c, ®2); - pci_read_config_word(bmide_dev, 0x4e, ®3); - p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n", - reg2, reg3); + if (chipset_family < ATA_133) { + pci_read_config_word(bmide_dev, 0x4c, ®2); + pci_read_config_word(bmide_dev, 0x4e, ®3); + p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n", + reg2, reg3); + } p = get_masters_info(p); p = get_slaves_info(p); @@ -405,8 +470,51 @@ #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ -byte sis_proc = 0; -extern char *ide_xfer_verbose (byte xfer_rate); +u8 sis_proc = 0; + +static u8 sis5513_ratemask (ide_drive_t *drive) +{ + u8 mode = 0x00; + + switch(chipset_family) { + case ATA_133: + case ATA_133a: { mode |= 0x04; break; } + case ATA_100: + case ATA_100a: { mode |= 0x03; break; } + case ATA_66: { mode |= 0x02; break; } + case ATA_33: { mode |= 0x01; break; } + case ATA_16: + case ATA_00: + default: + return (mode &= ~0xF8); + } + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static u8 sis5513_ratefilter (ide_drive_t *drive, u8 speed) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + u8 mode = sis5513_ratemask(drive); + + switch(mode) { + case 0x04: while (speed > XFER_UDMA_6) speed--; break; + case 0x03: while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} /* @@ -418,8 +526,8 @@ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte reg4bh = 0; - byte rw_prefetch = (0x11 << drive->dn); + u8 reg4bh = 0; + u8 rw_prefetch = (0x11 << drive->dn); #ifdef DEBUG printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn); @@ -439,15 +547,15 @@ /* Set per-drive active and recovery time */ -static void config_art_rwp_pio (ide_drive_t *drive, byte pio) +static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte timing, drive_pci, test1, test2; + u8 timing, drive_pci, test1, test2; - unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; - unsigned short xfer_pio = drive->id->eide_pio_modes; + u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; + u16 xfer_pio = drive->id->eide_pio_modes; #ifdef DEBUG sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); @@ -477,12 +585,28 @@ drive->dn, pio, timing); #endif - switch(drive->dn) { - case 0: drive_pci = 0x40; break; - case 1: drive_pci = 0x42; break; - case 2: drive_pci = 0x44; break; - case 3: drive_pci = 0x46; break; - default: return; + /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */ + drive_pci = 0x40; + /* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */ + if (chipset_family >= ATA_133) { + u32 reg54h; + pci_read_config_dword(dev, 0x54, ®54h); + if (reg54h & 0x40000000) drive_pci = 0x70; + switch(drive->dn) { + case 0: drive_pci += 0x0; break; + case 1: drive_pci += 0x4; break; + case 2: drive_pci += 0x8; break; + case 3: drive_pci += 0xc; break; + default: return; + } + } else { + switch(drive->dn) { + case 0: drive_pci += 0x0; break; + case 1: drive_pci += 0x2; break; + case 2: drive_pci += 0x4; break; + case 3: drive_pci += 0x6; break; + default: return; + } } /* register layout changed with newer ATA100 chips */ @@ -503,9 +627,9 @@ } pci_write_config_byte(dev, drive_pci, test1); pci_write_config_byte(dev, drive_pci+1, test2); - } else { - switch(timing) { /* active recovery - v v */ + } else if (chipset_family < ATA_133) { + switch(timing) { /* active recovery + v v */ case 4: test1 = 0x30|0x01; break; case 3: test1 = 0x30|0x03; break; case 2: test1 = 0x40|0x04; break; @@ -513,6 +637,20 @@ default: break; } pci_write_config_byte(dev, drive_pci, test1); + } else { /* ATA_133 */ + u32 test3; + pci_read_config_dword(dev, drive_pci, &test3); + test3 &= 0xc0c00fff; + if (test3 & 0x08) { + test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12; + test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16; + test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24; + } else { + test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12; + test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16; + test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24; + } + pci_write_config_dword(dev, drive_pci, test3); } #ifdef DEBUG @@ -520,9 +658,9 @@ #endif } -static int config_chipset_for_pio (ide_drive_t *drive, byte pio) +static int config_chipset_for_pio (ide_drive_t *drive, u8 pio) { - byte speed; + u8 speed; switch(pio) { case 4: speed = XFER_PIO_4; break; @@ -533,62 +671,104 @@ } config_art_rwp_pio(drive, pio); - drive->current_speed = speed; return ide_config_drive_speed(drive, speed); } -static int sis5513_tune_chipset (ide_drive_t *drive, byte speed) +static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte drive_pci, reg; + u8 drive_pci, reg; + u32 regdw; #ifdef DEBUG sis5513_load_verify_registers(dev, "sis5513_tune_chipset start"); printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n", drive->dn, speed); #endif - switch(drive->dn) { - case 0: drive_pci = 0x40; break; - case 1: drive_pci = 0x42; break; - case 2: drive_pci = 0x44; break; - case 3: drive_pci = 0x46; break; - default: return ide_dma_off; - } #ifdef BROKEN_LEVEL #ifdef DEBUG - printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL); + printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL); #endif - if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL; + if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL; #endif - pci_read_config_byte(dev, drive_pci+1, ®); - /* Disable UDMA bit for non UDMA modes on UDMA chips */ - if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) { - reg &= 0x7F; - pci_write_config_byte(dev, drive_pci+1, reg); + u8 speed = sis5513_ratefilter(drive, xferspeed); + + /* See config_art_rwp_pio for drive pci config registers */ + drive_pci = 0x40; + if (chipset_family >= ATA_133) { + u32 reg54h; + pci_read_config_dword(dev, 0x54, ®54h); + if (reg54h & 0x40000000) drive_pci = 0x70; + switch(drive->dn) { + case 0: drive_pci += 0x0; break; + case 1: drive_pci += 0x4; break; + case 2: drive_pci += 0x8; break; + case 3: drive_pci += 0xc; break; + default: return ide_dma_off; + } + pci_read_config_dword(dev, (unsigned long)drive_pci, ®dw); + /* Disable UDMA bit for non UDMA modes on UDMA chips */ + if (speed < XFER_UDMA_0) { + regdw &= 0xfffffffb; + pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); + } + + } else { + switch(drive->dn) { + case 0: drive_pci += 0x0; break; + case 1: drive_pci += 0x2; break; + case 2: drive_pci += 0x4; break; + case 3: drive_pci += 0x6; break; + default: return ide_dma_off; + } + pci_read_config_byte(dev, drive_pci+1, ®); + /* Disable UDMA bit for non UDMA modes on UDMA chips */ + if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) { + reg &= 0x7F; + pci_write_config_byte(dev, drive_pci+1, reg); + } } /* Config chip for mode */ switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA + 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: - /* Force the UDMA bit on if we want to use UDMA */ - reg |= 0x80; - /* clean reg cycle time bits */ - reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family])) - << cycle_time_offset[chipset_family]); - /* set reg cycle time bits */ - reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0] - << cycle_time_offset[chipset_family]; - pci_write_config_byte(dev, drive_pci+1, reg); + if (chipset_family >= ATA_133) { + regdw |= 0x04; + regdw &= 0xfffff00f; + /* check if ATA133 enable */ + if (regdw & 0x08) { + regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8; + } else { + /* if ATA133 disable, we should not set speed above UDMA5 */ + if (speed > XFER_UDMA_5) + speed = XFER_UDMA_5; + regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8; + } + pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); + } else { + /* Force the UDMA bit on if we want to use UDMA */ + reg |= 0x80; + /* clean reg cycle time bits */ + reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family])) + << cycle_time_offset[chipset_family]); + /* set reg cycle time bits */ + reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0] + << cycle_time_offset[chipset_family]; + pci_write_config_byte(dev, drive_pci+1, reg); + } break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: @@ -605,14 +785,13 @@ case XFER_PIO_0: default: return((int) config_chipset_for_pio(drive, 0)); } - drive->current_speed = speed; #ifdef DEBUG sis5513_load_verify_registers(dev, "sis5513_tune_chipset end"); #endif return ((int) ide_config_drive_speed(drive, speed)); } -static void sis5513_tune_drive (ide_drive_t *drive, byte pio) +static void sis5513_tune_drive (ide_drive_t *drive, u8 pio) { (void) config_chipset_for_pio(drive, pio); } @@ -621,53 +800,56 @@ /* * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four)) */ -static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) +static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - - byte speed = 0; - - byte unit = (drive->select.b.unit & 0x01); - byte udma_66 = eighty_ninty_three(drive); + u8 mode = sis5513_ratemask(drive); + u8 speed = 0; #ifdef DEBUG - printk("SIS5513: config_chipset_for_dma, drive %d, ultra %d\n", - drive->dn, ultra); + printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x, udma_66 %x\n", + drive->dn, id->dma_ultra); #endif - if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (chipset_family >= ATA_100a)) - speed = XFER_UDMA_5; - else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (chipset_family >= ATA_66)) - speed = XFER_UDMA_4; - else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (chipset_family >= ATA_66)) - speed = XFER_UDMA_3; - else if ((id->dma_ultra & 0x0004) && ultra && (chipset_family >= ATA_33)) - speed = XFER_UDMA_2; - else if ((id->dma_ultra & 0x0002) && ultra && (chipset_family >= ATA_33)) - speed = XFER_UDMA_1; - else if ((id->dma_ultra & 0x0001) && ultra && (chipset_family >= ATA_33)) - speed = XFER_UDMA_0; - else if (id->dma_mword & 0x0004) - speed = XFER_MW_DMA_2; - else if (id->dma_mword & 0x0002) - speed = XFER_MW_DMA_1; - else if (id->dma_mword & 0x0001) - speed = XFER_MW_DMA_0; - else if (id->dma_1word & 0x0004) - speed = XFER_SW_DMA_2; - else if (id->dma_1word & 0x0002) - speed = XFER_SW_DMA_1; - else if (id->dma_1word & 0x0001) - speed = XFER_SW_DMA_0; - else - return ((int) ide_dma_off_quietly); - - outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); - + switch(mode) { + case 0x04: + if (id->dma_ultra & 0x0040) + { speed = XFER_UDMA_6; break; } + case 0x03: + if (id->dma_ultra & 0x0020) + { speed = XFER_UDMA_5; break; } + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_mword & 0x0001) + { speed = XFER_MW_DMA_0; break; } + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + if (id->dma_1word & 0x0002) + { speed = XFER_SW_DMA_1; break; } + if (id->dma_1word & 0x0001) + { speed = XFER_SW_DMA_0; break; } + default: + return ((int) ide_dma_off_quietly); + } sis5513_tune_chipset(drive, speed); - return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : + return ((int) ((id->dma_ultra >> 14) & 3) ? ide_dma_on : + ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : ((id->dma_1word >> 8) & 7) ? ide_dma_on : @@ -679,7 +861,7 @@ struct hd_driveid *id = drive->id; ide_dma_action_t dma_func = ide_dma_off_quietly; - (void) config_chipset_for_pio(drive, 5); +// drive->init_speed = 0; if (id && (id->capability & 1) && HWIF(drive)->autodma) { /* Consult the list of known "bad" drives */ @@ -691,7 +873,7 @@ if (id->field_valid & 4) { if (id->dma_ultra & 0x003F) { /* Force if Capable UltraDMA */ - dma_func = config_chipset_for_dma(drive, 1); + dma_func = config_chipset_for_dma(drive); if ((id->field_valid & 2) && (dma_func != ide_dma_on)) goto try_dma_modes; @@ -701,14 +883,14 @@ if ((id->dma_mword & 0x0007) || (id->dma_1word & 0x0007)) { /* Force if Capable regular DMA modes */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } } else if ((ide_dmaproc(ide_dma_good_drive, drive)) && (id->eide_dma_time > 150)) { /* Consult the list of known "good" drives */ - dma_func = config_chipset_for_dma(drive, 0); + dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) goto no_dma_set; } else { @@ -718,7 +900,7 @@ fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - (void) config_chipset_for_pio(drive, 5); + sis5513_tune_drive(drive, 5); } return HWIF(drive)->dmaproc(dma_func, drive); @@ -755,7 +937,32 @@ host_dev = host; chipset_family = SiSHostChipInfo[i].chipset_family; + + /* check 100/133 chipset family */ + if (chipset_family == ATA_133) { + u32 reg54h; + u16 reg02h; + pci_read_config_dword(dev, 0x54, ®54h); + pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff)); + pci_read_config_word(dev, 0x02, ®02h); + pci_write_config_dword(dev, 0x54, reg54h); + /* devid 5518 here means SiS962 or later + which supports ATA133 */ + if (reg02h != 0x5518) { + byte reg49h; + unsigned long sbrev; + /* SiS961 family */ + outl(0x80001008, 0x0cf8); + sbrev = inl(0x0cfc); + pci_read_config_byte(dev, 0x49, ®49h); + if (((sbrev & 0xff) == 0x10) && (reg49h & 0x80)) + chipset_family = ATA_133a; + else + chipset_family = ATA_100; + } + } printk(SiSHostChipInfo[i].name); + printk(" %s controller", chipset_capability[chipset_family]); printk("\n"); #ifdef DEBUG @@ -772,9 +979,19 @@ 1/ tell IDE channels to operate in Compabitility mode only 2/ tell old chips to allow per drive IDE timings */ if (host_dev) { - byte reg; + u8 reg; + u16 regw; switch(chipset_family) { case ATA_133: + /* SiS962 operation mode */ + pci_read_config_word(dev, 0x50, ®w); + if (regw & 0x08) + pci_write_config_word(dev, 0x50, regw&0xfff7); + pci_read_config_word(dev, 0x52, ®w); + if (regw & 0x08) + pci_write_config_word(dev, 0x52, regw&0xfff7); + break; + case ATA_133a: case ATA_100: /* Set compatibility bit */ pci_read_config_byte(dev, 0x49, ®); @@ -824,11 +1041,17 @@ unsigned int __init ata66_sis5513 (ide_hwif_t *hwif) { - byte reg48h = 0, ata66 = 0; - byte mask = hwif->channel ? 0x20 : 0x10; - pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); + byte ata66 = 0; - if (chipset_family >= ATA_66) { + if (chipset_family >= ATA_133) { + u16 regw = 0; + u16 reg_addr = hwif->channel ? 0x52: 0x50; + pci_read_config_word(hwif->pci_dev, reg_addr, ®w); + ata66 = (regw & 0x8000) ? 0 : 1; + } else if (chipset_family >= ATA_66) { + byte reg48h = 0; + byte mask = hwif->channel ? 0x20 : 0x10; + pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); ata66 = (reg48h & mask) ? 0 : 1; } return ata66; @@ -841,21 +1064,36 @@ hwif->tuneproc = &sis5513_tune_drive; hwif->speedproc = &sis5513_tune_chipset; +// hwif->drives[0].autotune = 1; +// hwif->drives[1].autotune = 1; + hwif->autodma = 0; if (!(hwif->dma_base)) return; - if (host_dev) { #ifdef CONFIG_BLK_DEV_IDEDMA - if (chipset_family > ATA_16) { - hwif->autodma = noautodma ? 0 : 1; + if (host_dev) { + if (chipset_family > ATA_16) hwif->dmaproc = &sis5513_dmaproc; - } else { -#endif + else hwif->autodma = 0; -#ifdef CONFIG_BLK_DEV_IDEDMA - } -#endif } +# ifdef CONFIG_IDEDMA_AUTO + if (!noautodma) + hwif->autodma = 1; +# endif +#endif return; } + +extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d); + +void __init fixup_device_sis5513 (struct pci_dev *dev, ide_pci_device_t *d) +{ + if (dev->resource[0].start != 0x01F1) + ide_register_xp_fix(dev); + + printk("%s: IDE controller on PCI bus %02x dev %02x\n", + d->name, dev->bus->number, dev->devfn); + ide_setup_pci_device(dev, d); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/sl82c105.c linux.20pre2-ac1/drivers/ide/sl82c105.c --- linux.20pre2/drivers/ide/sl82c105.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/sl82c105.c 2002-08-06 15:42:11.000000000 +0100 @@ -26,8 +26,6 @@ #include "ide_modes.h" -extern char *ide_xfer_verbose (byte xfer_rate); - /* * Convert a PIO mode and cycle time to the required on/off * times for the interface. This has protection against run-away @@ -243,7 +241,7 @@ unsigned int rev; byte dma_state; - dma_state = inb(dma_base + 2); + dma_state = IN_BYTE(dma_base + 2); rev = sl82c105_bridge_revision(hwif->pci_dev); if (rev <= 5) { hwif->autodma = 0; @@ -256,7 +254,7 @@ dma_state |= 0x60; hwif->autodma = 1; } - outb(dma_state, dma_base + 2); + OUT_BYTE(dma_state, dma_base + 2); hwif->dmaproc = NULL; ide_setup_dma(hwif, dma_base, 8); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/slc90e66.c linux.20pre2-ac1/drivers/ide/slc90e66.c --- linux.20pre2/drivers/ide/slc90e66.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/slc90e66.c 2002-08-06 15:42:11.000000000 +0100 @@ -60,7 +60,6 @@ static int slc90e66_get_info(char *, char **, off_t, int); extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */ -extern char *ide_media_verbose(ide_drive_t *); static struct pci_dev *bmide_dev; static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count) @@ -95,22 +94,29 @@ #endif p += sprintf(p, " SLC90E66 Chipset.\n"); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); - p += sprintf(p, " %sabled %sabled\n", + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", (c0&0x80) ? "dis" : " en", (c1&0x80) ? "dis" : " en"); - p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s %s %s\n", + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s " + " %s %s\n", (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + p += sprintf(p, "UDMA enabled: %s %s " + " %s %s\n", (reg48&0x01) ? "yes" : "no ", (reg48&0x02) ? "yes" : "no ", (reg48&0x04) ? "yes" : "no ", (reg48&0x08) ? "yes" : "no " ); - p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + p += sprintf(p, "UDMA enabled: %s %s " + " %s %s\n", ((reg4a&0x04)==0x04) ? "4" : ((reg4a&0x03)==0x03) ? "3" : (reg4a&0x02) ? "2" : @@ -150,12 +156,40 @@ byte slc90e66_proc = 0; -extern char *ide_xfer_verbose (byte xfer_rate); +static byte slc90e66_ratemask (ide_drive_t *drive) +{ + byte mode = 0x00; + + mode |= 0x02; + if (!eighty_ninty_three(drive)) { + mode &= ~0xFE; + mode |= 0x01; + } + return (mode &= ~0xF8); +} + +static byte slc90e66_ratefilter (ide_drive_t *drive, byte speed) +{ #ifdef CONFIG_BLK_DEV_IDEDMA -/* - * - */ + byte mode = slc90e66_ratemask(drive); + + switch(mode) { + case 0x04: // while (speed > XFER_UDMA_6) speed--; break; + case 0x03: // while (speed > XFER_UDMA_5) speed--; break; + case 0x02: while (speed > XFER_UDMA_4) speed--; break; + case 0x01: while (speed > XFER_UDMA_2) speed--; break; + case 0x00: + default: while (speed > XFER_MW_DMA_2) speed--; break; + break; + } +#else + while (speed > XFER_PIO_4) speed--; +#endif /* CONFIG_BLK_DEV_IDEDMA */ +// printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed); + return speed; +} + static byte slc90e66_dma_2_pio (byte xfer_rate) { switch(xfer_rate) { case XFER_UDMA_4: @@ -182,7 +216,6 @@ return 0; } } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * Based on settings done by AMI BIOS @@ -190,12 +223,14 @@ */ static void slc90e66_tune_drive (ide_drive_t *drive, byte pio) { + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int is_slave = (&hwif->drives[1] == drive); + int master_port = hwif->channel ? 0x42 : 0x40; + int slave_port = 0x44; unsigned long flags; u16 master_data; byte slave_data; - int is_slave = (&HWIF(drive)->drives[1] == drive); - int master_port = HWIF(drive)->index ? 0x42 : 0x40; - int slave_port = 0x44; /* ISP RTC */ byte timings[][2] = { { 0, 0 }, { 0, 0 }, @@ -204,42 +239,38 @@ { 2, 3 }, }; pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data); + spin_lock_irqsave(&io_request_lock, flags); + pci_read_config_word(dev, master_port, &master_data); if (is_slave) { master_data = master_data | 0x4000; if (pio > 1) /* enable PPE, IE and TIME */ master_data = master_data | 0x0070; - pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data); - slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0); - slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1] - << (HWIF(drive)->index ? 4 : 0))); + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); + slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); } else { master_data = master_data & 0xccf8; if (pio > 1) /* enable PPE, IE and TIME */ master_data = master_data | 0x0007; - master_data = master_data | (timings[pio][0] << 12) | - (timings[pio][1] << 8); + master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); } - save_flags(flags); - cli(); - pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data); + pci_write_config_word(dev, master_port, master_data); if (is_slave) - pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data); - restore_flags(flags); + pci_write_config_byte(dev, slave_port, slave_data); + spin_unlock_irqrestore(&io_request_lock, flags); } -#ifdef CONFIG_BLK_DEV_IDEDMA -static int slc90e66_tune_chipset (ide_drive_t *drive, byte speed) +static int slc90e66_tune_chipset (ide_drive_t *drive, byte xferspeed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; byte maslave = hwif->channel ? 0x42 : 0x40; + byte speed = slc90e66_ratefilter(drive, xferspeed); int a_speed = 7 << (drive->dn * 4); int u_flag = 1 << drive->dn; int u_speed = 0; - int err = 0; int sitre; short reg4042, reg44, reg48, reg4a; @@ -250,6 +281,7 @@ pci_read_config_word(dev, 0x4a, ®4a); switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_4: u_speed = 4 << (drive->dn * 4); break; case XFER_UDMA_3: u_speed = 3 << (drive->dn * 4); break; case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; @@ -258,9 +290,12 @@ case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; -#if 0 /* allow PIO modes */ +#endif /* CONFIG_BLK_DEV_IDEDMA */ + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_0: break; default: return -1; -#endif } if (speed >= XFER_UDMA_0) { @@ -271,8 +306,7 @@ pci_read_config_word(dev, 0x4a, ®4a); pci_write_config_word(dev, 0x4a, reg4a|u_speed); } - } - if (speed < XFER_UDMA_0) { + } else { if (reg48 & u_flag) pci_write_config_word(dev, 0x48, reg48 & ~u_flag); if (reg4a & a_speed) @@ -280,53 +314,45 @@ } slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed)); - -#if SLC90E66_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); -#endif /* SLC90E66_DEBUG_DRIVE_INFO */ - if (!drive->init_speed) - drive->init_speed = speed; - err = ide_config_drive_speed(drive, speed); - drive->current_speed = speed; - return err; + return (ide_config_drive_speed(drive, speed)); } +#ifdef CONFIG_BLK_DEV_IDEDMA static int slc90e66_config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; - int ultra = 1; - byte speed = 0; - byte udma_66 = eighty_ninty_three(drive); - -#if 1 /* allow PIO modes */ - if (!HWIF(drive)->autodma) { - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); - (void) slc90e66_tune_chipset(drive, speed); - return ((int) ide_dma_off_quietly); - } -#endif - if ((id->dma_ultra & 0x0010) && (ultra)) { - speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0008) && (ultra)) { - speed = (udma_66) ? XFER_UDMA_3 : XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0004) && (ultra)) { - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (ultra)) { - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (ultra)) { - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else { - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + byte mode = slc90e66_ratemask(drive); + byte speed, tspeed, dma = 1; + + switch(mode) { + case 0x02: + if (id->dma_ultra & 0x0010) + { speed = XFER_UDMA_4; break; } + if (id->dma_ultra & 0x0008) + { speed = XFER_UDMA_3; break; } + case 0x01: + if (id->dma_ultra & 0x0004) + { speed = XFER_UDMA_2; break; } + if (id->dma_ultra & 0x0002) + { speed = XFER_UDMA_1; break; } + if (id->dma_ultra & 0x0001) + { speed = XFER_UDMA_0; break; } + case 0x00: + if (id->dma_mword & 0x0004) + { speed = XFER_MW_DMA_2; break; } + if (id->dma_mword & 0x0002) + { speed = XFER_MW_DMA_1; break; } + if (id->dma_1word & 0x0004) + { speed = XFER_SW_DMA_2; break; } + default: + tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); + speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed); + dma = 0; + break; } (void) slc90e66_tune_chipset(drive, speed); - +// return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly); return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : @@ -334,11 +360,62 @@ ide_dma_off_quietly); } +static int config_drive_xfer_rate (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_dma_action_t dma_func = ide_dma_on; + + drive->init_speed = 0; + + if (id && (id->capability & 1) && HWIF(drive)->autodma) { + /* Consult the list of known "bad" drives */ + if (ide_dmaproc(ide_dma_bad_drive, drive)) { + dma_func = ide_dma_off; + goto fast_ata_pio; + } + dma_func = ide_dma_off_quietly; + if (id->field_valid & 4) { + if (id->dma_ultra & 0x007F) { + /* Force if Capable UltraDMA */ + dma_func = slc90e66_config_drive_for_dma(drive); + if ((id->field_valid & 2) && + (dma_func != ide_dma_on)) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & 0x0007) || + (id->dma_1word & 0x007)) { + /* Force if Capable regular DMA modes */ + dma_func = slc90e66_config_drive_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } + } else if (ide_dmaproc(ide_dma_good_drive, drive)) { + if (id->eide_dma_time > 150) { + goto no_dma_set; + } + /* Consult the list of known "good" drives */ + dma_func = slc90e66_config_drive_for_dma(drive); + if (dma_func != ide_dma_on) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + dma_func = ide_dma_off_quietly; +no_dma_set: + slc90e66_tune_drive(drive, 5); + } + return HWIF(drive)->dmaproc(dma_func, drive); +} + static int slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { switch (func) { case ide_dma_check: - return ide_dmaproc((ide_dma_action_t) slc90e66_config_drive_for_dma(drive), drive); + return config_drive_xfer_rate(drive); default : break; } @@ -361,16 +438,11 @@ unsigned int __init ata66_slc90e66 (ide_hwif_t *hwif) { -#if 1 byte reg47 = 0, ata66 = 0; byte mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */ pci_read_config_byte(hwif->pci_dev, 0x47, ®47); - ata66 = (reg47 & mask) ? 0 : 1; /* bit[0(1)]: 0:80, 1:40 */ -#else - byte ata66 = 0; -#endif return ata66; } @@ -379,6 +451,8 @@ if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; + hwif->autodma = 0; + hwif->speedproc = &slc90e66_tune_chipset; hwif->tuneproc = &slc90e66_tune_drive; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; @@ -386,11 +460,11 @@ if (!hwif->dma_base) return; - hwif->autodma = 0; #ifdef CONFIG_BLK_DEV_IDEDMA + hwif->dmaproc = &slc90e66_dmaproc; +#ifdef CONFIG_IDEDMA_AUTO if (!noautodma) hwif->autodma = 1; - hwif->dmaproc = &slc90e66_dmaproc; - hwif->speedproc = &slc90e66_tune_chipset; +#endif /* CONFIG_IDEDMA_AUTO */ #endif /* !CONFIG_BLK_DEV_IDEDMA */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/trm290.c linux.20pre2-ac1/drivers/ide/trm290.c --- linux.20pre2/drivers/ide/trm290.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/trm290.c 2002-08-06 15:42:11.000000000 +0100 @@ -148,23 +148,23 @@ /* select PIO or DMA */ reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82); - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); if (reg != hwif->select_data) { hwif->select_data = reg; - outb(0x51|(hwif->channel<<3), hwif->config_data+1); /* set PIO/DMA */ - outw(reg & 0xff, hwif->config_data); + /* set PIO/DMA */ + OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1); + OUT_WORD(reg & 0xff, hwif->config_data); } /* enable IRQ if not probing */ if (drive->present) { - reg = inw(hwif->config_data+3) & 0x13; + reg = IN_WORD(hwif->config_data+3) & 0x13; reg &= ~(1 << hwif->channel); - outw(reg, hwif->config_data+3); + OUT_WORD(reg, hwif->config_data+3); } - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); } static void trm290_selectproc (ide_drive_t *drive) @@ -176,6 +176,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); +// ide_task_t *args = HWGROUP(drive)->rq->special; unsigned int count, reading = 2, writing = 0; switch (func) { @@ -187,24 +188,46 @@ #endif case ide_dma_read: if (!(count = ide_build_dmatable(drive, func))) - break; /* try PIO instead of DMA */ - trm290_prepare_drive(drive, 1); /* select DMA xfer */ + /* try PIO instead of DMA */ + break; + /* select DMA xfer */ + trm290_prepare_drive(drive, 1); outl(hwif->dmatable_dma|reading|writing, hwif->dma_base); drive->waiting_for_dma = 1; - outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ + /* start DMA */ + OUT_WORD((count * 2) - 1, hwif->dma_base+2); if (drive->media != ide_disk) return 0; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); - OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); - return 0; +/* + * FIX ME to use only ACB ide_task_t args Struct + */ +#if 0 + { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } +#else + if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) { + ide_task_t *args = HWGROUP(drive)->rq->special; + OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG); + } else if (drive->addressing == 1) + OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG); + else + OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); +#endif + return HWIF(drive)->dmaproc(ide_dma_begin, drive); case ide_dma_begin: return 0; case ide_dma_end: drive->waiting_for_dma = 0; - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (inw(hwif->dma_base+2) != 0x00ff); + /* purge DMA mappings */ + ide_destroy_dmatable(drive); + return (IN_WORD(hwif->dma_base+2) != 0x00ff); case ide_dma_test_irq: - return (inw(hwif->dma_base+2) == 0x00ff); + return (IN_WORD(hwif->dma_base+2) == 0x00ff); default: return ide_dmaproc(func, drive); } @@ -225,25 +248,28 @@ hwif->chipset = ide_trm290; cfgbase = pci_resource_start(dev, 4); - if ((dev->class & 5) && cfgbase) - { + if ((dev->class & 5) && cfgbase) { hwif->config_data = cfgbase; - printk("TRM290: chip config base at 0x%04lx\n", hwif->config_data); + printk("TRM290: chip config base at 0x%04lx\n", + hwif->config_data); } else { hwif->config_data = 0x3df0; - printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data); + printk("TRM290: using default config base at 0x%04lx\n", + hwif->config_data); } - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); /* put config reg into first byte of hwif->select_data */ - outb(0x51|(hwif->channel<<3), hwif->config_data+1); - hwif->select_data = 0x21; /* select PIO as default */ - outb(hwif->select_data, hwif->config_data); - reg = inb(hwif->config_data+3); /* get IRQ info */ - reg = (reg & 0x10) | 0x03; /* mask IRQs for both ports */ - outb(reg, hwif->config_data+3); - __restore_flags(flags); /* local CPU only */ + OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1); + /* select PIO as default */ + hwif->select_data = 0x21; + OUT_BYTE(hwif->select_data, hwif->config_data); + /* get IRQ info */ + reg = IN_BYTE(hwif->config_data+3); + /* mask IRQs for both ports */ + reg = (reg & 0x10) | 0x03; + OUT_BYTE(reg, hwif->config_data+3); + local_irq_restore(flags); if ((reg & 0x10)) hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ @@ -256,20 +282,20 @@ #endif /* CONFIG_BLK_DEV_IDEDMA */ hwif->selectproc = &trm290_selectproc; - hwif->autodma = 0; /* play it safe for now */ + hwif->autodma = 0; /* play it safe for now */ #if 1 { - /* - * My trm290-based card doesn't seem to work with all possible values - * for the control basereg, so this kludge ensures that we use only - * values that are known to work. Ugh. -ml - */ + /* + * My trm290-based card doesn't seem to work with all possible values + * for the control basereg, so this kludge ensures that we use only + * values that are known to work. Ugh. -ml + */ unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4; static unsigned short next_offset = 0; - outb(0x54|(hwif->channel<<3), hwif->config_data+1); - old = inw(hwif->config_data) & ~1; - if (old != compat && inb(old+2) == 0xff) { + OUT_BYTE(0x54|(hwif->channel<<3), hwif->config_data+1); + old = IN_WORD(hwif->config_data) & ~1; + if (old != compat && IN_BYTE(old+2) == 0xff) { compat += (next_offset += 0x400); /* leave lower 10 bits untouched */ #if 1 if (ide_check_region(compat + 2, 1)) @@ -281,8 +307,8 @@ */ #endif hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; - outw(compat|1, hwif->config_data); - printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1); + OUT_WORD(compat|1, hwif->config_data); + printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, IN_WORD(hwif->config_data) & ~1); } } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/umc8672.c linux.20pre2-ac1/drivers/ide/umc8672.c --- linux.20pre2/drivers/ide/umc8672.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/umc8672.c 2002-08-06 15:42:11.000000000 +0100 @@ -73,36 +73,34 @@ static void out_umc (char port,char wert) { - outb_p (port,0x108); - outb_p (wert,0x109); + outb_p(port,0x108); + outb_p(wert,0x109); } static inline byte in_umc (char port) { - outb_p (port,0x108); - return inb_p (0x109); + outb_p(port,0x108); + return inb_p(0x109); } static void umc_set_speeds (byte speeds[]) { int i, tmp; - outb_p (0x5A,0x108); /* enable umc */ + outb_p(0x5A,0x108); /* enable umc */ out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4))); out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4))); tmp = 0; - for (i = 3; i >= 0; i--) - { + for (i = 3; i >= 0; i--) { tmp = (tmp << 2) | speedtab[1][speeds[i]]; } out_umc (0xdc,tmp); - for (i = 0;i < 4; i++) - { + for (i = 0;i < 4; i++) { out_umc (0xd0+i,speedtab[2][speeds[i]]); out_umc (0xd8+i,speedtab[2][speeds[i]]); } - outb_p (0xa5,0x108); /* disable umc */ + outb_p(0xa5,0x108); /* disable umc */ printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n", speeds[0], speeds[1], speeds[2], speeds[3]); @@ -114,40 +112,38 @@ ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup; pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ + printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", + drive->name, pio, pio_to_umc[pio]); + spin_lock_irqsave(&io_request_lock, flags); if (hwgroup && hwgroup->handler != NULL) { printk("umc8672: other interface is busy: exiting tune_umc()\n"); } else { current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; umc_set_speeds (current_speeds); } - restore_flags(flags); /* all CPUs */ + spin_unlock_irqrestore(&io_request_lock, flags); } void __init init_umc8672 (void) /* called from ide.c */ { unsigned long flags; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ + local_irq_save(flags); if (check_region(0x108, 2)) { - __restore_flags(flags); + local_irq_restore(flags); printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n"); return; } - outb_p (0x5A,0x108); /* enable umc */ - if (in_umc (0xd5) != 0xa0) - { - __restore_flags(flags); /* local CPU only */ + outb_p(0x5A,0x108); /* enable umc */ + if (in_umc (0xd5) != 0xa0) { + local_irq_restore(flags); printk ("umc8672: not found\n"); return; } - outb_p (0xa5,0x108); /* disable umc */ + outb_p(0xa5,0x108); /* disable umc */ umc_set_speeds (current_speeds); - __restore_flags(flags); /* local CPU only */ + local_irq_restore(flags); request_region(0x108, 2, "umc8672"); ide_hwifs[0].chipset = ide_umc8672; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/ide/via82cxxx.c linux.20pre2-ac1/drivers/ide/via82cxxx.c --- linux.20pre2/drivers/ide/via82cxxx.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/ide/via82cxxx.c 2002-08-06 15:42:11.000000000 +0100 @@ -193,7 +193,7 @@ pci_read_config_byte(dev, VIA_IDE_ENABLE, &t); via_print("Enabled: %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no"); - c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8); + c = IN_BYTE(via_base + 0x02) | (IN_BYTE(via_base + 0x0a) << 8); via_print("Simplex only: %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no"); via_print("Cable Type: %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/isdn/hisax/hisax_debug.h linux.20pre2-ac1/drivers/isdn/hisax/hisax_debug.h --- linux.20pre2/drivers/isdn/hisax/hisax_debug.h 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/isdn/hisax/hisax_debug.h 2002-08-12 13:07:48.000000000 +0100 @@ -28,7 +28,7 @@ #define DBG(level, format, arg...) do { \ if (level & __debug_variable) \ -printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \ +printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__, ## arg); \ } while (0) #define DBG_PACKET(level,data,count) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/isdn/hisax/st5481.h linux.20pre2-ac1/drivers/isdn/hisax/st5481.h --- linux.20pre2/drivers/isdn/hisax/st5481.h 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/isdn/hisax/st5481.h 2002-08-14 14:41:30.000000000 +0100 @@ -219,13 +219,13 @@ #define L1_EVENT_COUNT (EV_TIMER3 + 1) #define ERR(format, arg...) \ -printk(KERN_ERR __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg) +printk(KERN_ERR __FILE__ ": %s: " format "\n" , __FUNCTION__, ## arg) #define WARN(format, arg...) \ -printk(KERN_WARNING __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg) +printk(KERN_WARNING __FILE__ ": %s: " format "\n" , __FUNCTION__, ## arg) #define INFO(format, arg...) \ -printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg) +printk(KERN_INFO __FILE__ ": %s: " format "\n" , __FUNCTION__, ## arg) #include "st5481_hdlc.h" #include "fsm.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/isdn/hisax/st5481_usb.c linux.20pre2-ac1/drivers/isdn/hisax/st5481_usb.c --- linux.20pre2/drivers/isdn/hisax/st5481_usb.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/isdn/hisax/st5481_usb.c 2002-08-13 14:23:52.000000000 +0100 @@ -41,9 +41,9 @@ (unsigned char *)&ctrl->msg_fifo.data[r_index]; DBG(1,"request=0x%02x,value=0x%04x,index=%x", - ((struct ctrl_msg *)urb->setup_packet)->dr.request, - ((struct ctrl_msg *)urb->setup_packet)->dr.value, - ((struct ctrl_msg *)urb->setup_packet)->dr.index); + ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest, + ((struct ctrl_msg *)urb->setup_packet)->dr.wValue, + ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex); // Prepare the URB urb->dev = adapter->usb_dev; @@ -69,11 +69,11 @@ } ctrl_msg = &ctrl->msg_fifo.data[w_index]; - ctrl_msg->dr.requesttype = requesttype; - ctrl_msg->dr.request = request; - ctrl_msg->dr.value = cpu_to_le16p(&value); - ctrl_msg->dr.index = cpu_to_le16p(&index); - ctrl_msg->dr.length = 0; + ctrl_msg->dr.bRequestType = requesttype; + ctrl_msg->dr.bRequest = request; + ctrl_msg->dr.wValue = cpu_to_le16p(&value); + ctrl_msg->dr.wIndex = cpu_to_le16p(&index); + ctrl_msg->dr.wLength = 0; ctrl_msg->complete = complete; ctrl_msg->context = context; @@ -140,17 +140,17 @@ ctrl_msg = (struct ctrl_msg *)urb->setup_packet; - if (ctrl_msg->dr.request == USB_REQ_CLEAR_FEATURE) { + if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { /* Special case handling for pipe reset */ - le16_to_cpus(&ctrl_msg->dr.index); + le16_to_cpus(&ctrl_msg->dr.wIndex); usb_endpoint_running(adapter->usb_dev, - ctrl_msg->dr.index & ~USB_DIR_IN, - (ctrl_msg->dr.index & USB_DIR_IN) == 0); + ctrl_msg->dr.wIndex & ~USB_DIR_IN, + (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0); /* toggle is reset on clear */ usb_settoggle(adapter->usb_dev, - ctrl_msg->dr.index & ~USB_DIR_IN, - (ctrl_msg->dr.index & USB_DIR_IN) == 0, + ctrl_msg->dr.wIndex & ~USB_DIR_IN, + (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0, 0); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/Config.in linux.20pre2-ac1/drivers/md/Config.in --- linux.20pre2/drivers/md/Config.in 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/Config.in 2002-08-12 22:42:29.000000000 +0100 @@ -14,5 +14,8 @@ dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Device-mapper support (EXPERIMENTAL)' CONFIG_BLK_DEV_DM $CONFIG_MD +fi endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm.c linux.20pre2-ac1/drivers/md/dm.c --- linux.20pre2/drivers/md/dm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm.c 2002-08-12 22:44:36.000000000 +0100 @@ -0,0 +1,1172 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include + +/* we only need this for the lv_bmap struct definition, not happy */ +#include + +#define DEFAULT_READ_AHEAD 64 + +static const char *_name = DM_NAME; + +static int major = 0; +static int _major = 0; + +struct io_hook { + struct mapped_device *md; + struct target *target; + int rw; + + void (*end_io) (struct buffer_head * bh, int uptodate); + void *context; +}; + +static kmem_cache_t *_io_hook_cache; + +static struct mapped_device *_devs[MAX_DEVICES]; +static struct rw_semaphore _dev_locks[MAX_DEVICES]; + +/* + * This lock is only held by dm_create and dm_set_name to avoid + * race conditions where someone else may create a device with + * the same name. + */ +static spinlock_t _create_lock = SPIN_LOCK_UNLOCKED; + +/* block device arrays */ +static int _block_size[MAX_DEVICES]; +static int _blksize_size[MAX_DEVICES]; +static int _hardsect_size[MAX_DEVICES]; + +static devfs_handle_t _dev_dir; + +static int request(request_queue_t * q, int rw, struct buffer_head *bh); +static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb); + +/* + * Protect the mapped_devices referenced from _dev[] + */ +struct mapped_device *dm_get_r(int minor) +{ + struct mapped_device *md; + + if (minor >= MAX_DEVICES) + return NULL; + + down_read(_dev_locks + minor); + md = _devs[minor]; + if (!md) + up_read(_dev_locks + minor); + return md; +} + +struct mapped_device *dm_get_w(int minor) +{ + struct mapped_device *md; + + if (minor >= MAX_DEVICES) + return NULL; + + down_write(_dev_locks + minor); + md = _devs[minor]; + if (!md) + up_write(_dev_locks + minor); + return md; +} + +static int namecmp(struct mapped_device *md, const char *name, int nametype) +{ + switch (nametype) { + case DM_LOOKUP_BY_NAME: + return strcmp(md->name, name); + break; + + case DM_LOOKUP_BY_UUID: + if (!md->uuid) + return -1; /* never equal */ + + return strcmp(md->uuid, name); + break; + + default: + DMWARN("Unknown comparison type in namecmp: %d", nametype); + BUG(); + } + + return -1; +} + +/* + * The interface (eg, ioctl) will probably access the devices + * through these slow 'by name' locks, this needs improving at + * some point if people start playing with *large* numbers of dm + * devices. + */ +struct mapped_device *dm_get_name_r(const char *name, int nametype) +{ + int i; + struct mapped_device *md; + + for (i = 0; i < MAX_DEVICES; i++) { + md = dm_get_r(i); + if (md) { + if (!namecmp(md, name, nametype)) + return md; + + dm_put_r(md); + } + } + + return NULL; +} + +struct mapped_device *dm_get_name_w(const char *name, int nametype) +{ + int i; + struct mapped_device *md; + + /* + * To avoid getting write locks on all the devices we try + * and promote a read lock to a write lock, this can + * fail, in which case we just start again. + */ + + restart: + for (i = 0; i < MAX_DEVICES; i++) { + md = dm_get_r(i); + if (!md) + continue; + + if (namecmp(md, name, nametype)) { + dm_put_r(md); + continue; + } + + /* found it */ + dm_put_r(md); + + md = dm_get_w(i); + if (!md) + goto restart; + + if (namecmp(md, name, nametype)) { + dm_put_w(md); + goto restart; + } + + return md; + } + + return NULL; +} + +void dm_put_r(struct mapped_device *md) +{ + int minor = MINOR(md->dev); + + if (minor >= MAX_DEVICES) + return; + + up_read(_dev_locks + minor); +} + +void dm_put_w(struct mapped_device *md) +{ + int minor = MINOR(md->dev); + + if (minor >= MAX_DEVICES) + return; + + up_write(_dev_locks + minor); +} + +/* + * Setup and tear down the driver + */ +static __init void init_locks(void) +{ + int i; + + for (i = 0; i < MAX_DEVICES; i++) + init_rwsem(_dev_locks + i); +} + +static __init int local_init(void) +{ + int r; + + init_locks(); + + /* allocate a slab for the io-hooks */ + if (!_io_hook_cache && + !(_io_hook_cache = kmem_cache_create("dm io hooks", + sizeof(struct io_hook), + 0, 0, NULL, NULL))) + return -ENOMEM; + + _major = major; + r = devfs_register_blkdev(_major, _name, &dm_blk_dops); + if (r < 0) { + DMERR("register_blkdev failed"); + kmem_cache_destroy(_io_hook_cache); + return r; + } + + if (!_major) + _major = r; + + /* set up the arrays */ + read_ahead[_major] = DEFAULT_READ_AHEAD; + blk_size[_major] = _block_size; + blksize_size[_major] = _blksize_size; + hardsect_size[_major] = _hardsect_size; + + blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), request); + + _dev_dir = devfs_mk_dir(0, DM_DIR, NULL); + + return 0; +} + +static void local_exit(void) +{ + if (kmem_cache_destroy(_io_hook_cache)) + DMWARN("io_hooks still allocated during unregistration"); + _io_hook_cache = NULL; + + if (devfs_unregister_blkdev(_major, _name) < 0) + DMERR("devfs_unregister_blkdev failed"); + + read_ahead[_major] = 0; + blk_size[_major] = NULL; + blksize_size[_major] = NULL; + hardsect_size[_major] = NULL; + _major = 0; + + DMINFO("cleaned up"); +} + +/* + * We have a lot of init/exit functions, so it seems easier to + * store them in an array. The disposable macro 'xx' + * expands a prefix into a pair of function names. + */ +static struct { + int (*init)(void); + void (*exit)(void); + +} _inits[] = { +#define xx(n) {n ## _init, n ## _exit}, + xx(local) + xx(dm_target) + xx(dm_linear) + xx(dm_stripe) + xx(dm_snapshot) + xx(dm_interface) +#undef xx +}; + +static int __init dm_init(void) +{ + const int count = sizeof(_inits) / sizeof(*_inits); + + int r, i; + + for (i = 0; i < count; i++) { + r = _inits[i].init(); + if (r) + goto bad; + } + + return 0; + + bad: + while (i--) + _inits[i].exit(); + + return r; +} + +static void __exit dm_exit(void) +{ + int i = sizeof(_inits) / sizeof(*_inits); + + dm_destroy_all(); + while (i--) + _inits[i].exit(); +} + +/* + * Block device functions + */ +static int dm_blk_open(struct inode *inode, struct file *file) +{ + struct mapped_device *md; + + md = dm_get_w(MINOR(inode->i_rdev)); + if (!md) + return -ENXIO; + + md->use_count++; + dm_put_w(md); + + return 0; +} + +static int dm_blk_close(struct inode *inode, struct file *file) +{ + struct mapped_device *md; + + md = dm_get_w(MINOR(inode->i_rdev)); + if (!md) + return -ENXIO; + + if (md->use_count < 1) + DMWARN("incorrect reference count found in mapped_device"); + + md->use_count--; + dm_put_w(md); + + return 0; +} + +/* In 512-byte units */ +#define VOLUME_SIZE(minor) (_block_size[(minor)] << 1) + +static int dm_blk_ioctl(struct inode *inode, struct file *file, + uint command, unsigned long a) +{ + int minor = MINOR(inode->i_rdev); + long size; + + if (minor >= MAX_DEVICES) + return -ENXIO; + + switch (command) { + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKSSZGET: + //case BLKRRPART: /* Re-read partition tables */ + //case BLKPG: + case BLKELVGET: + case BLKELVSET: + case BLKBSZGET: + case BLKBSZSET: + return blk_ioctl(inode->i_rdev, command, a); + break; + + case BLKGETSIZE: + size = VOLUME_SIZE(minor); + if (copy_to_user((void *) a, &size, sizeof(long))) + return -EFAULT; + break; + + case BLKGETSIZE64: + size = VOLUME_SIZE(minor); + if (put_user((u64) ((u64) size) << 9, (u64 *) a)) + return -EFAULT; + break; + + case BLKRRPART: + return -ENOTTY; + + case LV_BMAP: + return dm_user_bmap(inode, (struct lv_bmap *) a); + + default: + DMWARN("unknown block ioctl 0x%x", command); + return -ENOTTY; + } + + return 0; +} + +static inline struct io_hook *alloc_io_hook(void) +{ + return kmem_cache_alloc(_io_hook_cache, GFP_NOIO); +} + +static inline void free_io_hook(struct io_hook *ih) +{ + kmem_cache_free(_io_hook_cache, ih); +} + +/* + * FIXME: We need to decide if deferred_io's need + * their own slab, I say no for now since they are + * only used when the device is suspended. + */ +static inline struct deferred_io *alloc_deferred(void) +{ + return kmalloc(sizeof(struct deferred_io), GFP_NOIO); +} + +static inline void free_deferred(struct deferred_io *di) +{ + kfree(di); +} + +/* + * Call a target's optional error function if an I/O failed. + */ +static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh) +{ + dm_err_fn err = ih->target->type->err; + + if (err) + return err(bh, ih->rw, ih->target->private); + + return 0; +} + +/* + * bh->b_end_io routine that decrements the pending count + * and then calls the original bh->b_end_io fn. + */ +static void dec_pending(struct buffer_head *bh, int uptodate) +{ + struct io_hook *ih = bh->b_private; + + if (!uptodate && call_err_fn(ih, bh)) + return; + + if (atomic_dec_and_test(&ih->md->pending)) + /* nudge anyone waiting on suspend queue */ + wake_up(&ih->md->wait); + + bh->b_end_io = ih->end_io; + bh->b_private = ih->context; + free_io_hook(ih); + + bh->b_end_io(bh, uptodate); +} + +/* + * Add the bh to the list of deferred io. + */ +static int queue_io(struct buffer_head *bh, int rw) +{ + struct deferred_io *di = alloc_deferred(); + struct mapped_device *md; + + if (!di) + return -ENOMEM; + + md = dm_get_w(MINOR(bh->b_rdev)); + if (!md) { + free_deferred(di); + return -ENXIO; + } + + if (!md->suspended) { + dm_put_w(md); + free_deferred(di); + return 1; + } + + di->bh = bh; + di->rw = rw; + di->next = md->deferred; + md->deferred = di; + + dm_put_w(md); + + return 0; /* deferred successfully */ +} + +/* + * Do the bh mapping for a given leaf + */ +static inline int __map_buffer(struct mapped_device *md, + struct buffer_head *bh, int rw, int leaf) +{ + int r; + dm_map_fn fn; + void *context; + struct io_hook *ih = NULL; + struct target *ti = md->map->targets + leaf; + + fn = ti->type->map; + context = ti->private; + + ih = alloc_io_hook(); + + if (!ih) + return -1; + + ih->md = md; + ih->rw = rw; + ih->target = ti; + ih->end_io = bh->b_end_io; + ih->context = bh->b_private; + + r = fn(bh, rw, context); + + if (r > 0) { + /* hook the end io request fn */ + atomic_inc(&md->pending); + bh->b_end_io = dec_pending; + bh->b_private = ih; + + } else if (r == 0) + /* we don't need to hook */ + free_io_hook(ih); + + else if (r < 0) { + free_io_hook(ih); + return -1; + } + + return r; +} + +/* + * Search the btree for the correct target. + */ +static inline int __find_node(struct dm_table *t, struct buffer_head *bh) +{ + int l, n = 0, k = 0; + offset_t *node; + + for (l = 0; l < t->depth; l++) { + n = get_child(n, k); + node = get_node(t, l, n); + + for (k = 0; k < KEYS_PER_NODE; k++) + if (node[k] >= bh->b_rsector) + break; + } + + return (KEYS_PER_NODE * n) + k; +} + +static int request(request_queue_t * q, int rw, struct buffer_head *bh) +{ + struct mapped_device *md; + int r, minor = MINOR(bh->b_rdev); + unsigned int block_size = _blksize_size[minor]; + + md = dm_get_r(minor); + if (!md) { + buffer_IO_error(bh); + return 0; + } + + /* + * Sanity checks. + */ + if (bh->b_size > block_size) + DMERR("request is larger than block size " + "b_size (%d), block size (%d)", + bh->b_size, block_size); + + if (bh->b_rsector & ((bh->b_size >> 9) - 1)) + DMERR("misaligned block requested logical " + "sector (%lu), b_size (%d)", + bh->b_rsector, bh->b_size); + + /* + * If we're suspended we have to queue + * this io for later. + */ + while (md->suspended) { + dm_put_r(md); + + if (rw == READA) + goto bad_no_lock; + + r = queue_io(bh, rw); + + if (r < 0) + goto bad_no_lock; + + else if (r == 0) + return 0; /* deferred successfully */ + + /* + * We're in a while loop, because someone could suspend + * before we get to the following read lock. + */ + md = dm_get_r(minor); + if (!md) { + buffer_IO_error(bh); + return 0; + } + } + + if ((r = __map_buffer(md, bh, rw, __find_node(md->map, bh))) < 0) + goto bad; + + dm_put_r(md); + return r; + + bad: + dm_put_r(md); + + bad_no_lock: + buffer_IO_error(bh); + return 0; +} + +static int check_dev_size(int minor, unsigned long block) +{ + /* FIXME: check this */ + unsigned long max_sector = (_block_size[minor] << 1) + 1; + unsigned long sector = (block + 1) * (_blksize_size[minor] >> 9); + + return (sector > max_sector) ? 0 : 1; +} + +/* + * Creates a dummy buffer head and maps it (for lilo). + */ +static int do_bmap(kdev_t dev, unsigned long block, + kdev_t * r_dev, unsigned long *r_block) +{ + struct mapped_device *md; + struct buffer_head bh; + int minor = MINOR(dev), r; + struct target *t; + + md = dm_get_r(minor); + if (!md) + return -ENXIO; + + if (md->suspended) { + dm_put_r(md); + return -EPERM; + } + + if (!check_dev_size(minor, block)) { + dm_put_r(md); + return -EINVAL; + } + + /* setup dummy bh */ + memset(&bh, 0, sizeof(bh)); + bh.b_blocknr = block; + bh.b_dev = bh.b_rdev = dev; + bh.b_size = _blksize_size[minor]; + bh.b_rsector = block * (bh.b_size >> 9); + + /* find target */ + t = md->map->targets + __find_node(md->map, &bh); + + /* do the mapping */ + r = t->type->map(&bh, READ, t->private); + + *r_dev = bh.b_rdev; + *r_block = bh.b_rsector / (bh.b_size >> 9); + + dm_put_r(md); + return r; +} + +/* + * Marshals arguments and results between user and kernel space. + */ +static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb) +{ + unsigned long block, r_block; + kdev_t r_dev; + int r; + + if (get_user(block, &lvb->lv_block)) + return -EFAULT; + + if ((r = do_bmap(inode->i_rdev, block, &r_dev, &r_block))) + return r; + + if (put_user(kdev_t_to_nr(r_dev), &lvb->lv_dev) || + put_user(r_block, &lvb->lv_block)) + return -EFAULT; + + return 0; +} + +/* + * See if the device with a specific minor # is free. The write + * lock is held when it returns successfully. + */ +static inline int specific_dev(int minor, struct mapped_device *md) +{ + if (minor >= MAX_DEVICES) { + DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)", + MAX_DEVICES); + return -1; + } + + down_write(_dev_locks + minor); + if (_devs[minor]) { + /* in use */ + up_write(_dev_locks + minor); + return -1; + } + + return minor; +} + +/* + * Find the first free device. Again the write lock is held on + * success. + */ +static int any_old_dev(struct mapped_device *md) +{ + int i; + + for (i = 0; i < MAX_DEVICES; i++) + if (specific_dev(i, md) != -1) + return i; + + return -1; +} + +/* + * Allocate and initialise a blank device. + * Caller must ensure uuid is null-terminated. + * Device is returned with a write lock held. + */ +static struct mapped_device *alloc_dev(const char *name, const char *uuid, + int minor) +{ + struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); + int len; + + if (!md) { + DMWARN("unable to allocate device, out of memory."); + return NULL; + } + + memset(md, 0, sizeof(*md)); + + /* + * This grabs the write lock if it succeeds. + */ + minor = (minor < 0) ? any_old_dev(md) : specific_dev(minor, md); + if (minor < 0) { + kfree(md); + return NULL; + } + + md->dev = MKDEV(_major, minor); + md->suspended = 0; + + strncpy(md->name, name, sizeof(md->name) - 1); + md->name[sizeof(md->name) - 1] = '\0'; + + /* + * Copy in the uuid. + */ + if (uuid && *uuid) { + len = strlen(uuid) + 1; + if (!(md->uuid = kmalloc(len, GFP_KERNEL))) { + DMWARN("unable to allocate uuid - out of memory."); + kfree(md); + return NULL; + } + strcpy(md->uuid, uuid); + } + + init_waitqueue_head(&md->wait); + return md; +} + +static int __register_device(struct mapped_device *md) +{ + md->devfs_entry = + devfs_register(_dev_dir, md->name, DEVFS_FL_CURRENT_OWNER, + MAJOR(md->dev), MINOR(md->dev), + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + &dm_blk_dops, NULL); + + return 0; +} + +static int __unregister_device(struct mapped_device *md) +{ + devfs_unregister(md->devfs_entry); + return 0; +} + +/* + * The hardsect size for a mapped device is the smallest hardsect size + * from the devices it maps onto. + */ +static int __find_hardsect_size(struct list_head *devices) +{ + int result = INT_MAX, size; + struct list_head *tmp; + + list_for_each(tmp, devices) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + size = get_hardsect_size(dd->dev); + if (size < result) + result = size; + } + + /* + * I think it's safe to assume that no block devices have + * a hard sector size this large. + */ + if (result == INT_MAX) + result = 512; + + return result; +} + +/* + * Bind a table to the device. + */ +static int __bind(struct mapped_device *md, struct dm_table *t) +{ + int minor = MINOR(md->dev); + + md->map = t; + + if (!t->num_targets) { + _block_size[minor] = 0; + _blksize_size[minor] = BLOCK_SIZE; + _hardsect_size[minor] = 0; + return 0; + } + + /* in k */ + _block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1; + + _blksize_size[minor] = BLOCK_SIZE; + _hardsect_size[minor] = __find_hardsect_size(&t->devices); + register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]); + + return 0; +} + +static void __unbind(struct mapped_device *md) +{ + int minor = MINOR(md->dev); + + dm_table_destroy(md->map); + md->map = NULL; + + _block_size[minor] = 0; + _blksize_size[minor] = 0; + _hardsect_size[minor] = 0; +} + +static int check_name(const char *name) +{ + struct mapped_device *md; + + if (strchr(name, '/') || strlen(name) > DM_NAME_LEN) { + DMWARN("invalid device name"); + return -1; + } + + md = dm_get_name_r(name, DM_LOOKUP_BY_NAME); + if (md) { + dm_put_r(md); + DMWARN("device name already in use"); + return -1; + } + + return 0; +} + +static int check_uuid(const char *uuid) +{ + struct mapped_device *md; + + if (uuid) { + md = dm_get_name_r(uuid, DM_LOOKUP_BY_UUID); + if (md) { + dm_put_r(md); + DMWARN("device uuid already in use"); + return -1; + } + } + + return 0; +} + +/* + * Constructor for a new device. + */ +int dm_create(const char *name, const char *uuid, int minor, int ro, + struct dm_table *table) +{ + int r; + struct mapped_device *md; + + spin_lock(&_create_lock); + if (check_name(name) || check_uuid(uuid)) { + spin_unlock(&_create_lock); + return -EINVAL; + } + + md = alloc_dev(name, uuid, minor); + if (!md) { + spin_unlock(&_create_lock); + return -ENXIO; + } + minor = MINOR(md->dev); + _devs[minor] = md; + + r = __register_device(md); + if (r) + goto err; + + r = __bind(md, table); + if (r) + goto err; + + dm_set_ro(md, ro); + + spin_unlock(&_create_lock); + dm_put_w(md); + return 0; + + err: + _devs[minor] = NULL; + if (md->uuid) + kfree(md->uuid); + + dm_put_w(md); + kfree(md); + spin_unlock(&_create_lock); + return r; +} + +/* + * Renames the device. No lock held. + */ +int dm_set_name(const char *name, int nametype, const char *newname) +{ + int r; + struct mapped_device *md; + + spin_lock(&_create_lock); + if (check_name(newname) < 0) { + spin_unlock(&_create_lock); + return -EINVAL; + } + + md = dm_get_name_w(name, nametype); + if (!md) { + spin_unlock(&_create_lock); + return -ENXIO; + } + + r = __unregister_device(md); + if (r) + goto out; + + strcpy(md->name, newname); + r = __register_device(md); + + out: + dm_put_w(md); + spin_unlock(&_create_lock); + return r; +} + +/* + * Destructor for the device. You cannot destroy an open + * device. Write lock must be held before calling. + * Caller must dm_put_w(md) then kfree(md) if call was successful. + */ +int dm_destroy(struct mapped_device *md) +{ + int minor, r; + + if (md->use_count) + return -EPERM; + + r = __unregister_device(md); + if (r) + return r; + + minor = MINOR(md->dev); + _devs[minor] = NULL; + __unbind(md); + + if (md->uuid) + kfree(md->uuid); + + return 0; +} + +/* + * Destroy all devices - except open ones + */ +void dm_destroy_all(void) +{ + int i, some_destroyed, r; + struct mapped_device *md; + + do { + some_destroyed = 0; + for (i = 0; i < MAX_DEVICES; i++) { + md = dm_get_w(i); + if (!md) + continue; + + r = dm_destroy(md); + dm_put_w(md); + + if (!r) { + kfree(md); + some_destroyed = 1; + } + } + } while (some_destroyed); +} + +/* + * Sets or clears the read-only flag for the device. Write lock + * must be held. + */ +void dm_set_ro(struct mapped_device *md, int ro) +{ + md->read_only = ro; + set_device_ro(md->dev, ro); +} + +/* + * A target is notifying us of some event + */ +void dm_notify(void *target) +{ +} + +/* + * Requeue the deferred buffer_heads by calling generic_make_request. + */ +static void flush_deferred_io(struct deferred_io *c) +{ + struct deferred_io *n; + + while (c) { + n = c->next; + generic_make_request(c->rw, c->bh); + free_deferred(c); + c = n; + } +} + +/* + * Swap in a new table (destroying old one). Write lock must be + * held. + */ +int dm_swap_table(struct mapped_device *md, struct dm_table *table) +{ + int r; + + /* device must be suspended */ + if (!md->suspended) + return -EPERM; + + __unbind(md); + + r = __bind(md, table); + if (r) + return r; + + return 0; +} + +/* + * We need to be able to change a mapping table under a mounted + * filesystem. for example we might want to move some data in + * the background. Before the table can be swapped with + * dm_bind_table, dm_suspend must be called to flush any in + * flight buffer_heads and ensure that any further io gets + * deferred. Write lock must be held. + */ +int dm_suspend(struct mapped_device *md) +{ + int minor = MINOR(md->dev); + DECLARE_WAITQUEUE(wait, current); + + if (md->suspended) + return -EINVAL; + + md->suspended = 1; + dm_put_w(md); + + /* wait for all the pending io to flush */ + add_wait_queue(&md->wait, &wait); + current->state = TASK_UNINTERRUPTIBLE; + do { + md = dm_get_w(minor); + if (!md) { + /* Caller expects to free this lock. Yuck. */ + down_write(_dev_locks + minor); + return -ENXIO; + } + + if (!atomic_read(&md->pending)) + break; + + dm_put_w(md); + schedule(); + + } while (1); + + current->state = TASK_RUNNING; + remove_wait_queue(&md->wait, &wait); + + return 0; +} + +int dm_resume(struct mapped_device *md) +{ + int minor = MINOR(md->dev); + struct deferred_io *def; + + if (!md->suspended || !md->map->num_targets) + return -EINVAL; + + md->suspended = 0; + def = md->deferred; + md->deferred = NULL; + + dm_put_w(md); + flush_deferred_io(def); + run_task_queue(&tq_disk); + + if (!dm_get_w(minor)) { + /* FIXME: yuck */ + down_write(_dev_locks + minor); + return -ENXIO; + } + + return 0; +} + +struct block_device_operations dm_blk_dops = { + open: dm_blk_open, + release: dm_blk_close, + ioctl: dm_blk_ioctl, + owner: THIS_MODULE +}; + +/* + * module hooks + */ +module_init(dm_init); +module_exit(dm_exit); + +MODULE_PARM(major, "i"); +MODULE_PARM_DESC(major, "The major number of the device mapper"); +MODULE_DESCRIPTION(DM_NAME " driver"); +MODULE_AUTHOR("Joe Thornber "); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm-exception-store.c linux.20pre2-ac1/drivers/md/dm-exception-store.c --- linux.20pre2/drivers/md/dm-exception-store.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm-exception-store.c 2002-08-12 22:44:36.000000000 +0100 @@ -0,0 +1,724 @@ +/* + * dm-snapshot.c + * + * Copyright (C) 2001-2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm-snapshot.h" +#include "kcopyd.h" +#include +#include + +#define SECTOR_SIZE 512 +#define SECTOR_SHIFT 9 + +/*----------------------------------------------------------------- + * Persistent snapshots, by persistent we mean that the snapshot + * will survive a reboot. + *---------------------------------------------------------------*/ + +/* + * We need to store a record of which parts of the origin have + * been copied to the snapshot device. The snapshot code + * requires that we copy exception chunks to chunk aligned areas + * of the COW store. It makes sense therefore, to store the + * metadata in chunk size blocks. + * + * There is no backward or forward compatibility implemented, + * snapshots with different disk versions than the kernel will + * not be usable. It is expected that "lvcreate" will blank out + * the start of a fresh COW device before calling the snapshot + * constructor. + * + * The first chunk of the COW device just contains the header. + * After this there is a chunk filled with exception metadata, + * followed by as many exception chunks as can fit in the + * metadata areas. + * + * All on disk structures are in little-endian format. The end + * of the exceptions info is indicated by an exception with a + * new_chunk of 0, which is invalid since it would point to the + * header chunk. + */ + +/* + * Magic for persistent snapshots: "SnAp" - Feeble isn't it. + */ +#define SNAP_MAGIC 0x70416e53 + +/* + * The on-disk version of the metadata. + */ +#define SNAPSHOT_DISK_VERSION 1 + +struct disk_header { + uint32_t magic; + + /* + * Is this snapshot valid. There is no way of recovering + * an invalid snapshot. + */ + int valid; + + /* + * Simple, incrementing version. no backward + * compatibility. + */ + uint32_t version; + + /* In sectors */ + uint32_t chunk_size; +}; + +struct disk_exception { + uint64_t old_chunk; + uint64_t new_chunk; +}; + +struct commit_callback { + void (*callback)(void *, int success); + void *context; +}; + +/* + * The top level structure for a persistent exception store. + */ +struct pstore { + struct dm_snapshot *snap; /* up pointer to my snapshot */ + int version; + int valid; + uint32_t chunk_size; + uint32_t exceptions_per_area; + + /* + * Now that we have an asynchronous kcopyd there is no + * need for large chunk sizes, so it wont hurt to have a + * whole chunks worth of metadata in memory at once. + */ + void *area; + struct kiobuf *iobuf; + + /* + * Used to keep track of which metadata area the data in + * 'chunk' refers to. + */ + uint32_t current_area; + + /* + * The next free chunk for an exception. + */ + uint32_t next_free; + + /* + * The index of next free exception in the current + * metadata area. + */ + uint32_t current_committed; + + atomic_t pending_count; + uint32_t callback_count; + struct commit_callback *callbacks; +}; + +/* + * For performance reasons we want to defer writing a committed + * exceptions metadata to disk so that we can amortise away this + * exensive operation. + * + * For the initial version of this code we will remain with + * synchronous io. There are some deadlock issues with async + * that I haven't yet worked out. + */ +static int do_io(int rw, struct kcopyd_region *where, struct kiobuf *iobuf) +{ + int i, sectors_per_block, nr_blocks, start; + int blocksize = get_hardsect_size(where->dev); + int status; + + sectors_per_block = blocksize / SECTOR_SIZE; + + nr_blocks = where->count / sectors_per_block; + start = where->sector / sectors_per_block; + + for (i = 0; i < nr_blocks; i++) + iobuf->blocks[i] = start++; + + iobuf->length = where->count << 9; + iobuf->locked = 1; + + status = brw_kiovec(rw, 1, &iobuf, where->dev, iobuf->blocks, + blocksize); + if (status != (where->count << 9)) + return -EIO; + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 4, 19) +/* + * FIXME: Remove once 2.4.19 has been released. + */ +struct page *vmalloc_to_page(void *vmalloc_addr) +{ + unsigned long addr = (unsigned long) vmalloc_addr; + struct page *page = NULL; + pmd_t *pmd; + pte_t *pte; + pgd_t *pgd; + + pgd = pgd_offset_k(addr); + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, addr); + if (!pmd_none(*pmd)) { + pte = pte_offset(pmd, addr); + if (pte_present(*pte)) { + page = pte_page(*pte); + } + } + } + return page; +} +#endif + +static int allocate_iobuf(struct pstore *ps) +{ + size_t i, r = -ENOMEM, len, nr_pages; + struct page *page; + + len = ps->chunk_size << SECTOR_SHIFT; + + /* + * Allocate the chunk_size block of memory that will hold + * a single metadata area. + */ + ps->area = vmalloc(len); + if (!ps->area) + return r; + + if (alloc_kiovec(1, &ps->iobuf)) + goto bad; + + nr_pages = ps->chunk_size / (PAGE_SIZE / SECTOR_SIZE); + r = expand_kiobuf(ps->iobuf, nr_pages); + if (r) + goto bad; + + /* + * We lock the pages for ps->area into memory since they'll be + * doing a lot of io. + */ + for (i = 0; i < nr_pages; i++) { + page = vmalloc_to_page(ps->area + (i * PAGE_SIZE)); + LockPage(page); + ps->iobuf->maplist[i] = page; + ps->iobuf->nr_pages++; + } + + ps->iobuf->nr_pages = nr_pages; + ps->iobuf->offset = 0; + + return 0; + + bad: + if (ps->iobuf) + free_kiovec(1, &ps->iobuf); + + if (ps->area) + vfree(ps->area); + ps->iobuf = NULL; + return r; +} + +static void free_iobuf(struct pstore *ps) +{ + int i; + + for (i = 0; i < ps->iobuf->nr_pages; i++) + UnlockPage(ps->iobuf->maplist[i]); + ps->iobuf->locked = 0; + + free_kiovec(1, &ps->iobuf); + vfree(ps->area); +} + +/* + * Read or write a chunk aligned and sized block of data from a device. + */ +static int chunk_io(struct pstore *ps, uint32_t chunk, int rw) +{ + int r; + struct kcopyd_region where; + + where.dev = ps->snap->cow->dev; + where.sector = ps->chunk_size * chunk; + where.count = ps->chunk_size; + + r = do_io(rw, &where, ps->iobuf); + if (r) + return r; + + return 0; +} + +/* + * Read or write a metadata area. Remembering to skip the first + * chunk which holds the header. + */ +static int area_io(struct pstore *ps, uint32_t area, int rw) +{ + int r; + uint32_t chunk; + + /* convert a metadata area index to a chunk index */ + chunk = 1 + ((ps->exceptions_per_area + 1) * area); + + r = chunk_io(ps, chunk, rw); + if (r) + return r; + + ps->current_area = area; + return 0; +} + +static int zero_area(struct pstore *ps, uint32_t area) +{ + memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); + return area_io(ps, area, WRITE); +} + +static int read_header(struct pstore *ps, int *new_snapshot) +{ + int r; + struct disk_header *dh; + + r = chunk_io(ps, 0, READ); + if (r) + return r; + + dh = (struct disk_header *) ps->area; + + if (dh->magic == 0) { + *new_snapshot = 1; + + } else if (dh->magic == SNAP_MAGIC) { + *new_snapshot = 0; + ps->valid = dh->valid; + ps->version = dh->version; + ps->chunk_size = dh->chunk_size; + + } else { + DMWARN("Invalid/corrupt snapshot"); + r = -ENXIO; + } + + return r; +} + +static int write_header(struct pstore *ps) +{ + struct disk_header *dh; + + memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); + + dh = (struct disk_header *) ps->area; + dh->magic = SNAP_MAGIC; + dh->valid = ps->valid; + dh->version = ps->version; + dh->chunk_size = ps->chunk_size; + + return chunk_io(ps, 0, WRITE); +} + +/* + * Access functions for the disk exceptions, these do the endian conversions. + */ +static struct disk_exception *get_exception(struct pstore *ps, uint32_t index) +{ + if (index >= ps->exceptions_per_area) + return NULL; + + return ((struct disk_exception *) ps->area) + index; +} + +static int read_exception(struct pstore *ps, + uint32_t index, struct disk_exception *result) +{ + struct disk_exception *e; + + e = get_exception(ps, index); + if (!e) + return -EINVAL; + + /* copy it */ + result->old_chunk = le64_to_cpu(e->old_chunk); + result->new_chunk = le64_to_cpu(e->new_chunk); + + return 0; +} + +static int write_exception(struct pstore *ps, + uint32_t index, struct disk_exception *de) +{ + struct disk_exception *e; + + e = get_exception(ps, index); + if (!e) + return -EINVAL; + + /* copy it */ + e->old_chunk = cpu_to_le64(de->old_chunk); + e->new_chunk = cpu_to_le64(de->new_chunk); + + return 0; +} + +/* + * Registers the exceptions that are present in the current area. + * 'full' is filled in to indicate if the area has been + * filled. + */ +static int insert_exceptions(struct pstore *ps, int *full) +{ + int i, r; + struct disk_exception de; + + /* presume the area is full */ + *full = 1; + + for (i = 0; i < ps->exceptions_per_area; i++) { + r = read_exception(ps, i, &de); + + if (r) + return r; + + /* + * If the new_chunk is pointing at the start of + * the COW device, where the first metadata area + * is we know that we've hit the end of the + * exceptions. Therefore the area is not full. + */ + if (de.new_chunk == 0LL) { + ps->current_committed = i; + *full = 0; + break; + } + + /* + * Keep track of the start of the free chunks. + */ + if (ps->next_free <= de.new_chunk) + ps->next_free = de.new_chunk + 1; + + /* + * Otherwise we add the exception to the snapshot. + */ + r = dm_add_exception(ps->snap, de.old_chunk, de.new_chunk); + if (r) + return r; + } + + return 0; +} + +static int read_exceptions(struct pstore *ps) +{ + uint32_t area; + int r, full = 1; + + /* + * Keeping reading chunks and inserting exceptions until + * we find a partially full area. + */ + for (area = 0; full; area++) { + r = area_io(ps, area, READ); + if (r) + return r; + + r = insert_exceptions(ps, &full); + if (r) + return r; + + area++; + } + + return 0; +} + +static inline struct pstore *get_info(struct exception_store *store) +{ + return (struct pstore *) store->context; +} + +static int persistent_percentfull(struct exception_store *store) +{ + struct pstore *ps = get_info(store); + return (ps->next_free * store->snap->chunk_size * 100) / + get_dev_size(store->snap->cow->dev); +} + +static void persistent_destroy(struct exception_store *store) +{ + struct pstore *ps = get_info(store); + + vfree(ps->callbacks); + free_iobuf(ps); + kfree(ps); +} + +static int persistent_prepare(struct exception_store *store, + struct exception *e) +{ + struct pstore *ps = get_info(store); + uint32_t stride; + offset_t size = get_dev_size(store->snap->cow->dev); + + /* Is there enough room ? */ + if (size <= (ps->next_free * store->snap->chunk_size)) + return -ENOSPC; + + e->new_chunk = ps->next_free; + + /* + * Move onto the next free pending, making sure to take + * into account the location of the metadata chunks. + */ + stride = (ps->exceptions_per_area + 1); + if (!(++ps->next_free % stride)) + ps->next_free++; + + atomic_inc(&ps->pending_count); + return 0; +} + +static void persistent_commit(struct exception_store *store, + struct exception *e, + void (*callback) (void *, int success), + void *callback_context) +{ + int r, i; + struct pstore *ps = get_info(store); + struct disk_exception de; + struct commit_callback *cb; + + de.old_chunk = e->old_chunk; + de.new_chunk = e->new_chunk; + write_exception(ps, ps->current_committed++, &de); + + /* + * Add the callback to the back of the array. This code + * is the only place where the callback array is + * manipulated, and we know that it will never be called + * multiple times concurrently. + */ + cb = ps->callbacks + ps->callback_count++; + cb->callback = callback; + cb->context = callback_context; + + /* + * If there are no more exceptions in flight, or we have + * filled this metadata area we commit the exceptions to + * disk. + */ + if (atomic_dec_and_test(&ps->pending_count) || + (ps->current_committed == ps->exceptions_per_area)) { + r = area_io(ps, ps->current_area, WRITE); + if (r) + ps->valid = 0; + + for (i = 0; i < ps->callback_count; i++) { + cb = ps->callbacks + i; + cb->callback(cb->context, r == 0 ? 1 : 0); + } + + ps->callback_count = 0; + } + + /* + * Have we completely filled the current area ? + */ + if (ps->current_committed == ps->exceptions_per_area) { + ps->current_committed = 0; + r = zero_area(ps, ps->current_area + 1); + if (r) + ps->valid = 0; + } +} + +static void persistent_drop(struct exception_store *store) +{ + struct pstore *ps = get_info(store); + + ps->valid = 0; + if (write_header(ps)) + DMWARN("write header failed"); +} + +int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) +{ + int r, new_snapshot; + struct pstore *ps; + + /* allocate the pstore */ + ps = kmalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) + return -ENOMEM; + + ps->snap = store->snap; + ps->valid = 1; + ps->version = SNAPSHOT_DISK_VERSION; + ps->chunk_size = chunk_size; + ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) / + sizeof(struct disk_exception); + ps->next_free = 2; /* skipping the header and first area */ + ps->current_committed = 0; + + r = allocate_iobuf(ps); + if (r) + goto bad; + + /* + * Allocate space for all the callbacks. + */ + ps->callback_count = 0; + atomic_set(&ps->pending_count, 0); + ps->callbacks = vcalloc(ps->exceptions_per_area, + sizeof(*ps->callbacks)); + + if (!ps->callbacks) + goto bad; + + /* + * Read the snapshot header. + */ + r = read_header(ps, &new_snapshot); + if (r) + goto bad; + + /* + * Do we need to setup a new snapshot ? + */ + if (new_snapshot) { + r = write_header(ps); + if (r) { + DMWARN("write_header failed"); + goto bad; + } + + r = zero_area(ps, 0); + if (r) { + DMWARN("zero_area(0) failed"); + goto bad; + } + + } else { + /* + * Sanity checks. + */ + if (ps->chunk_size != chunk_size) { + DMWARN("chunk size for existing snapshot different " + "from that requested"); + r = -EINVAL; + goto bad; + } + + if (ps->version != SNAPSHOT_DISK_VERSION) { + DMWARN("unable to handle snapshot disk version %d", + ps->version); + r = -EINVAL; + goto bad; + } + + /* + * Read the metadata. + */ + r = read_exceptions(ps); + if (r) + goto bad; + } + + store->destroy = persistent_destroy; + store->prepare_exception = persistent_prepare; + store->commit_exception = persistent_commit; + store->drop_snapshot = persistent_drop; + store->percent_full = persistent_percentfull; + store->context = ps; + + return r; + + bad: + if (ps) { + if (ps->callbacks) + vfree(ps->callbacks); + + if (ps->iobuf) + free_iobuf(ps); + + kfree(ps); + } + return r; +} + +/*----------------------------------------------------------------- + * Implementation of the store for non-persistent snapshots. + *---------------------------------------------------------------*/ +struct transient_c { + offset_t next_free; +}; + +void transient_destroy(struct exception_store *store) +{ + kfree(store->context); +} + +int transient_prepare(struct exception_store *store, struct exception *e) +{ + struct transient_c *tc = (struct transient_c *) store->context; + offset_t size = get_dev_size(store->snap->cow->dev); + + if (size < (tc->next_free + store->snap->chunk_size)) + return -1; + + e->new_chunk = sector_to_chunk(store->snap, tc->next_free); + tc->next_free += store->snap->chunk_size; + + return 0; +} + +void transient_commit(struct exception_store *store, + struct exception *e, + void (*callback) (void *, int success), + void *callback_context) +{ + /* Just succeed */ + callback(callback_context, 1); +} + +static int transient_percentfull(struct exception_store *store) +{ + struct transient_c *tc = (struct transient_c *) store->context; + return (tc->next_free * 100) / get_dev_size(store->snap->cow->dev); +} + +int dm_create_transient(struct exception_store *store, + struct dm_snapshot *s, int blocksize, void **error) +{ + struct transient_c *tc; + + memset(store, 0, sizeof(*store)); + store->destroy = transient_destroy; + store->prepare_exception = transient_prepare; + store->commit_exception = transient_commit; + store->percent_full = transient_percentfull; + store->snap = s; + + tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL); + if (!tc) + return -ENOMEM; + + tc->next_free = 0; + store->context = tc; + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm.h linux.20pre2-ac1/drivers/md/dm.h --- linux.20pre2/drivers/md/dm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,241 @@ +/* + * Internal header file for device mapper + * + * Copyright (C) 2001 Sistina Software + * + * This file is released under the LGPL. + */ + +#ifndef DM_INTERNAL_H +#define DM_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DM_NAME "device-mapper" /* Name for messaging */ +#define DM_DRIVER_EMAIL "lvm-devel@lists.sistina.com" +#define MAX_DEPTH 16 +#define NODE_SIZE L1_CACHE_BYTES +#define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t)) +#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) +#define MAX_ARGS 32 +#define MAX_DEVICES 256 + +/* + * List of devices that a metadevice uses and should open/close. + */ +struct dm_dev { + atomic_t count; + struct list_head list; + + int mode; + + kdev_t dev; + struct block_device *bd; +}; + +/* + * I/O that had to be deferred while we were suspended + */ +struct deferred_io { + int rw; + struct buffer_head *bh; + struct deferred_io *next; +}; + +/* + * Btree leaf - this does the actual mapping + */ +struct target { + struct target_type *type; + void *private; +}; + +/* + * The btree + */ +struct dm_table { + /* btree table */ + int depth; + int counts[MAX_DEPTH]; /* in nodes */ + offset_t *index[MAX_DEPTH]; + + int num_targets; + int num_allocated; + offset_t *highs; + struct target *targets; + + /* + * Indicates the rw permissions for the new logical + * device. This should be a combination of FMODE_READ + * and FMODE_WRITE. + */ + int mode; + + /* a list of devices used by this table */ + struct list_head devices; + + /* + * A waitqueue for processes waiting for something + * interesting to happen to this table. + */ + wait_queue_head_t eventq; +}; + +/* + * The actual device struct + */ +struct mapped_device { + kdev_t dev; + char name[DM_NAME_LEN]; + char *uuid; + + int use_count; + int suspended; + int read_only; + + /* a list of io's that arrived while we were suspended */ + atomic_t pending; + wait_queue_head_t wait; + struct deferred_io *deferred; + + struct dm_table *map; + + /* used by dm-fs.c */ + devfs_handle_t devfs_entry; +}; + +extern struct block_device_operations dm_blk_dops; + +/* dm-target.c */ +int dm_target_init(void); +struct target_type *dm_get_target_type(const char *name); +void dm_put_target_type(struct target_type *t); +void dm_target_exit(void); + +/* + * Destructively splits argument list to pass to ctr. + */ +int split_args(int max, int *argc, char **argv, char *input); + +/* dm.c */ +struct mapped_device *dm_get_r(int minor); +struct mapped_device *dm_get_w(int minor); + +/* + * There are two ways to lookup a device. + */ +enum { + DM_LOOKUP_BY_NAME, + DM_LOOKUP_BY_UUID +}; + +struct mapped_device *dm_get_name_r(const char *name, int nametype); +struct mapped_device *dm_get_name_w(const char *name, int nametype); + +void dm_put_r(struct mapped_device *md); +void dm_put_w(struct mapped_device *md); + +/* + * Call with no lock. + */ +int dm_create(const char *name, const char *uuid, int minor, int ro, + struct dm_table *table); +int dm_set_name(const char *name, int nametype, const char *newname); +void dm_destroy_all(void); + +/* + * You must have the write lock before calling the remaining md + * methods. + */ +int dm_destroy(struct mapped_device *md); +void dm_set_ro(struct mapped_device *md, int ro); + +/* + * The device must be suspended before calling this method. + */ +int dm_swap_table(struct mapped_device *md, struct dm_table *t); + +/* + * A device can still be used while suspended, but I/O is deferred. + */ +int dm_suspend(struct mapped_device *md); +int dm_resume(struct mapped_device *md); + +/* dm-table.c */ +int dm_table_create(struct dm_table **result, int mode); +void dm_table_destroy(struct dm_table *t); + +int dm_table_add_target(struct dm_table *t, offset_t highs, + struct target_type *type, void *private); +int dm_table_complete(struct dm_table *t); + +/* + * Event handling + */ +void dm_table_event(struct dm_table *t); + +#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x) +#define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x) +#define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x) + +/* + * Calculate the index of the child node of the n'th node k'th key. + */ +static inline int get_child(int n, int k) +{ + return (n * CHILDREN_PER_NODE) + k; +} + +/* + * Return the n'th node of level l from table t. + */ +static inline offset_t *get_node(struct dm_table *t, int l, int n) +{ + return t->index[l] + (n * KEYS_PER_NODE); +} + +static inline int array_too_big(unsigned long fixed, unsigned long obj, + unsigned long num) +{ + return (num > (ULONG_MAX - fixed) / obj); +} + + +/* + * Targets + */ +int dm_linear_init(void); +void dm_linear_exit(void); + +int dm_stripe_init(void); +void dm_stripe_exit(void); + +int dm_snapshot_init(void); +void dm_snapshot_exit(void); + + +/* + * Init functions for the user interface to device-mapper. At + * the moment an ioctl interface on a special char device is + * used. A filesystem based interface would be a nicer way to + * go. + */ +int __init dm_interface_init(void); +void dm_interface_exit(void); + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm-ioctl.c linux.20pre2-ac1/drivers/md/dm-ioctl.c --- linux.20pre2/drivers/md/dm-ioctl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm-ioctl.c 2002-08-12 22:45:52.000000000 +0100 @@ -0,0 +1,830 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include +#include +#include + +/*----------------------------------------------------------------- + * Implementation of the ioctl commands + *---------------------------------------------------------------*/ + +/* + * All the ioctl commands get dispatched to functions with this + * prototype. + */ +typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user); + +/* + * This is really a debug only call. + */ +static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user) +{ + dm_destroy_all(); + return 0; +} + +/* + * Check a string doesn't overrun the chunk of + * memory we copied from userland. + */ +static int valid_str(char *str, void *begin, void *end) +{ + while (((void *) str >= begin) && ((void *) str < end)) + if (!*str++) + return 0; + + return -EINVAL; +} + +static int next_target(struct dm_target_spec *last, uint32_t next, + void *begin, void *end, + struct dm_target_spec **spec, char **params) +{ + *spec = (struct dm_target_spec *) + ((unsigned char *) last + next); + *params = (char *) (*spec + 1); + + if (*spec < (last + 1) || ((void *) *spec > end)) + return -EINVAL; + + return valid_str(*params, begin, end); +} + +/* + * Checks to see if there's a gap in the table. + * Returns true iff there is a gap. + */ +static int gap(struct dm_table *table, struct dm_target_spec *spec) +{ + if (!table->num_targets) + return (spec->sector_start > 0) ? 1 : 0; + + if (spec->sector_start != table->highs[table->num_targets - 1] + 1) + return 1; + + return 0; +} + +static int populate_table(struct dm_table *table, struct dm_ioctl *args) +{ + int i = 0, r, first = 1, argc; + struct dm_target_spec *spec; + char *params, *argv[MAX_ARGS]; + struct target_type *ttype; + void *context, *begin, *end; + offset_t highs = 0; + + if (!args->target_count) { + DMWARN("populate_table: no targets specified"); + return -EINVAL; + } + + begin = (void *) args; + end = begin + args->data_size; + +#define PARSE_ERROR(msg) {DMWARN(msg); return -EINVAL;} + + for (i = 0; i < args->target_count; i++) { + + if (first) + r = next_target((struct dm_target_spec *) args, + args->data_start, + begin, end, &spec, ¶ms); + else + r = next_target(spec, spec->next, begin, end, + &spec, ¶ms); + + if (r) + PARSE_ERROR("unable to find target"); + + /* Look up the target type */ + ttype = dm_get_target_type(spec->target_type); + if (!ttype) + PARSE_ERROR("unable to find target type"); + + if (gap(table, spec)) + PARSE_ERROR("gap in target ranges"); + + /* Split up the parameter list */ + if (split_args(MAX_ARGS, &argc, argv, params) < 0) + PARSE_ERROR("Too many arguments"); + + /* Build the target */ + if (ttype->ctr(table, spec->sector_start, spec->length, + argc, argv, &context)) { + DMWARN("%s: target constructor failed", + (char *) context); + return -EINVAL; + } + + /* Add the target to the table */ + highs = spec->sector_start + (spec->length - 1); + if (dm_table_add_target(table, highs, ttype, context)) + PARSE_ERROR("internal error adding target to table"); + + first = 0; + } + +#undef PARSE_ERROR + + r = dm_table_complete(table); + return r; +} + +/* + * Round up the ptr to the next 'align' boundary. Obviously + * 'align' must be a power of 2. + */ +static inline void *align_ptr(void *ptr, unsigned int align) +{ + align--; + return (void *) (((unsigned long) (ptr + align)) & ~align); +} + +/* + * Copies a dm_ioctl and an optional additional payload to + * userland. + */ +static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param, + void *data, uint32_t len) +{ + int r; + void *ptr = NULL; + + if (data) { + ptr = align_ptr(user + 1, sizeof(unsigned long)); + param->data_start = ptr - (void *) user; + } + + /* + * The version number has already been filled in, so we + * just copy later fields. + */ + r = copy_to_user(&user->data_size, ¶m->data_size, + sizeof(*param) - sizeof(param->version)); + if (r) + return -EFAULT; + + if (data) { + if (param->data_start + len > param->data_size) + return -ENOSPC; + + if (copy_to_user(ptr, data, len)) + r = -EFAULT; + } + + return r; +} + +/* + * Fills in a dm_ioctl structure, ready for sending back to + * userland. + */ +static void __info(struct mapped_device *md, struct dm_ioctl *param) +{ + param->flags = DM_EXISTS_FLAG; + if (md->suspended) + param->flags |= DM_SUSPEND_FLAG; + if (md->read_only) + param->flags |= DM_READONLY_FLAG; + + strncpy(param->name, md->name, sizeof(param->name)); + + if (md->uuid) + strncpy(param->uuid, md->uuid, sizeof(param->uuid) - 1); + else + param->uuid[0] = '\0'; + + param->open_count = md->use_count; + param->dev = kdev_t_to_nr(md->dev); + param->target_count = md->map->num_targets; +} + +/* + * Always use UUID for lookups if it's present, otherwise use name. + */ +static inline char *lookup_name(struct dm_ioctl *param) +{ + return (*param->uuid) ? param->uuid : param->name; +} + +static inline int lookup_type(struct dm_ioctl *param) +{ + return (*param->uuid) ? DM_LOOKUP_BY_UUID : DM_LOOKUP_BY_NAME; +} + +#define ALIGNMENT sizeof(int) +static void *_align(void *ptr, unsigned int a) +{ + register unsigned long align = --a; + + return (void *) (((unsigned long) ptr + align) & ~align); +} + +/* + * Copies device info back to user space, used by + * the create and info ioctls. + */ +static int info(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + + param->flags = 0; + + md = dm_get_name_r(lookup_name(param), lookup_type(param)); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + __info(md, param); + dm_put_r(md); + + out: + return results_to_user(user, param, NULL, 0); +} + +static inline int get_mode(struct dm_ioctl *param) +{ + int mode = FMODE_READ | FMODE_WRITE; + + if (param->flags & DM_READONLY_FLAG) + mode = FMODE_READ; + + return mode; +} + +static int create(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r, ro; + struct dm_table *t; + int minor; + + r = dm_table_create(&t, get_mode(param)); + if (r) + return r; + + r = populate_table(t, param); + if (r) { + dm_table_destroy(t); + return r; + } + + minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ? + MINOR(to_kdev_t(param->dev)) : -1; + + ro = (param->flags & DM_READONLY_FLAG) ? 1 : 0; + + r = dm_create(param->name, param->uuid, minor, ro, t); + if (r) { + dm_table_destroy(t); + return r; + } + + r = info(param, user); + return r; +} + + + +/* + * Build up the status struct for each target + */ +static int __status(struct mapped_device *md, struct dm_ioctl *param, + char *outbuf, int *len) +{ + int i; + struct dm_target_spec *spec; + uint64_t sector = 0LL; + char *outptr; + status_type_t type; + + if (param->flags & DM_STATUS_TABLE_FLAG) + type = STATUSTYPE_TABLE; + else + type = STATUSTYPE_INFO; + + outptr = outbuf; + + /* Get all the target info */ + for (i = 0; i < md->map->num_targets; i++) { + struct target_type *tt = md->map->targets[i].type; + offset_t high = md->map->highs[i]; + + if (outptr - outbuf + + sizeof(struct dm_target_spec) > param->data_size) + return -ENOMEM; + + spec = (struct dm_target_spec *) outptr; + + spec->status = 0; + spec->sector_start = sector; + spec->length = high - sector + 1; + strncpy(spec->target_type, tt->name, sizeof(spec->target_type)); + + outptr += sizeof(struct dm_target_spec); + + /* Get the status/table string from the target driver */ + if (tt->status) + tt->status(type, outptr, + outbuf + param->data_size - outptr, + md->map->targets[i].private); + else + outptr[0] = '\0'; + + outptr += strlen(outptr) + 1; + _align(outptr, ALIGNMENT); + + sector = high + 1; + + spec->next = outptr - outbuf; + } + + param->target_count = md->map->num_targets; + *len = outptr - outbuf; + + return 0; +} + +/* + * Return the status of a device as a text string for each + * target. + */ +static int get_status(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + int len = 0; + int ret; + char *outbuf = NULL; + + md = dm_get_name_r(lookup_name(param), lookup_type(param)); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + + /* We haven't a clue how long the resultant data will be so + just allocate as much as userland has allowed us and make sure + we don't overun it */ + outbuf = kmalloc(param->data_size, GFP_KERNEL); + if (!outbuf) + goto out; + /* + * Get the status of all targets + */ + __status(md, param, outbuf, &len); + + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + out: + if (md) + dm_put_r(md); + + ret = results_to_user(user, param, outbuf, len); + + if (outbuf) + kfree(outbuf); + + return ret; +} + +/* + * Wait for a device to report an event + */ +static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user) +{ + struct mapped_device *md; + DECLARE_WAITQUEUE(wq, current); + + md = dm_get_name_r(lookup_name(param), lookup_type(param)); + if (!md) + /* + * Device not found - returns cleared exists flag. + */ + goto out; + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + /* + * Wait for a notification event + */ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&md->map->eventq, &wq); + + dm_put_r(md); + + schedule(); + set_current_state(TASK_RUNNING); + + out: + return results_to_user(user, param, NULL, 0); +} + +/* + * Retrieves a list of devices used by a particular dm device. + */ +static int dep(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int count, r; + struct mapped_device *md; + struct list_head *tmp; + size_t len = 0; + struct dm_target_deps *deps = NULL; + + md = dm_get_name_r(lookup_name(param), lookup_type(param)); + if (!md) + goto out; + + /* + * Setup the basic dm_ioctl structure. + */ + __info(md, param); + + /* + * Count the devices. + */ + count = 0; + list_for_each(tmp, &md->map->devices) + count++; + + /* + * Allocate a kernel space version of the dm_target_status + * struct. + */ + if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) { + dm_put_r(md); + return -ENOMEM; + } + + len = sizeof(*deps) + (sizeof(*deps->dev) * count); + deps = kmalloc(len, GFP_KERNEL); + if (!deps) { + dm_put_r(md); + return -ENOMEM; + } + + /* + * Fill in the devices. + */ + deps->count = count; + count = 0; + list_for_each(tmp, &md->map->devices) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + deps->dev[count++] = kdev_t_to_nr(dd->dev); + } + dm_put_r(md); + + out: + r = results_to_user(user, param, deps, len); + + kfree(deps); + return r; +} + +static int remove(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct mapped_device *md; + + md = dm_get_name_w(lookup_name(param), lookup_type(param)); + if (!md) + return -ENXIO; + + r = dm_destroy(md); + dm_put_w(md); + if (!r) + kfree(md); + + return r; +} + +static int suspend(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct mapped_device *md; + + md = dm_get_name_w(lookup_name(param), lookup_type(param)); + if (!md) + return -ENXIO; + + r = (param->flags & DM_SUSPEND_FLAG) ? dm_suspend(md) : dm_resume(md); + dm_put_w(md); + + return r; +} + +static int reload(struct dm_ioctl *param, struct dm_ioctl *user) +{ + int r; + struct mapped_device *md; + struct dm_table *t; + + r = dm_table_create(&t, get_mode(param)); + if (r) + return r; + + r = populate_table(t, param); + if (r) { + dm_table_destroy(t); + return r; + } + + md = dm_get_name_w(lookup_name(param), lookup_type(param)); + if (!md) { + dm_table_destroy(t); + return -ENXIO; + } + + r = dm_swap_table(md, t); + if (r) { + dm_put_w(md); + dm_table_destroy(t); + return r; + } + + dm_set_ro(md, (param->flags & DM_READONLY_FLAG) ? 1 : 0); + dm_put_w(md); + + r = info(param, user); + return r; +} + +static int rename(struct dm_ioctl *param, struct dm_ioctl *user) +{ + char *newname = (char *) param + param->data_start; + + if (valid_str(newname, (void *) param, + (void *) param + param->data_size) || + dm_set_name(lookup_name(param), lookup_type(param), newname)) { + DMWARN("Invalid new logical volume name supplied."); + return -EINVAL; + } + + return 0; +} + + +/*----------------------------------------------------------------- + * Implementation of open/close/ioctl on the special char + * device. + *---------------------------------------------------------------*/ +static int ctl_open(struct inode *inode, struct file *file) +{ + /* only root can open this */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int ctl_close(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static ioctl_fn lookup_ioctl(unsigned int cmd) +{ + static struct { + int cmd; + ioctl_fn fn; + } _ioctls[] = { + {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */ + {DM_REMOVE_ALL_CMD, remove_all}, + {DM_DEV_CREATE_CMD, create}, + {DM_DEV_REMOVE_CMD, remove}, + {DM_DEV_RELOAD_CMD, reload}, + {DM_DEV_RENAME_CMD, rename}, + {DM_DEV_SUSPEND_CMD, suspend}, + {DM_DEV_DEPS_CMD, dep}, + {DM_DEV_STATUS_CMD, info}, + {DM_TARGET_STATUS_CMD, get_status}, + {DM_TARGET_WAIT_CMD, wait_device_event}, + }; + static int nelts = sizeof(_ioctls) / sizeof(*_ioctls); + + return (cmd >= nelts) ? NULL : _ioctls[cmd].fn; +} + +/* + * As well as checking the version compatibility this always + * copies the kernel interface version out. + */ +static int check_version(int cmd, struct dm_ioctl *user) +{ + uint32_t version[3]; + int r = 0; + + if (copy_from_user(version, user->version, sizeof(version))) + return -EFAULT; + + if ((DM_VERSION_MAJOR != version[0]) || + (DM_VERSION_MINOR < version[1])) { + DMWARN("ioctl interface mismatch: " + "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", + DM_VERSION_MAJOR, DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL, + version[0], version[1], version[2], cmd); + r = -EINVAL; + } + + /* + * Fill in the kernel version. + */ + version[0] = DM_VERSION_MAJOR; + version[1] = DM_VERSION_MINOR; + version[2] = DM_VERSION_PATCHLEVEL; + if (copy_to_user(user->version, version, sizeof(version))) + return -EFAULT; + + return r; +} + +static void free_params(struct dm_ioctl *param) +{ + vfree(param); +} + +static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param) +{ + struct dm_ioctl tmp, *dmi; + + if (copy_from_user(&tmp, user, sizeof(tmp))) + return -EFAULT; + + if (tmp.data_size < sizeof(tmp)) + return -EINVAL; + + dmi = (struct dm_ioctl *) vmalloc(tmp.data_size); + if (!dmi) + return -ENOMEM; + + if (copy_from_user(dmi, user, tmp.data_size)) { + vfree(dmi); + return -EFAULT; + } + + *param = dmi; + return 0; +} + +static int validate_params(uint cmd, struct dm_ioctl *param) +{ + /* Ignores parameters */ + if (cmd == DM_REMOVE_ALL_CMD) + return 0; + + /* Unless creating, either name of uuid but not both */ + if (cmd != DM_DEV_CREATE_CMD) { + if ((!*param->uuid && !*param->name) || + (*param->uuid && *param->name)) { + DMWARN("one of name or uuid must be supplied"); + return -EINVAL; + } + } + + /* Ensure strings are terminated */ + param->name[DM_NAME_LEN - 1] = '\0'; + param->uuid[DM_UUID_LEN - 1] = '\0'; + + return 0; +} + +static int ctl_ioctl(struct inode *inode, struct file *file, + uint command, ulong u) +{ + + int r = 0, cmd; + struct dm_ioctl *param; + struct dm_ioctl *user = (struct dm_ioctl *) u; + ioctl_fn fn = NULL; + + if (_IOC_TYPE(command) != DM_IOCTL) + return -ENOTTY; + + cmd = _IOC_NR(command); + + /* + * Check the interface version passed in. This also + * writes out the kernel's interface version. + */ + r = check_version(cmd, user); + if (r) + return r; + + /* + * Nothing more to do for the version command. + */ + if (cmd == DM_VERSION_CMD) + return 0; + + fn = lookup_ioctl(cmd); + if (!fn) { + DMWARN("dm_ctl_ioctl: unknown command 0x%x", command); + return -ENOTTY; + } + + /* + * Copy the parameters into kernel space. + */ + r = copy_params(user, ¶m); + if (r) + return r; + + r = validate_params(cmd, param); + if (r) { + free_params(param); + return r; + } + + r = fn(param, user); + free_params(param); + return r; +} + +static struct file_operations _ctl_fops = { + open: ctl_open, + release: ctl_close, + ioctl: ctl_ioctl, + owner: THIS_MODULE, +}; + +static devfs_handle_t _ctl_handle; + +static struct miscdevice _dm_misc = { + minor: MISC_DYNAMIC_MINOR, + name: DM_NAME, + fops: &_ctl_fops +}; + +static int __init dm_devfs_init(void) { + int r; + char rname[64]; + + r = devfs_generate_path(_dm_misc.devfs_handle, rname + 3, + sizeof rname - 3); + if (r == -ENOSYS) + return 0; /* devfs not present */ + + if (r < 0) { + DMERR("devfs_generate_path failed for control device"); + return r; + } + + strncpy(rname + r, "../", 3); + r = devfs_mk_symlink(NULL, DM_DIR "/control", + DEVFS_FL_DEFAULT, rname + r, &_ctl_handle, NULL); + if (r) { + DMERR("devfs_mk_symlink failed for control device"); + return r; + } + devfs_auto_unregister(_dm_misc.devfs_handle, _ctl_handle); + + return 0; +} + +/* Create misc character device and link to DM_DIR/control */ +int __init dm_interface_init(void) +{ + int r; + + r = misc_register(&_dm_misc); + if (r) { + DMERR("misc_register failed for control device"); + return r; + } + + r = dm_devfs_init(); + if (r) { + misc_deregister(&_dm_misc); + return r; + } + + DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, + DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, + DM_DRIVER_EMAIL); + + return 0; +} + +void dm_interface_exit(void) +{ + if (misc_deregister(&_dm_misc) < 0) + DMERR("misc_deregister failed for control device"); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm-linear.c linux.20pre2-ac1/drivers/md/dm-linear.c --- linux.20pre2/drivers/md/dm-linear.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm-linear.c 2002-08-12 22:45:52.000000000 +0100 @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include +#include + +/* + * Linear: maps a linear range of a device. + */ +struct linear_c { + long delta; /* FIXME: we need a signed offset type */ + long start; /* For display only */ + struct dm_dev *dev; +}; + +/* + * Construct a linear mapping: + */ +static int linear_ctr(struct dm_table *t, offset_t b, offset_t l, + int argc, char **argv, void **context) +{ + struct linear_c *lc; + unsigned long start; /* FIXME: unsigned long long */ + char *end; + + if (argc != 2) { + *context = "dm-linear: Not enough arguments"; + return -EINVAL; + } + + lc = kmalloc(sizeof(*lc), GFP_KERNEL); + if (lc == NULL) { + *context = "dm-linear: Cannot allocate linear context"; + return -ENOMEM; + } + + start = simple_strtoul(argv[1], &end, 10); + if (*end) { + *context = "dm-linear: Invalid device sector"; + goto bad; + } + + if (dm_table_get_device(t, argv[0], start, l, t->mode, &lc->dev)) { + *context = "dm-linear: Device lookup failed"; + goto bad; + } + + lc->delta = (int) start - (int) b; + lc->start = start; + *context = lc; + return 0; + + bad: + kfree(lc); + return -EINVAL; +} + +static void linear_dtr(struct dm_table *t, void *c) +{ + struct linear_c *lc = (struct linear_c *) c; + + dm_table_put_device(t, lc->dev); + kfree(c); +} + +static int linear_map(struct buffer_head *bh, int rw, void *context) +{ + struct linear_c *lc = (struct linear_c *) context; + + bh->b_rdev = lc->dev->dev; + bh->b_rsector = bh->b_rsector + lc->delta; + + return 1; +} + +static int linear_status(status_type_t type, char *result, int maxlen, + void *context) +{ + struct linear_c *lc = (struct linear_c *) context; + + switch (type) { + case STATUSTYPE_INFO: + result[0] = '\0'; + break; + + case STATUSTYPE_TABLE: + snprintf(result, maxlen, "%s %ld", kdevname(lc->dev->dev), + lc->start); + break; + } + return 0; +} + +static struct target_type linear_target = { + name: "linear", + module: THIS_MODULE, + ctr: linear_ctr, + dtr: linear_dtr, + map: linear_map, + status: linear_status, +}; + +int __init dm_linear_init(void) +{ + int r = dm_register_target(&linear_target); + + if (r < 0) + DMERR("linear: register failed %d", r); + + return r; +} + +void dm_linear_exit(void) +{ + int r = dm_unregister_target(&linear_target); + + if (r < 0) + DMERR("linear: unregister failed %d", r); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm-snapshot.c linux.20pre2-ac1/drivers/md/dm-snapshot.c --- linux.20pre2/drivers/md/dm-snapshot.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm-snapshot.c 2002-08-12 22:45:52.000000000 +0100 @@ -0,0 +1,1169 @@ +/* + * dm-snapshot.c + * + * Copyright (C) 2001-2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dm-snapshot.h" +#include "kcopyd.h" + +/* + * FIXME: Remove this before release. + */ +#if 0 +#define DMDEBUG(x...) DMWARN( ## x) +#else +#define DMDEBUG(x...) +#endif + +/* + * The percentage increment we will wake up users at + */ +#define WAKE_UP_PERCENT 5 + +/* + * Hard sector size used all over the kernel + */ +#define SECTOR_SIZE 512 + +/* + * kcopyd priority of snapshot operations + */ +#define SNAPSHOT_COPY_PRIORITY 2 + +struct pending_exception { + struct exception e; + + /* + * Origin buffers waiting for this to complete are held + * in a list (using b_reqnext). + */ + struct buffer_head *origin_bhs; + struct buffer_head *snapshot_bhs; + + /* + * Other pending_exceptions that are processing this + * chunk. When this list is empty, we know we can + * complete the origins. + */ + struct list_head siblings; + + /* Pointer back to snapshot context */ + struct dm_snapshot *snap; + + /* + * 1 indicates the exception has already been sent to + * kcopyd. + */ + int started; +}; + +/* + * Hash table mapping origin volumes to lists of snapshots and + * a lock to protect it + */ +static kmem_cache_t *exception_cache; +static kmem_cache_t *pending_cache; +static mempool_t *pending_pool; + +/* + * One of these per registered origin, held in the snapshot_origins hash + */ +struct origin { + /* The origin device */ + kdev_t dev; + + struct list_head hash_list; + + /* List of snapshots for this origin */ + struct list_head snapshots; +}; + +/* + * Size of the hash table for origin volumes. If we make this + * the size of the minors list then it should be nearly perfect + */ +#define ORIGIN_HASH_SIZE 256 +#define ORIGIN_MASK 0xFF +static struct list_head *_origins; +static struct rw_semaphore _origins_lock; + +static int init_origin_hash(void) +{ + int i; + + _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head), + GFP_KERNEL); + if (!_origins) { + DMERR("Device mapper: Snapshot: unable to allocate memory"); + return -ENOMEM; + } + + for (i = 0; i < ORIGIN_HASH_SIZE; i++) + INIT_LIST_HEAD(_origins + i); + init_rwsem(&_origins_lock); + + return 0; +} + +static void exit_origin_hash(void) +{ + kfree(_origins); +} + +static inline unsigned int origin_hash(kdev_t dev) +{ + return MINOR(dev) & ORIGIN_MASK; +} + +static struct origin *__lookup_origin(kdev_t origin) +{ + struct list_head *slist; + struct list_head *ol; + struct origin *o; + + ol = &_origins[origin_hash(origin)]; + list_for_each(slist, ol) { + o = list_entry(slist, struct origin, hash_list); + + if (o->dev == origin) + return o; + } + + return NULL; +} + +static void __insert_origin(struct origin *o) +{ + struct list_head *sl = &_origins[origin_hash(o->dev)]; + list_add_tail(&o->hash_list, sl); +} + +/* + * Make a note of the snapshot and its origin so we can look it + * up when the origin has a write on it. + */ +static int register_snapshot(struct dm_snapshot *snap) +{ + struct origin *o; + kdev_t dev = snap->origin->dev; + + down_write(&_origins_lock); + o = __lookup_origin(dev); + + if (!o) { + /* New origin */ + o = kmalloc(sizeof(*o), GFP_KERNEL); + if (!o) { + up_write(&_origins_lock); + return -ENOMEM; + } + + /* Initialise the struct */ + INIT_LIST_HEAD(&o->snapshots); + o->dev = dev; + + __insert_origin(o); + } + + list_add_tail(&snap->list, &o->snapshots); + + up_write(&_origins_lock); + return 0; +} + +static void unregister_snapshot(struct dm_snapshot *s) +{ + struct origin *o; + + down_write(&_origins_lock); + o = __lookup_origin(s->origin->dev); + + list_del(&s->list); + if (list_empty(&o->snapshots)) { + list_del(&o->hash_list); + kfree(o); + } + + up_write(&_origins_lock); +} + +/* + * Implementation of the exception hash tables. + */ +static int init_exception_table(struct exception_table *et, uint32_t size) +{ + int i; + + et->hash_mask = size - 1; + et->table = vcalloc(size, sizeof(struct list_head)); + if (!et->table) + return -ENOMEM; + + for (i = 0; i < size; i++) + INIT_LIST_HEAD(et->table + i); + + return 0; +} + +static void exit_exception_table(struct exception_table *et, kmem_cache_t *mem) +{ + struct list_head *slot, *entry, *temp; + struct exception *ex; + int i, size; + + size = et->hash_mask + 1; + for (i = 0; i < size; i++) { + slot = et->table + i; + + list_for_each_safe(entry, temp, slot) { + ex = list_entry(entry, struct exception, hash_list); + kmem_cache_free(mem, ex); + } + } + + vfree(et->table); +} + +/* + * FIXME: check how this hash fn is performing. + */ +static inline uint32_t exception_hash(struct exception_table *et, chunk_t chunk) +{ + return chunk & et->hash_mask; +} + +static void insert_exception(struct exception_table *eh, struct exception *e) +{ + struct list_head *l = &eh->table[exception_hash(eh, e->old_chunk)]; + list_add(&e->hash_list, l); +} + +static inline void remove_exception(struct exception *e) +{ + list_del(&e->hash_list); +} + +/* + * Return the exception data for a sector, or NULL if not + * remapped. + */ +static struct exception *lookup_exception(struct exception_table *et, + chunk_t chunk) +{ + struct list_head *slot, *el; + struct exception *e; + + slot = &et->table[exception_hash(et, chunk)]; + list_for_each(el, slot) { + e = list_entry(el, struct exception, hash_list); + if (e->old_chunk == chunk) + return e; + } + + return NULL; +} + +static inline struct exception *alloc_exception(void) +{ + struct exception *e; + + e = kmem_cache_alloc(exception_cache, GFP_NOIO); + if (!e) + e = kmem_cache_alloc(exception_cache, GFP_ATOMIC); + + return e; +} + +static inline void free_exception(struct exception *e) +{ + kmem_cache_free(exception_cache, e); +} + +static inline struct pending_exception *alloc_pending_exception(void) +{ + return mempool_alloc(pending_pool, GFP_NOIO); +} + +static inline void free_pending_exception(struct pending_exception *pe) +{ + mempool_free(pe, pending_pool); +} + +int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new) +{ + struct exception *e; + + e = alloc_exception(); + if (!e) + return -ENOMEM; + + e->old_chunk = old; + e->new_chunk = new; + insert_exception(&s->complete, e); + return 0; +} + +/* + * Hard coded magic. + */ +static int calc_max_buckets(void) +{ + unsigned long mem; + + mem = num_physpages << PAGE_SHIFT; + mem /= 50; + mem /= sizeof(struct list_head); + + return mem; +} + +/* + * Rounds a number down to a power of 2. + */ +static inline uint32_t round_down(uint32_t n) +{ + while (n & (n - 1)) + n &= (n - 1); + return n; +} + +/* + * Allocate room for a suitable hash table. + */ +static int init_hash_tables(struct dm_snapshot *s) +{ + offset_t hash_size, cow_dev_size, origin_dev_size, max_buckets; + + /* + * Calculate based on the size of the original volume or + * the COW volume... + */ + cow_dev_size = get_dev_size(s->cow->dev); + origin_dev_size = get_dev_size(s->origin->dev); + max_buckets = calc_max_buckets(); + + hash_size = min(origin_dev_size, cow_dev_size) / s->chunk_size; + hash_size = min(hash_size, max_buckets); + + /* Round it down to a power of 2 */ + hash_size = round_down(hash_size); + if (init_exception_table(&s->complete, hash_size)) + return -ENOMEM; + + /* + * Allocate hash table for in-flight exceptions + * Make this smaller than the real hash table + */ + hash_size >>= 3; + if (!hash_size) + hash_size = 64; + + if (init_exception_table(&s->pending, hash_size)) { + exit_exception_table(&s->complete, exception_cache); + return -ENOMEM; + } + + return 0; +} + +/* + * Round a number up to the nearest 'size' boundary. size must + * be a power of 2. + */ +static inline ulong round_up(ulong n, ulong size) +{ + size--; + return (n + size) & ~size; +} + +/* + * Construct a snapshot mapping:

+ */ +static int snapshot_ctr(struct dm_table *t, offset_t b, offset_t l, + int argc, char **argv, void **context) +{ + struct dm_snapshot *s; + unsigned long chunk_size; + int r = -EINVAL; + char *persistent; + char *origin_path; + char *cow_path; + char *value; + int blocksize; + + if (argc < 4) { + *context = "dm-snapshot: requires exactly 4 arguments"; + r = -EINVAL; + goto bad; + } + + origin_path = argv[0]; + cow_path = argv[1]; + persistent = argv[2]; + + if ((*persistent & 0x5f) != 'P' && (*persistent & 0x5f) != 'N') { + *context = "Persistent flag is not P or N"; + r = -EINVAL; + goto bad; + } + + chunk_size = simple_strtoul(argv[3], &value, 10); + if (chunk_size == 0 || value == NULL) { + *context = "Invalid chunk size"; + r = -EINVAL; + goto bad; + } + + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) { + *context = "Cannot allocate snapshot context private structure"; + r = -ENOMEM; + goto bad; + } + + r = dm_table_get_device(t, origin_path, 0, 0, FMODE_READ, &s->origin); + if (r) { + *context = "Cannot get origin device"; + goto bad_free; + } + + r = dm_table_get_device(t, cow_path, 0, 0, + FMODE_READ | FMODE_WRITE, &s->cow); + if (r) { + dm_table_put_device(t, s->origin); + *context = "Cannot get COW device"; + goto bad_free; + } + + /* + * Chunk size must be multiple of page size. Silently + * round up if it's not. + */ + chunk_size = round_up(chunk_size, PAGE_SIZE / SECTOR_SIZE); + + /* Validate the chunk size against the device block size */ + blocksize = get_hardsect_size(s->cow->dev); + if (chunk_size % (blocksize / SECTOR_SIZE)) { + *context = "Chunk size is not a multiple of device blocksize"; + r = -EINVAL; + goto bad_putdev; + } + + /* Check the sizes are small enough to fit in one kiovec */ + if (chunk_size > KIO_MAX_SECTORS) { + *context = "Chunk size is too big"; + r = -EINVAL; + goto bad_putdev; + } + + /* Check chunk_size is a power of 2 */ + if (chunk_size & (chunk_size - 1)) { + *context = "Chunk size is not a power of 2"; + r = -EINVAL; + goto bad_putdev; + } + + s->chunk_size = chunk_size; + s->chunk_mask = chunk_size - 1; + s->type = *persistent; + for (s->chunk_shift = 0; chunk_size; + s->chunk_shift++, chunk_size >>= 1) + ; + s->chunk_shift--; + + s->valid = 1; + s->last_percent = 0; + s->table = t; + init_rwsem(&s->lock); + + /* Allocate hash table for COW data */ + if (init_hash_tables(s)) { + *context = "Unable to allocate hash table space"; + r = -ENOMEM; + goto bad_putdev; + } + + /* + * Check the persistent flag - done here because we need the iobuf + * to check the LV header + */ + s->store.snap = s; + + if ((*persistent & 0x5f) == 'P') + r = dm_create_persistent(&s->store, s->chunk_size); + else + r = dm_create_transient(&s->store, s, blocksize, context); + + if (r) { + *context = "Couldn't create exception store"; + r = -EINVAL; + goto bad_free1; + } + + /* Flush IO to the origin device */ +#if LVM_VFS_ENHANCEMENT + fsync_dev_lockfs(s->origin->dev); +#else + fsync_dev(s->origin->dev); +#endif + + /* Add snapshot to the list of snapshots for this origin */ + if (register_snapshot(s)) { + r = -EINVAL; + *context = "Cannot register snapshot origin"; + goto bad_free2; + } +#if LVM_VFS_ENHANCEMENT + unlockfs(s->origin->dev); +#endif + kcopyd_inc_client_count(); + + *context = s; + return 0; + + bad_free2: + s->store.destroy(&s->store); + + bad_free1: + exit_exception_table(&s->pending, pending_cache); + exit_exception_table(&s->complete, exception_cache); + + bad_putdev: + dm_table_put_device(t, s->cow); + dm_table_put_device(t, s->origin); + + bad_free: + kfree(s); + + bad: + return r; +} + +static void snapshot_dtr(struct dm_table *t, void *context) +{ + struct dm_snapshot *s = (struct dm_snapshot *) context; + + dm_table_event(s->table); + + unregister_snapshot(s); + + exit_exception_table(&s->pending, pending_cache); + exit_exception_table(&s->complete, exception_cache); + + /* Deallocate memory used */ + s->store.destroy(&s->store); + + dm_table_put_device(t, s->origin); + dm_table_put_device(t, s->cow); + kfree(s); + + kcopyd_dec_client_count(); +} + +/* + * We hold lists of buffer_heads, using the b_reqnext field. + */ +static void queue_buffer(struct buffer_head **queue, struct buffer_head *bh) +{ + bh->b_reqnext = *queue; + *queue = bh; +} + +/* + * Flush a list of buffers. + */ +static void flush_buffers(struct buffer_head *bh) +{ + struct buffer_head *n; + + DMDEBUG("begin flush"); + while (bh) { + n = bh->b_reqnext; + bh->b_reqnext = NULL; + DMDEBUG("flushing %p", bh); + generic_make_request(WRITE, bh); + bh = n; + } + + run_task_queue(&tq_disk); +} + +/* + * Error a list of buffers. + */ +static void error_buffers(struct buffer_head *bh) +{ + struct buffer_head *n; + + while (bh) { + n = bh->b_reqnext; + bh->b_reqnext = NULL; + buffer_IO_error(bh); + bh = n; + } +} + +static void pending_complete(struct pending_exception *pe, int success) +{ + struct exception *e; + struct dm_snapshot *s = pe->snap; + + if (success) { + e = alloc_exception(); + if (!e) { + printk("Unable to allocate exception."); + down_write(&s->lock); + s->store.drop_snapshot(&s->store); + s->valid = 0; + up_write(&s->lock); + return; + } + + /* + * Add a proper exception, and remove the + * inflight exception from the list. + */ + down_write(&s->lock); + + memcpy(e, &pe->e, sizeof(*e)); + insert_exception(&s->complete, e); + remove_exception(&pe->e); + + /* Submit any pending write BHs */ + up_write(&s->lock); + + flush_buffers(pe->snapshot_bhs); + DMDEBUG("Exception completed successfully."); + + /* Notify any interested parties */ + if (s->store.percent_full) { + int pc = s->store.percent_full(&s->store); + + if (pc >= s->last_percent + WAKE_UP_PERCENT) { + dm_table_event(s->table); + s->last_percent = pc - pc % WAKE_UP_PERCENT; + } + } + + } else { + /* Read/write error - snapshot is unusable */ + DMERR("Error reading/writing snapshot"); + + down_write(&s->lock); + s->store.drop_snapshot(&s->store); + s->valid = 0; + remove_exception(&pe->e); + up_write(&s->lock); + + error_buffers(pe->snapshot_bhs); + + dm_table_event(s->table); + DMDEBUG("Exception failed."); + } + + if (list_empty(&pe->siblings)) + flush_buffers(pe->origin_bhs); + else + list_del(&pe->siblings); + + free_pending_exception(pe); +} + +static void commit_callback(void *context, int success) +{ + struct pending_exception *pe = (struct pending_exception *) context; + pending_complete(pe, success); +} + +/* + * Called when the copy I/O has finished. kcopyd actually runs + * this code so don't block. + */ +static void copy_callback(int err, void *context) +{ + struct pending_exception *pe = (struct pending_exception *) context; + struct dm_snapshot *s = pe->snap; + + if (err) + pending_complete(pe, 0); + + else + /* Update the metadata if we are persistent */ + s->store.commit_exception(&s->store, &pe->e, commit_callback, + pe); +} + +/* + * Dispatches the copy operation to kcopyd. + */ +static inline void start_copy(struct pending_exception *pe) +{ + struct dm_snapshot *s = pe->snap; + struct kcopyd_region src, dest; + + src.dev = s->origin->dev; + src.sector = chunk_to_sector(s, pe->e.old_chunk); + src.count = s->chunk_size; + + dest.dev = s->cow->dev; + dest.sector = chunk_to_sector(s, pe->e.new_chunk); + dest.count = s->chunk_size; + + if (!pe->started) { + /* Hand over to kcopyd */ + kcopyd_copy(&src, &dest, copy_callback, pe); + pe->started = 1; + } +} + +/* + * Looks to see if this snapshot already has a pending exception + * for this chunk, otherwise it allocates a new one and inserts + * it into the pending table. + */ +static struct pending_exception *find_pending_exception(struct dm_snapshot *s, + struct buffer_head *bh) +{ + struct exception *e; + struct pending_exception *pe; + chunk_t chunk = sector_to_chunk(s, bh->b_rsector); + + /* + * Is there a pending exception for this already ? + */ + e = lookup_exception(&s->pending, chunk); + if (e) { + /* cast the exception to a pending exception */ + pe = list_entry(e, struct pending_exception, e); + + } else { + /* Create a new pending exception */ + pe = alloc_pending_exception(); + if (!pe) { + DMWARN("Couldn't allocate pending exception."); + return NULL; + } + + pe->e.old_chunk = chunk; + pe->origin_bhs = pe->snapshot_bhs = NULL; + INIT_LIST_HEAD(&pe->siblings); + pe->snap = s; + pe->started = 0; + + if (s->store.prepare_exception(&s->store, &pe->e)) { + free_pending_exception(pe); + s->valid = 0; + return NULL; + } + + insert_exception(&s->pending, &pe->e); + } + + return pe; +} + +static inline void remap_exception(struct dm_snapshot *s, struct exception *e, + struct buffer_head *bh) +{ + bh->b_rdev = s->cow->dev; + bh->b_rsector = chunk_to_sector(s, e->new_chunk) + + (bh->b_rsector & s->chunk_mask); +} + +static int snapshot_map(struct buffer_head *bh, int rw, void *context) +{ + struct exception *e; + struct dm_snapshot *s = (struct dm_snapshot *) context; + int r = 1; + chunk_t chunk; + struct pending_exception *pe; + + chunk = sector_to_chunk(s, bh->b_rsector); + + /* Full snapshots are not usable */ + if (!s->valid) + return -1; + + /* + * Write to snapshot - higher level takes care of RW/RO + * flags so we should only get this if we are + * writeable. + */ + if (rw == WRITE) { + + down_write(&s->lock); + + /* If the block is already remapped - use that, else remap it */ + e = lookup_exception(&s->complete, chunk); + if (e) + remap_exception(s, e, bh); + + else { + pe = find_pending_exception(s, bh); + + if (!pe) { + s->store.drop_snapshot(&s->store); + s->valid = 0; + } + + queue_buffer(&pe->snapshot_bhs, bh); + start_copy(pe); + r = 0; + } + + up_write(&s->lock); + + } else { + /* + * FIXME: this read path scares me because we + * always use the origin when we have a pending + * exception. However I can't think of a + * situation where this is wrong - ejt. + */ + + /* Do reads */ + down_read(&s->lock); + + /* See if it it has been remapped */ + e = lookup_exception(&s->complete, chunk); + if (e) + remap_exception(s, e, bh); + else + bh->b_rdev = s->origin->dev; + + up_read(&s->lock); + } + + return r; +} + +static void list_merge(struct list_head *l1, struct list_head *l2) +{ + struct list_head *l1_n, *l2_p; + + l1_n = l1->next; + l2_p = l2->prev; + + l1->next = l2; + l2->prev = l1; + + l2_p->next = l1_n; + l1_n->prev = l2_p; +} + +static int __origin_write(struct list_head *snapshots, struct buffer_head *bh) +{ + int r = 1; + struct list_head *sl; + struct dm_snapshot *snap; + struct exception *e; + struct pending_exception *pe, *last = NULL; + chunk_t chunk; + + /* Do all the snapshots on this origin */ + list_for_each(sl, snapshots) { + snap = list_entry(sl, struct dm_snapshot, list); + + /* Only deal with valid snapshots */ + if (!snap->valid) + continue; + + down_write(&snap->lock); + + /* + * Remember, different snapshots can have + * different chunk sizes. + */ + chunk = sector_to_chunk(snap, bh->b_rsector); + + /* + * Check exception table to see if block + * is already remapped in this snapshot + * and trigger an exception if not. + */ + e = lookup_exception(&snap->complete, chunk); + if (!e) { + pe = find_pending_exception(snap, bh); + if (!pe) { + snap->store.drop_snapshot(&snap->store); + snap->valid = 0; + + } else { + if (last) + list_merge(&pe->siblings, + &last->siblings); + + last = pe; + r = 0; + } + } + + up_write(&snap->lock); + } + + /* + * Now that we have a complete pe list we can start the copying. + */ + if (last) { + pe = last; + do { + down_write(&pe->snap->lock); + queue_buffer(&pe->origin_bhs, bh); + start_copy(pe); + up_write(&pe->snap->lock); + pe = list_entry(pe->siblings.next, + struct pending_exception, siblings); + + } while (pe != last); + } + + return r; +} + +static int snapshot_status(status_type_t type, char *result, + int maxlen, void *context) +{ + struct dm_snapshot *snap = (struct dm_snapshot *) context; + char cow[16]; + char org[16]; + + switch (type) { + case STATUSTYPE_INFO: + if (!snap->valid) + snprintf(result, maxlen, "Invalid"); + else { + if (snap->store.percent_full) + snprintf(result, maxlen, "%d%%", + snap->store.percent_full(&snap-> + store)); + else + snprintf(result, maxlen, "Unknown"); + } + break; + + case STATUSTYPE_TABLE: + /* + * kdevname returns a static pointer so we need + * to make private copies if the output is to + * make sense. + */ + strncpy(cow, kdevname(snap->cow->dev), sizeof(cow)); + strncpy(org, kdevname(snap->origin->dev), sizeof(org)); + snprintf(result, maxlen, "%s %s %c %ld", org, cow, + snap->type, snap->chunk_size); + break; + } + + return 0; +} + +/* + * Called on a write from the origin driver. + */ +int do_origin(struct dm_dev *origin, struct buffer_head *bh) +{ + struct origin *o; + int r; + + down_read(&_origins_lock); + o = __lookup_origin(origin->dev); + if (!o) + BUG(); + + r = __origin_write(&o->snapshots, bh); + up_read(&_origins_lock); + + return r; +} + +/* + * Origin: maps a linear range of a device, with hooks for snapshotting. + */ + +/* + * Construct an origin mapping: + * The context for an origin is merely a 'struct dm_dev *' + * pointing to the real device. + */ +static int origin_ctr(struct dm_table *t, offset_t b, offset_t l, + int argc, char **argv, void **context) +{ + int r; + struct dm_dev *dev; + + if (argc != 1) { + *context = "dm-origin: incorrect number of arguments"; + return -EINVAL; + } + + r = dm_table_get_device(t, argv[0], 0, l, t->mode, &dev); + if (r) { + *context = "Cannot get target device"; + return r; + } + + *context = dev; + + return 0; +} + +static void origin_dtr(struct dm_table *t, void *c) +{ + struct dm_dev *dev = (struct dm_dev *) c; + dm_table_put_device(t, dev); +} + +static int origin_map(struct buffer_head *bh, int rw, void *context) +{ + struct dm_dev *dev = (struct dm_dev *) context; + bh->b_rdev = dev->dev; + + /* Only tell snapshots if this is a write */ + return (rw == WRITE) ? do_origin(dev, bh) : 1; +} + +static int origin_status(status_type_t type, char *result, + int maxlen, void *context) +{ + struct dm_dev *dev = (struct dm_dev *) context; + + switch (type) { + case STATUSTYPE_INFO: + result[0] = '\0'; + break; + + case STATUSTYPE_TABLE: + snprintf(result, maxlen, "%s", kdevname(dev->dev)); + break; + } + + return 0; +} + +static struct target_type origin_target = { + name: "snapshot-origin", + module: THIS_MODULE, + ctr: origin_ctr, + dtr: origin_dtr, + map: origin_map, + status: origin_status, + err: NULL +}; + +static struct target_type snapshot_target = { + name: "snapshot", + module: THIS_MODULE, + ctr: snapshot_ctr, + dtr: snapshot_dtr, + map: snapshot_map, + status: snapshot_status, + err: NULL +}; + +int __init dm_snapshot_init(void) +{ + int r; + + r = dm_register_target(&snapshot_target); + if (r) { + DMERR("snapshot target register failed %d", r); + return r; + } + + r = dm_register_target(&origin_target); + if (r < 0) { + DMERR("Device mapper: Origin: register failed %d\n", r); + goto bad1; + } + + r = init_origin_hash(); + if (r) { + DMERR("init_origin_hash failed."); + goto bad2; + } + + exception_cache = kmem_cache_create("dm-snapshot-ex", + sizeof(struct exception), + __alignof__(struct exception), + 0, NULL, NULL); + if (!exception_cache) { + DMERR("Couldn't create exception cache."); + r = -ENOMEM; + goto bad3; + } + + pending_cache = + kmem_cache_create("dm-snapshot-in", + sizeof(struct pending_exception), + __alignof__(struct pending_exception), + 0, NULL, NULL); + if (!pending_cache) { + DMERR("Couldn't create pending cache."); + r = -ENOMEM; + goto bad4; + } + + pending_pool = mempool_create(128, mempool_alloc_slab, + mempool_free_slab, pending_cache); + if (!pending_pool) { + DMERR("Couldn't create pending pool."); + r = -ENOMEM; + goto bad5; + } + + return 0; + + bad5: + kmem_cache_destroy(pending_cache); + bad4: + kmem_cache_destroy(exception_cache); + bad3: + exit_origin_hash(); + bad2: + dm_unregister_target(&origin_target); + bad1: + dm_unregister_target(&snapshot_target); + return r; +} + +void dm_snapshot_exit(void) +{ + int r; + + r = dm_unregister_target(&snapshot_target); + if (r) + DMERR("snapshot unregister failed %d", r); + + r = dm_unregister_target(&origin_target); + if (r) + DMERR("origin unregister failed %d", r); + + exit_origin_hash(); + mempool_destroy(pending_pool); + kmem_cache_destroy(pending_cache); + kmem_cache_destroy(exception_cache); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm-snapshot.h linux.20pre2-ac1/drivers/md/dm-snapshot.h --- linux.20pre2/drivers/md/dm-snapshot.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm-snapshot.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,147 @@ +/* + * dm-snapshot.c + * + * Copyright (C) 2001-2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#ifndef DM_SNAPSHOT_H +#define DM_SNAPSHOT_H + +#include "dm.h" +#include + +struct exception_table { + uint32_t hash_mask; + struct list_head *table; +}; + +/* + * The snapshot code deals with largish chunks of the disk at a + * time. Typically 64k - 256k. + */ +/* FIXME: can we get away with limiting these to a uint32_t ? */ +typedef offset_t chunk_t; + +/* + * An exception is used where an old chunk of data has been + * replaced by a new one. + */ +struct exception { + struct list_head hash_list; + + chunk_t old_chunk; + chunk_t new_chunk; +}; + +/* + * Abstraction to handle the meta/layout of exception stores (the + * COW device). + */ +struct exception_store { + + /* + * Destroys this object when you've finished with it. + */ + void (*destroy) (struct exception_store *store); + + /* + * Find somewhere to store the next exception. + */ + int (*prepare_exception) (struct exception_store *store, + struct exception *e); + + /* + * Update the metadata with this exception. + */ + void (*commit_exception) (struct exception_store *store, + struct exception *e, + void (*callback) (void *, int success), + void *callback_context); + + /* + * The snapshot is invalid, note this in the metadata. + */ + void (*drop_snapshot) (struct exception_store *store); + + /* + * Return the %age full of the snapshot + */ + int (*percent_full) (struct exception_store *store); + + struct dm_snapshot *snap; + void *context; +}; + +struct dm_snapshot { + struct rw_semaphore lock; + struct dm_table *table; + + struct dm_dev *origin; + struct dm_dev *cow; + + /* List of snapshots per Origin */ + struct list_head list; + + /* Size of data blocks saved - must be a power of 2 */ + chunk_t chunk_size; + chunk_t chunk_mask; + chunk_t chunk_shift; + + /* You can't use a snapshot if this is 0 (e.g. if full) */ + int valid; + + /* Used for display of table */ + char type; + + /* The last percentage we notified */ + int last_percent; + + struct exception_table pending; + struct exception_table complete; + + /* The on disk metadata handler */ + struct exception_store store; +}; + +/* + * Used by the exception stores to load exceptions hen + * initialising. + */ +int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new); + +/* + * Constructor and destructor for the default persistent + * store. + */ +int dm_create_persistent(struct exception_store *store, uint32_t chunk_size); + +int dm_create_transient(struct exception_store *store, + struct dm_snapshot *s, int blocksize, void **error); + +/* + * Return the number of sectors in the device. + */ +static inline offset_t get_dev_size(kdev_t dev) +{ + int *sizes; + + sizes = blk_size[MAJOR(dev)]; + if (sizes) + return sizes[MINOR(dev)] << 1; + + return 0; +} + +static inline chunk_t sector_to_chunk(struct dm_snapshot *s, offset_t sector) +{ + return (sector & ~s->chunk_mask) >> s->chunk_shift; +} + +static inline offset_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk) +{ + return chunk << s->chunk_shift; +} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm-stripe.c linux.20pre2-ac1/drivers/md/dm-stripe.c --- linux.20pre2/drivers/md/dm-stripe.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm-stripe.c 2002-08-12 22:45:52.000000000 +0100 @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include +#include +#include + +struct stripe { + struct dm_dev *dev; + offset_t physical_start; +}; + +struct stripe_c { + offset_t logical_start; + uint32_t stripes; + + /* The size of this target / num. stripes */ + uint32_t stripe_width; + + /* stripe chunk size */ + uint32_t chunk_shift; + offset_t chunk_mask; + + struct stripe stripe[0]; +}; + +static inline struct stripe_c *alloc_context(int stripes) +{ + size_t len; + + if (array_too_big(sizeof(struct stripe_c), sizeof(struct stripe), + stripes)) + return NULL; + + len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes); + + return kmalloc(len, GFP_KERNEL); +} + +/* + * Parse a single pair + */ +static int get_stripe(struct dm_table *t, struct stripe_c *sc, + int stripe, char **argv) +{ + char *end; + unsigned long start; + + start = simple_strtoul(argv[1], &end, 10); + if (*end) + return -EINVAL; + + if (dm_table_get_device(t, argv[0], start, sc->stripe_width, + t->mode, &sc->stripe[stripe].dev)) + return -ENXIO; + + sc->stripe[stripe].physical_start = start; + return 0; +} + +/* + * Construct a striped mapping. + * [ ]+ + */ +static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l, + int argc, char **argv, void **context) +{ + struct stripe_c *sc; + uint32_t stripes; + uint32_t chunk_size; + char *end; + int r, i; + + if (argc < 2) { + *context = "dm-stripe: Not enough arguments"; + return -EINVAL; + } + + stripes = simple_strtoul(argv[0], &end, 10); + if (*end) { + *context = "dm-stripe: Invalid stripe count"; + return -EINVAL; + } + + chunk_size = simple_strtoul(argv[1], &end, 10); + if (*end) { + *context = "dm-stripe: Invalid chunk_size"; + return -EINVAL; + } + + if (l % stripes) { + *context = "dm-stripe: Target length not divisable by " + "number of stripes"; + return -EINVAL; + } + + sc = alloc_context(stripes); + if (!sc) { + *context = "dm-stripe: Memory allocation for striped context " + "failed"; + return -ENOMEM; + } + + sc->logical_start = b; + sc->stripes = stripes; + sc->stripe_width = l / stripes; + + /* + * chunk_size is a power of two + */ + if (!chunk_size || (chunk_size & (chunk_size - 1))) { + *context = "dm-stripe: Invalid chunk size"; + kfree(sc); + return -EINVAL; + } + + sc->chunk_mask = chunk_size - 1; + for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++) + chunk_size >>= 1; + sc->chunk_shift--; + + /* + * Get the stripe destinations. + */ + for (i = 0; i < stripes; i++) { + if (argc < 2) { + *context = "dm-stripe: Not enough destinations " + "specified"; + kfree(sc); + return -EINVAL; + } + + argv += 2; + + r = get_stripe(t, sc, i, argv); + if (r < 0) { + *context = "dm-stripe: Couldn't parse stripe " + "destination"; + while (i--) + dm_table_put_device(t, sc->stripe[i].dev); + kfree(sc); + return r; + } + } + + *context = sc; + return 0; +} + +static void stripe_dtr(struct dm_table *t, void *c) +{ + unsigned int i; + struct stripe_c *sc = (struct stripe_c *) c; + + for (i = 0; i < sc->stripes; i++) + dm_table_put_device(t, sc->stripe[i].dev); + + kfree(sc); +} + +static int stripe_map(struct buffer_head *bh, int rw, void *context) +{ + struct stripe_c *sc = (struct stripe_c *) context; + + offset_t offset = bh->b_rsector - sc->logical_start; + uint32_t chunk = (uint32_t) (offset >> sc->chunk_shift); + uint32_t stripe = chunk % sc->stripes; /* 32bit modulus */ + chunk = chunk / sc->stripes; + + bh->b_rdev = sc->stripe[stripe].dev->dev; + bh->b_rsector = sc->stripe[stripe].physical_start + + (chunk << sc->chunk_shift) + (offset & sc->chunk_mask); + return 1; +} + +static int stripe_status(status_type_t type, char *result, int maxlen, + void *context) +{ + struct stripe_c *sc = (struct stripe_c *) context; + int offset; + int i; + + switch (type) { + case STATUSTYPE_INFO: + result[0] = '\0'; + break; + + case STATUSTYPE_TABLE: + offset = snprintf(result, maxlen, "%d %ld", + sc->stripes, sc->chunk_mask + 1); + for (i = 0; i < sc->stripes; i++) { + offset += + snprintf(result + offset, maxlen - offset, + " %s %ld", + kdevname(sc->stripe[i].dev->dev), + sc->stripe[i].physical_start); + } + break; + } + return 0; +} + +static struct target_type stripe_target = { + name: "striped", + module: THIS_MODULE, + ctr: stripe_ctr, + dtr: stripe_dtr, + map: stripe_map, + status: stripe_status, +}; + +int __init dm_stripe_init(void) +{ + int r; + + r = dm_register_target(&stripe_target); + if (r < 0) + DMWARN("striped target registration failed"); + + return r; +} + +void dm_stripe_exit(void) +{ + if (dm_unregister_target(&stripe_target)) + DMWARN("striped target unregistration failed"); + + return; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm-table.c linux.20pre2-ac1/drivers/md/dm-table.c --- linux.20pre2/drivers/md/dm-table.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm-table.c 2002-08-12 22:45:52.000000000 +0100 @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include + +/* ceiling(n / size) * size */ +static inline unsigned long round_up(unsigned long n, unsigned long size) +{ + unsigned long r = n % size; + return n + (r ? (size - r) : 0); +} + +/* ceiling(n / size) */ +static inline unsigned long div_up(unsigned long n, unsigned long size) +{ + return round_up(n, size) / size; +} + +/* similar to ceiling(log_size(n)) */ +static uint int_log(unsigned long n, unsigned long base) +{ + int result = 0; + + while (n > 1) { + n = div_up(n, base); + result++; + } + + return result; +} + +/* + * return the highest key that you could lookup + * from the n'th node on level l of the btree. + */ +static offset_t high(struct dm_table *t, int l, int n) +{ + for (; l < t->depth - 1; l++) + n = get_child(n, CHILDREN_PER_NODE - 1); + + if (n >= t->counts[l]) + return (offset_t) - 1; + + return get_node(t, l, n)[KEYS_PER_NODE - 1]; +} + +/* + * fills in a level of the btree based on the + * highs of the level below it. + */ +static int setup_btree_index(int l, struct dm_table *t) +{ + int n, k; + offset_t *node; + + for (n = 0; n < t->counts[l]; n++) { + node = get_node(t, l, n); + + for (k = 0; k < KEYS_PER_NODE; k++) + node[k] = high(t, l + 1, get_child(n, k)); + } + + return 0; +} + +/* + * highs, and targets are managed as dynamic + * arrays during a table load. + */ +static int alloc_targets(struct dm_table *t, int num) +{ + offset_t *n_highs; + struct target *n_targets; + int n = t->num_targets; + + /* + * Allocate both the target array and offset array at once. + */ + n_highs = (offset_t *) vcalloc(sizeof(struct target) + sizeof(offset_t), + num); + if (!n_highs) + return -ENOMEM; + + n_targets = (struct target *) (n_highs + num); + + if (n) { + memcpy(n_highs, t->highs, sizeof(*n_highs) * n); + memcpy(n_targets, t->targets, sizeof(*n_targets) * n); + } + + memset(n_highs + n, -1, sizeof(*n_highs) * (num - n)); + if (t->highs) + vfree(t->highs); + + t->num_allocated = num; + t->highs = n_highs; + t->targets = n_targets; + + return 0; +} + +int dm_table_create(struct dm_table **result, int mode) +{ + struct dm_table *t = kmalloc(sizeof(*t), GFP_NOIO); + + if (!t) + return -ENOMEM; + + memset(t, 0, sizeof(*t)); + INIT_LIST_HEAD(&t->devices); + + /* allocate a single node's worth of targets to begin with */ + if (alloc_targets(t, KEYS_PER_NODE)) { + kfree(t); + t = NULL; + return -ENOMEM; + } + + init_waitqueue_head(&t->eventq); + t->mode = mode; + *result = t; + return 0; +} + +static void free_devices(struct list_head *devices) +{ + struct list_head *tmp, *next; + + for (tmp = devices->next; tmp != devices; tmp = next) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + next = tmp->next; + kfree(dd); + } +} + +void dm_table_destroy(struct dm_table *t) +{ + int i; + + /* destroying the table counts as an event */ + dm_table_event(t); + + /* free the indexes (see dm_table_complete) */ + if (t->depth >= 2) + vfree(t->index[t->depth - 2]); + + /* free the targets */ + for (i = 0; i < t->num_targets; i++) { + struct target *tgt = &t->targets[i]; + + dm_put_target_type(t->targets[i].type); + + if (tgt->type->dtr) + tgt->type->dtr(t, tgt->private); + } + + vfree(t->highs); + + /* free the device list */ + if (t->devices.next != &t->devices) { + DMWARN("devices still present during destroy: " + "dm_table_remove_device calls missing"); + + free_devices(&t->devices); + } + + kfree(t); +} + +/* + * Checks to see if we need to extend highs or targets. + */ +static inline int check_space(struct dm_table *t) +{ + if (t->num_targets >= t->num_allocated) + return alloc_targets(t, t->num_allocated * 2); + + return 0; +} + +/* + * Convert a device path to a kdev_t. + */ +int lookup_device(const char *path, kdev_t *dev) +{ + int r; + struct nameidata nd; + struct inode *inode; + + if (!path_init(path, LOOKUP_FOLLOW, &nd)) + return 0; + + if ((r = path_walk(path, &nd))) + goto bad; + + inode = nd.dentry->d_inode; + if (!inode) { + r = -ENOENT; + goto bad; + } + + if (!S_ISBLK(inode->i_mode)) { + r = -EINVAL; + goto bad; + } + + *dev = inode->i_rdev; + + bad: + path_release(&nd); + return r; +} + +/* + * See if we've already got a device in the list. + */ +static struct dm_dev *find_device(struct list_head *l, kdev_t dev) +{ + struct list_head *tmp; + + list_for_each(tmp, l) { + struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + if (dd->dev == dev) + return dd; + } + + return NULL; +} + +/* + * Open a device so we can use it as a map destination. + */ +static int open_dev(struct dm_dev *d) +{ + int err; + + if (d->bd) + BUG(); + + if (!(d->bd = bdget(kdev_t_to_nr(d->dev)))) + return -ENOMEM; + + if ((err = blkdev_get(d->bd, d->mode, 0, BDEV_FILE))) + return err; + + return 0; +} + +/* + * Close a device that we've been using. + */ +static void close_dev(struct dm_dev *d) +{ + if (!d->bd) + return; + + blkdev_put(d->bd, BDEV_FILE); + d->bd = NULL; +} + +/* + * If possible (ie. blk_size[major] is set), this + * checks an area of a destination device is + * valid. + */ +static int check_device_area(kdev_t dev, offset_t start, offset_t len) +{ + int *sizes; + offset_t dev_size; + + if (!(sizes = blk_size[MAJOR(dev)]) || !(dev_size = sizes[MINOR(dev)])) + /* we don't know the device details, + * so give the benefit of the doubt */ + return 1; + + /* convert to 512-byte sectors */ + dev_size <<= 1; + + return ((start < dev_size) && (len <= (dev_size - start))); +} + +/* + * This upgrades the mode on an already open dm_dev. Being + * careful to leave things as they were if we fail to reopen the + * device. + */ +static int upgrade_mode(struct dm_dev *dd, int new_mode) +{ + int r; + struct dm_dev dd_copy; + + memcpy(&dd_copy, dd, sizeof(dd_copy)); + + dd->mode |= new_mode; + dd->bd = NULL; + r = open_dev(dd); + if (!r) + close_dev(&dd_copy); + else + memcpy(dd, &dd_copy, sizeof(dd_copy)); + + return r; +} + +/* + * Add a device to the list, or just increment the usage count + * if it's already present. + */ +int dm_table_get_device(struct dm_table *t, const char *path, + offset_t start, offset_t len, int mode, + struct dm_dev **result) +{ + int r; + kdev_t dev; + struct dm_dev *dd; + int major, minor; + + if (sscanf(path, "%x:%x", &major, &minor) == 2) { + /* Extract the major/minor numbers */ + dev = MKDEV(major, minor); + } else { + /* convert the path to a device */ + if ((r = lookup_device(path, &dev))) + return r; + } + + dd = find_device(&t->devices, dev); + if (!dd) { + dd = kmalloc(sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; + + dd->mode = mode; + dd->dev = dev; + dd->bd = NULL; + + if ((r = open_dev(dd))) { + kfree(dd); + return r; + } + + atomic_set(&dd->count, 0); + list_add(&dd->list, &t->devices); + + } else if (dd->mode != (mode | dd->mode)) { + r = upgrade_mode(dd, mode); + if (r) + return r; + } + atomic_inc(&dd->count); + + if (!check_device_area(dd->dev, start, len)) { + DMWARN("device %s too small for target", path); + dm_table_put_device(t, dd); + return -EINVAL; + } + + *result = dd; + + return 0; +} + +/* + * Decrement a devices use count and remove it if neccessary. + */ +void dm_table_put_device(struct dm_table *t, struct dm_dev *dd) +{ + if (atomic_dec_and_test(&dd->count)) { + close_dev(dd); + list_del(&dd->list); + kfree(dd); + } +} + +/* + * Adds a target to the map + */ +int dm_table_add_target(struct dm_table *t, offset_t highs, + struct target_type *type, void *private) +{ + int r, n; + + if ((r = check_space(t))) + return r; + + n = t->num_targets++; + t->highs[n] = highs; + t->targets[n].type = type; + t->targets[n].private = private; + + return 0; +} + +static int setup_indexes(struct dm_table *t) +{ + int i, total = 0; + offset_t *indexes; + + /* allocate the space for *all* the indexes */ + for (i = t->depth - 2; i >= 0; i--) { + t->counts[i] = div_up(t->counts[i + 1], CHILDREN_PER_NODE); + total += t->counts[i]; + } + + indexes = (offset_t *) vcalloc(total, (unsigned long) NODE_SIZE); + if (!indexes) + return -ENOMEM; + + /* set up internal nodes, bottom-up */ + for (i = t->depth - 2, total = 0; i >= 0; i--) { + t->index[i] = indexes; + indexes += (KEYS_PER_NODE * t->counts[i]); + setup_btree_index(i, t); + } + + return 0; +} + +/* + * Builds the btree to index the map + */ +int dm_table_complete(struct dm_table *t) +{ + int leaf_nodes, r = 0; + + /* how many indexes will the btree have ? */ + leaf_nodes = div_up(t->num_targets, KEYS_PER_NODE); + t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); + + /* leaf layer has already been set up */ + t->counts[t->depth - 1] = leaf_nodes; + t->index[t->depth - 1] = t->highs; + + if (t->depth >= 2) + r = setup_indexes(t); + + return r; +} + +void dm_table_event(struct dm_table *t) +{ + wake_up_interruptible(&t->eventq); +} + +EXPORT_SYMBOL(dm_table_get_device); +EXPORT_SYMBOL(dm_table_put_device); +EXPORT_SYMBOL(dm_table_event); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/dm-target.c linux.20pre2-ac1/drivers/md/dm-target.c --- linux.20pre2/drivers/md/dm-target.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/dm-target.c 2002-08-12 22:42:29.000000000 +0100 @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited + * + * This file is released under the GPL. + */ + +#include "dm.h" + +#include + +struct tt_internal { + struct target_type tt; + + struct list_head list; + long use; +}; + +static LIST_HEAD(_targets); +static rwlock_t _lock = RW_LOCK_UNLOCKED; + +#define DM_MOD_NAME_SIZE 32 + +/* + * Destructively splits up the argument list to pass to ctr. + */ +int split_args(int max, int *argc, char **argv, char *input) +{ + char *start, *end = input, *out; + *argc = 0; + + while (1) { + start = end; + + /* Skip whitespace */ + while (*start && isspace(*start)) + start++; + + if (!*start) + break; /* success, we hit the end */ + + /* 'out' is used to remove any back-quotes */ + end = out = start; + while (*end) { + /* Everything apart from '\0' can be quoted */ + if (*end == '\\' && *(end + 1)) { + *out++ = *(end + 1); + end += 2; + continue; + } + + if (isspace(*end)) + break; /* end of token */ + + *out++ = *end++; + } + + /* have we already filled the array ? */ + if ((*argc + 1) > max) + return -EINVAL; + + /* we know this is whitespace */ + if (*end) + end++; + + /* terminate the string and put it in the array */ + *out = '\0'; + argv[*argc] = start; + (*argc)++; + } + + return 0; +} + +static inline struct tt_internal *__find_target_type(const char *name) +{ + struct list_head *tih; + struct tt_internal *ti; + + list_for_each(tih, &_targets) { + ti = list_entry(tih, struct tt_internal, list); + + if (!strcmp(name, ti->tt.name)) + return ti; + } + + return NULL; +} + +static struct tt_internal *get_target_type(const char *name) +{ + struct tt_internal *ti; + + read_lock(&_lock); + ti = __find_target_type(name); + + if (ti) { + if (ti->use == 0 && ti->tt.module) + __MOD_INC_USE_COUNT(ti->tt.module); + ti->use++; + } + read_unlock(&_lock); + + return ti; +} + +static void load_module(const char *name) +{ + char module_name[DM_MOD_NAME_SIZE] = "dm-"; + + /* Length check for strcat() below */ + if (strlen(name) > (DM_MOD_NAME_SIZE - 4)) + return; + + strcat(module_name, name); + request_module(module_name); + + return; +} + +struct target_type *dm_get_target_type(const char *name) +{ + struct tt_internal *ti = get_target_type(name); + + if (!ti) { + load_module(name); + ti = get_target_type(name); + } + + return ti ? &ti->tt : NULL; +} + +void dm_put_target_type(struct target_type *t) +{ + struct tt_internal *ti = (struct tt_internal *) t; + + read_lock(&_lock); + if (--ti->use == 0 && ti->tt.module) + __MOD_DEC_USE_COUNT(ti->tt.module); + + if (ti->use < 0) + BUG(); + read_unlock(&_lock); + + return; +} + +static struct tt_internal *alloc_target(struct target_type *t) +{ + struct tt_internal *ti = kmalloc(sizeof(*ti), GFP_KERNEL); + + if (ti) { + memset(ti, 0, sizeof(*ti)); + ti->tt = *t; + } + + return ti; +} + +int dm_register_target(struct target_type *t) +{ + int rv = 0; + struct tt_internal *ti = alloc_target(t); + + if (!ti) + return -ENOMEM; + + write_lock(&_lock); + if (__find_target_type(t->name)) + rv = -EEXIST; + else + list_add(&ti->list, &_targets); + + write_unlock(&_lock); + return rv; +} + +int dm_unregister_target(struct target_type *t) +{ + struct tt_internal *ti; + + write_lock(&_lock); + if (!(ti = __find_target_type(t->name))) { + write_unlock(&_lock); + return -EINVAL; + } + + if (ti->use) { + write_unlock(&_lock); + return -ETXTBSY; + } + + list_del(&ti->list); + kfree(ti); + + write_unlock(&_lock); + return 0; +} + +/* + * io-err: always fails an io, useful for bringing + * up LV's that have holes in them. + */ +static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l, + int argc, char **args, void **context) +{ + *context = NULL; + return 0; +} + +static void io_err_dtr(struct dm_table *t, void *c) +{ + /* empty */ + return; +} + +static int io_err_map(struct buffer_head *bh, int rw, void *context) +{ + buffer_IO_error(bh); + return 0; +} + +static struct target_type error_target = { + name: "error", + ctr: io_err_ctr, + dtr: io_err_dtr, + map: io_err_map, + status: NULL, +}; + +int dm_target_init(void) +{ + return dm_register_target(&error_target); +} + +void dm_target_exit(void) +{ + if (dm_unregister_target(&error_target)) + DMWARN("error target unregistration failed"); +} + +EXPORT_SYMBOL(dm_register_target); +EXPORT_SYMBOL(dm_unregister_target); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/kcopyd.c linux.20pre2-ac1/drivers/md/kcopyd.c --- linux.20pre2/drivers/md/kcopyd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/kcopyd.c 2002-08-12 22:46:01.000000000 +0100 @@ -0,0 +1,841 @@ +/* + * Copyright (C) 2002 Sistina Software (UK) Limited. + * + * This file is released under the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kcopyd.h" + +/* FIXME: this is only needed for the DMERR macros */ +#include "dm.h" + +/* + * Hard sector size used all over the kernel. + */ +#define SECTOR_SIZE 512 +#define SECTOR_SHIFT 9 + +static void wake_kcopyd(void); + +/*----------------------------------------------------------------- + * We reserve our own pool of preallocated pages that are + * only used for kcopyd io. + *---------------------------------------------------------------*/ + +/* + * FIXME: This should be configurable. + */ +#define NUM_PAGES 512 + +static DECLARE_MUTEX(_pages_lock); +static int _num_free_pages; +static struct page *_pages_array[NUM_PAGES]; +static DECLARE_MUTEX(start_lock); + +static int init_pages(void) +{ + int i; + struct page *p; + + for (i = 0; i < NUM_PAGES; i++) { + p = alloc_page(GFP_KERNEL); + if (!p) + goto bad; + + LockPage(p); + _pages_array[i] = p; + } + + _num_free_pages = NUM_PAGES; + return 0; + + bad: + while (i--) + __free_page(_pages_array[i]); + return -ENOMEM; +} + +static void exit_pages(void) +{ + int i; + struct page *p; + + for (i = 0; i < NUM_PAGES; i++) { + p = _pages_array[i]; + UnlockPage(p); + __free_page(p); + } + + _num_free_pages = 0; +} + +static int kcopyd_get_pages(int num, struct page **result) +{ + int i; + + down(&_pages_lock); + if (_num_free_pages < num) { + up(&_pages_lock); + return -ENOMEM; + } + + for (i = 0; i < num; i++) { + _num_free_pages--; + result[i] = _pages_array[_num_free_pages]; + } + up(&_pages_lock); + + return 0; +} + +static void kcopyd_free_pages(int num, struct page **result) +{ + int i; + + down(&_pages_lock); + for (i = 0; i < num; i++) + _pages_array[_num_free_pages++] = result[i]; + up(&_pages_lock); +} + +/*----------------------------------------------------------------- + * We keep our own private pool of buffer_heads. These are just + * held in a list on the b_reqnext field. + *---------------------------------------------------------------*/ + +/* + * Make sure we have enough buffers to always keep the pages + * occupied. So we assume the worst case scenario where blocks + * are the size of a single sector. + */ +#define NUM_BUFFERS NUM_PAGES * (PAGE_SIZE / SECTOR_SIZE) + +static spinlock_t _buffer_lock = SPIN_LOCK_UNLOCKED; +static struct buffer_head *_all_buffers; +static struct buffer_head *_free_buffers; + +static int init_buffers(void) +{ + int i; + struct buffer_head *buffers; + + buffers = vcalloc(NUM_BUFFERS, sizeof(struct buffer_head)); + if (!buffers) { + DMWARN("Couldn't allocate buffer heads."); + return -ENOMEM; + } + + for (i = 0; i < NUM_BUFFERS; i++) { + if (i < NUM_BUFFERS - 1) + buffers[i].b_reqnext = &buffers[i + 1]; + init_waitqueue_head(&buffers[i].b_wait); + INIT_LIST_HEAD(&buffers[i].b_inode_buffers); + } + + _all_buffers = _free_buffers = buffers; + return 0; +} + +static void exit_buffers(void) +{ + vfree(_all_buffers); +} + +static struct buffer_head *alloc_buffer(void) +{ + struct buffer_head *r; + int flags; + + spin_lock_irqsave(&_buffer_lock, flags); + + if (!_free_buffers) + r = NULL; + else { + r = _free_buffers; + _free_buffers = _free_buffers->b_reqnext; + r->b_reqnext = NULL; + } + + spin_unlock_irqrestore(&_buffer_lock, flags); + + return r; +} + +/* + * Only called from interrupt context. + */ +static void free_buffer(struct buffer_head *bh) +{ + int flags, was_empty; + + spin_lock_irqsave(&_buffer_lock, flags); + was_empty = (_free_buffers == NULL) ? 1 : 0; + bh->b_reqnext = _free_buffers; + _free_buffers = bh; + spin_unlock_irqrestore(&_buffer_lock, flags); + + /* + * If the buffer list was empty then kcopyd probably went + * to sleep because it ran out of buffer heads, so let's + * wake it up. + */ + if (was_empty) + wake_kcopyd(); +} + +/*----------------------------------------------------------------- + * kcopyd_jobs need to be allocated by the *clients* of kcopyd, + * for this reason we use a mempool to prevent the client from + * ever having to do io (which could cause a + * deadlock). + *---------------------------------------------------------------*/ +#define MIN_JOBS NUM_PAGES + +static kmem_cache_t *_job_cache = NULL; +static mempool_t *_job_pool = NULL; + +/* + * We maintain three lists of jobs: + * + * i) jobs waiting for pages + * ii) jobs that have pages, and are waiting for the io to be issued. + * iii) jobs that have completed. + * + * All three of these are protected by job_lock. + */ + +static spinlock_t _job_lock = SPIN_LOCK_UNLOCKED; + +static LIST_HEAD(_complete_jobs); +static LIST_HEAD(_io_jobs); +static LIST_HEAD(_pages_jobs); + +static int init_jobs(void) +{ + INIT_LIST_HEAD(&_complete_jobs); + INIT_LIST_HEAD(&_io_jobs); + INIT_LIST_HEAD(&_pages_jobs); + + _job_cache = kmem_cache_create("kcopyd-jobs", sizeof(struct kcopyd_job), + __alignof__(struct kcopyd_job), + 0, NULL, NULL); + if (!_job_cache) + return -ENOMEM; + + _job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab, + mempool_free_slab, _job_cache); + if (!_job_pool) { + kmem_cache_destroy(_job_cache); + return -ENOMEM; + } + + return 0; +} + +static void exit_jobs(void) +{ + mempool_destroy(_job_pool); + kmem_cache_destroy(_job_cache); +} + +struct kcopyd_job *kcopyd_alloc_job(void) +{ + struct kcopyd_job *job; + + job = mempool_alloc(_job_pool, GFP_KERNEL); + if (!job) + return NULL; + + memset(job, 0, sizeof(*job)); + return job; +} + +void kcopyd_free_job(struct kcopyd_job *job) +{ + mempool_free(job, _job_pool); +} + +/* + * Functions to push and pop a job onto the head of a given job + * list. + */ +static inline struct kcopyd_job *pop(struct list_head *jobs) +{ + struct kcopyd_job *job = NULL; + int flags; + + spin_lock_irqsave(&_job_lock, flags); + + if (!list_empty(jobs)) { + job = list_entry(jobs->next, struct kcopyd_job, list); + list_del(&job->list); + } + spin_unlock_irqrestore(&_job_lock, flags); + + return job; +} + +static inline void push(struct list_head *jobs, struct kcopyd_job *job) +{ + int flags; + + spin_lock_irqsave(&_job_lock, flags); + list_add(&job->list, jobs); + spin_unlock_irqrestore(&_job_lock, flags); +} + +/* + * Completion function for one of our buffers. + */ +static void end_bh(struct buffer_head *bh, int uptodate) +{ + struct kcopyd_job *job = bh->b_private; + + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); + + if (!uptodate) + job->err = -EIO; + + /* are we the last ? */ + if (atomic_dec_and_test(&job->nr_incomplete)) { + push(&_complete_jobs, job); + wake_kcopyd(); + } + + free_buffer(bh); +} + +static void dispatch_bh(struct kcopyd_job *job, + struct buffer_head *bh, int block) +{ + int p; + + /* + * Add in the job offset + */ + bh->b_blocknr = (job->disk.sector >> job->block_shift) + block; + + p = block >> job->bpp_shift; + block &= job->bpp_mask; + + bh->b_dev = B_FREE; + bh->b_size = job->block_size; + set_bh_page(bh, job->pages[p], ((block << job->block_shift) + + job->offset) << SECTOR_SHIFT); + bh->b_this_page = bh; + + init_buffer(bh, end_bh, job); + + bh->b_dev = job->disk.dev; + bh->b_state = ((1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req)); + + set_bit(BH_Uptodate, &bh->b_state); + if (job->rw == WRITE) + clear_bit(BH_Dirty, &bh->b_state); + + submit_bh(job->rw, bh); +} + +/* + * These three functions process 1 item from the corresponding + * job list. + * + * They return: + * < 0: error + * 0: success + * > 0: can't process yet. + */ +static int run_complete_job(struct kcopyd_job *job) +{ + job->callback(job); + return 0; +} + +/* + * Request io on as many buffer heads as we can currently get for + * a particular job. + */ +static int run_io_job(struct kcopyd_job *job) +{ + unsigned int block; + struct buffer_head *bh; + + for (block = atomic_read(&job->nr_requested); + block < job->nr_blocks; block++) { + bh = alloc_buffer(); + if (!bh) + break; + + atomic_inc(&job->nr_requested); + dispatch_bh(job, bh, block); + } + + return (block == job->nr_blocks) ? 0 : 1; +} + +static int run_pages_job(struct kcopyd_job *job) +{ + int r; + + job->nr_pages = (job->disk.count + job->offset) / + (PAGE_SIZE / SECTOR_SIZE); + r = kcopyd_get_pages(job->nr_pages, job->pages); + + if (!r) { + /* this job is ready for io */ + push(&_io_jobs, job); + return 0; + } + + if (r == -ENOMEM) + /* can complete now */ + return 1; + + return r; +} + +/* + * Run through a list for as long as possible. Returns the count + * of successful jobs. + */ +static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *)) +{ + struct kcopyd_job *job; + int r, count = 0; + + while ((job = pop(jobs))) { + + r = fn(job); + + if (r < 0) { + /* error this rogue job */ + job->err = r; + push(&_complete_jobs, job); + break; + } + + if (r > 0) { + /* + * We couldn't service this job ATM, so + * push this job back onto the list. + */ + push(jobs, job); + break; + } + + count++; + } + + return count; +} + +/* + * kcopyd does this every time it's woken up. + */ +static void do_work(void) +{ + int count; + + /* + * We loop round until there is no more work to do. + */ + do { + count = process_jobs(&_complete_jobs, run_complete_job); + count += process_jobs(&_io_jobs, run_io_job); + count += process_jobs(&_pages_jobs, run_pages_job); + + } while (count); + + run_task_queue(&tq_disk); +} + +/*----------------------------------------------------------------- + * The daemon + *---------------------------------------------------------------*/ +static atomic_t _kcopyd_must_die; +static DECLARE_MUTEX(_run_lock); +static DECLARE_WAIT_QUEUE_HEAD(_job_queue); + +static int kcopyd(void *arg) +{ + DECLARE_WAITQUEUE(wq, current); + + daemonize(); + strcpy(current->comm, "kcopyd"); + atomic_set(&_kcopyd_must_die, 0); + + add_wait_queue(&_job_queue, &wq); + + down(&_run_lock); + up(&start_lock); + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + + if (atomic_read(&_kcopyd_must_die)) + break; + + do_work(); + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&_job_queue, &wq); + + up(&_run_lock); + + return 0; +} + +static int start_daemon(void) +{ + static pid_t pid = 0; + + down(&start_lock); + + pid = kernel_thread(kcopyd, NULL, 0); + if (pid <= 0) { + DMERR("Failed to start kcopyd thread"); + return -EAGAIN; + } + + /* + * wait for the daemon to up this mutex. + */ + down(&start_lock); + up(&start_lock); + + return 0; +} + +static int stop_daemon(void) +{ + atomic_set(&_kcopyd_must_die, 1); + wake_kcopyd(); + down(&_run_lock); + up(&_run_lock); + + return 0; +} + +static void wake_kcopyd(void) +{ + wake_up_interruptible(&_job_queue); +} + +static int calc_shift(unsigned int n) +{ + int s; + + for (s = 0; n; s++, n >>= 1) + ; + + return --s; +} + +static void calc_block_sizes(struct kcopyd_job *job) +{ + job->block_size = get_hardsect_size(job->disk.dev); + job->block_shift = calc_shift(job->block_size / SECTOR_SIZE); + job->bpp_shift = PAGE_SHIFT - job->block_shift - SECTOR_SHIFT; + job->bpp_mask = (1 << job->bpp_shift) - 1; + job->nr_blocks = job->disk.count >> job->block_shift; + atomic_set(&job->nr_requested, 0); + atomic_set(&job->nr_incomplete, job->nr_blocks); +} + +int kcopyd_io(struct kcopyd_job *job) +{ + calc_block_sizes(job); + push(job->pages[0] ? &_io_jobs : &_pages_jobs, job); + wake_kcopyd(); + return 0; +} + +/*----------------------------------------------------------------- + * The copier is implemented on top of the simpler async io + * daemon above. + *---------------------------------------------------------------*/ +struct copy_info { + kcopyd_notify_fn notify; + void *notify_context; + + struct kcopyd_region to; +}; + +#define MIN_INFOS 128 +static kmem_cache_t *_copy_cache = NULL; +static mempool_t *_copy_pool = NULL; + +static int init_copier(void) +{ + _copy_cache = kmem_cache_create("kcopyd-info", + sizeof(struct copy_info), + __alignof__(struct copy_info), + 0, NULL, NULL); + if (!_copy_cache) + return -ENOMEM; + + _copy_pool = mempool_create(MIN_INFOS, mempool_alloc_slab, + mempool_free_slab, _copy_cache); + if (!_copy_pool) { + kmem_cache_destroy(_copy_cache); + return -ENOMEM; + } + + return 0; +} + +static void exit_copier(void) +{ + if (_copy_pool) + mempool_destroy(_copy_pool); + + if (_copy_cache) + kmem_cache_destroy(_copy_cache); +} + +static inline struct copy_info *alloc_copy_info(void) +{ + return mempool_alloc(_copy_pool, GFP_KERNEL); +} + +static inline void free_copy_info(struct copy_info *info) +{ + mempool_free(info, _copy_pool); +} + +void copy_complete(struct kcopyd_job *job) +{ + struct copy_info *info = (struct copy_info *) job->context; + + if (info->notify) + info->notify(job->err, info->notify_context); + + free_copy_info(info); + + kcopyd_free_pages(job->nr_pages, job->pages); + + kcopyd_free_job(job); +} + +static void page_write_complete(struct kcopyd_job *job) +{ + struct copy_info *info = (struct copy_info *) job->context; + int i; + + if (info->notify) + info->notify(job->err, info->notify_context); + + free_copy_info(info); + for (i = 0; i < job->nr_pages; i++) + put_page(job->pages[i]); + + kcopyd_free_job(job); +} + +/* + * These callback functions implement the state machine that copies regions. + */ +void copy_write(struct kcopyd_job *job) +{ + struct copy_info *info = (struct copy_info *) job->context; + + if (job->err && info->notify) { + info->notify(job->err, job->context); + kcopyd_free_job(job); + free_copy_info(info); + return; + } + + job->rw = WRITE; + memcpy(&job->disk, &info->to, sizeof(job->disk)); + job->callback = copy_complete; + job->context = info; + + /* + * Queue the write. + */ + kcopyd_io(job); +} + +int kcopyd_write_pages(struct kcopyd_region *to, int nr_pages, + struct page **pages, int offset, kcopyd_notify_fn fn, + void *context) +{ + struct copy_info *info; + struct kcopyd_job *job; + int i; + + /* + * Allocate a new copy_info. + */ + info = alloc_copy_info(); + if (!info) + return -ENOMEM; + + job = kcopyd_alloc_job(); + if (!job) { + free_copy_info(info); + return -ENOMEM; + } + + /* + * set up for the write. + */ + info->notify = fn; + info->notify_context = context; + memcpy(&info->to, to, sizeof(*to)); + + /* Get the pages */ + job->nr_pages = nr_pages; + for (i = 0; i < nr_pages; i++) { + get_page(pages[i]); + job->pages[i] = pages[i]; + } + + job->rw = WRITE; + + memcpy(&job->disk, &info->to, sizeof(job->disk)); + job->offset = offset; + calc_block_sizes(job); + job->callback = page_write_complete; + job->context = info; + + /* + * Trigger job. + */ + kcopyd_io(job); + return 0; +} + +int kcopyd_copy(struct kcopyd_region *from, struct kcopyd_region *to, + kcopyd_notify_fn fn, void *context) +{ + struct copy_info *info; + struct kcopyd_job *job; + + /* + * Allocate a new copy_info. + */ + info = alloc_copy_info(); + if (!info) + return -ENOMEM; + + job = kcopyd_alloc_job(); + if (!job) { + free_copy_info(info); + return -ENOMEM; + } + + /* + * set up for the read. + */ + info->notify = fn; + info->notify_context = context; + memcpy(&info->to, to, sizeof(*to)); + + job->rw = READ; + memcpy(&job->disk, from, sizeof(*from)); + + job->offset = 0; + calc_block_sizes(job); + job->callback = copy_write; + job->context = info; + + /* + * Trigger job. + */ + kcopyd_io(job); + return 0; +} + +/*----------------------------------------------------------------- + * Unit setup + *---------------------------------------------------------------*/ +static struct { + int (*init) (void); + void (*exit) (void); + +} _inits[] = { +#define xx(n) { init_ ## n, exit_ ## n} + xx(pages), + xx(buffers), + xx(jobs), + xx(copier) +#undef xx +}; + +static int _client_count = 0; +static DECLARE_MUTEX(_client_count_sem); + +static int kcopyd_init(void) +{ + const int count = sizeof(_inits) / sizeof(*_inits); + + int r, i; + + for (i = 0; i < count; i++) { + r = _inits[i].init(); + if (r) + goto bad; + } + + start_daemon(); + return 0; + + bad: + while (i--) + _inits[i].exit(); + + return r; +} + +static void kcopyd_exit(void) +{ + int i = sizeof(_inits) / sizeof(*_inits); + + if (stop_daemon()) + DMWARN("Couldn't stop kcopyd."); + + while (i--) + _inits[i].exit(); +} + +void kcopyd_inc_client_count(void) +{ + /* + * What I need here is an atomic_test_and_inc that returns + * the previous value of the atomic... In its absence I lock + * an int with a semaphore. :-( + */ + down(&_client_count_sem); + if (_client_count == 0) + kcopyd_init(); + _client_count++; + + up(&_client_count_sem); +} + +void kcopyd_dec_client_count(void) +{ + down(&_client_count_sem); + if (--_client_count == 0) + kcopyd_exit(); + + up(&_client_count_sem); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/kcopyd.h linux.20pre2-ac1/drivers/md/kcopyd.h --- linux.20pre2/drivers/md/kcopyd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/kcopyd.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * This file is released under the GPL. + */ + +#ifndef DM_KCOPYD_H +#define DM_KCOPYD_H + +/* + * Needed for the definition of offset_t. + */ +#include +#include + +struct kcopyd_region { + kdev_t dev; + offset_t sector; + offset_t count; +}; + +#define MAX_KCOPYD_PAGES 128 + +struct kcopyd_job { + struct list_head list; + + /* + * Error state of the job. + */ + int err; + + /* + * Either READ or WRITE + */ + int rw; + + /* + * The source or destination for the transfer. + */ + struct kcopyd_region disk; + + int nr_pages; + struct page *pages[MAX_KCOPYD_PAGES]; + + /* + * Shifts and masks that will be useful when dispatching + * each buffer_head. + */ + offset_t offset; + offset_t block_size; + offset_t block_shift; + offset_t bpp_shift; /* blocks per page */ + offset_t bpp_mask; + + /* + * nr_blocks is how many buffer heads will have to be + * displatched to service this job, nr_requested is how + * many have been dispatched and nr_complete is how many + * have come back. + */ + unsigned int nr_blocks; + atomic_t nr_requested; + atomic_t nr_incomplete; + + /* + * Set this to ensure you are notified when the job has + * completed. 'context' is for callback to use. + */ + void (*callback)(struct kcopyd_job *job); + void *context; +}; + +/* + * Low level async io routines. + */ +struct kcopyd_job *kcopyd_alloc_job(void); +void kcopyd_free_job(struct kcopyd_job *job); + +int kcopyd_queue_job(struct kcopyd_job *job); + +/* + * Submit a copy job to kcopyd. This is built on top of the + * previous three fns. + */ +typedef void (*kcopyd_notify_fn)(int err, void *context); + +int kcopyd_copy(struct kcopyd_region *from, struct kcopyd_region *to, + kcopyd_notify_fn fn, void *context); + +int kcopyd_write_pages(struct kcopyd_region *to, int nr_pages, + struct page **pages, int offset, kcopyd_notify_fn fn, + void *context); + +/* + * We only want kcopyd to reserve resources if someone is + * actually using it. + */ +void kcopyd_inc_client_count(void); +void kcopyd_dec_client_count(void); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/lvm-snap.c linux.20pre2-ac1/drivers/md/lvm-snap.c --- linux.20pre2/drivers/md/lvm-snap.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/lvm-snap.c 2002-08-12 13:10:59.000000000 +0100 @@ -130,7 +130,8 @@ list_move(next, hash_table); #else list_del(next); -#endif list_add(next, hash_table); + list_add(next, hash_table); +#endif } ret = exception; break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/Makefile linux.20pre2-ac1/drivers/md/Makefile --- linux.20pre2/drivers/md/Makefile 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/Makefile 2002-08-12 22:44:36.000000000 +0100 @@ -4,9 +4,11 @@ O_TARGET := mddev.o -export-objs := md.o xor.o +export-objs := md.o xor.o dm-table.o dm-target.o kcopyd.o list-multi := lvm-mod.o lvm-mod-objs := lvm.o lvm-snap.o lvm-fs.o +dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ + dm-ioctl.o dm-snapshot.o dm-exception-store.o kcopyd.o # Note: link order is important. All raid personalities # and xor.o must come before md.o, as they each initialise @@ -20,8 +22,12 @@ obj-$(CONFIG_MD_MULTIPATH) += multipath.o obj-$(CONFIG_BLK_DEV_MD) += md.o obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o +obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o include $(TOPDIR)/Rules.make lvm-mod.o: $(lvm-mod-objs) $(LD) -r -o $@ $(lvm-mod-objs) + +dm-mod.o: $(dm-mod-objs) + $(LD) -r -o $@ $(dm-mod-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/md/md.c linux.20pre2-ac1/drivers/md/md.c --- linux.20pre2/drivers/md/md.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/md/md.c 2002-08-06 15:42:18.000000000 +0100 @@ -724,9 +724,9 @@ * Make sure nobody else is using this mddev * (careful, we rely on the global kernel lock here) */ - while (md_atomic_read(&mddev->resync_sem.count) != 1) + while (sem_getcount(&mddev->resync_sem) != 1) schedule(); - while (md_atomic_read(&mddev->recovery_sem.count) != 1) + while (sem_getcount(&mddev->recovery_sem) != 1) schedule(); del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); @@ -2936,8 +2936,6 @@ * bdflush, otherwise bdflush will deadlock if there are too * many dirty RAID5 blocks. */ - current->policy = SCHED_OTHER; - current->nice = -20; md_unlock_kernel(); complete(thread->event); @@ -3219,7 +3217,7 @@ if (mddev->curr_resync) { sz += status_resync (page+sz, mddev); } else { - if (md_atomic_read(&mddev->resync_sem.count) != 1) + if (sem_getcount(&mddev->resync_sem) != 1) sz += sprintf(page + sz, " resync=DELAYED"); } sz += sprintf(page + sz, "\n"); @@ -3391,11 +3389,6 @@ "(but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max); - /* - * Resync has low priority. - */ - current->nice = 19; - is_mddev_idle(mddev); /* this also initializes IO event counters */ for (m = 0; m < SYNC_MARKS; m++) { mark[m] = jiffies; @@ -3473,16 +3466,13 @@ currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1; if (currspeed > sysctl_speed_limit_min) { - current->nice = 19; - if ((currspeed > sysctl_speed_limit_max) || !is_mddev_idle(mddev)) { current->state = TASK_INTERRUPTIBLE; md_schedule_timeout(HZ/4); goto repeat; } - } else - current->nice = -20; + } } printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); err = 0; @@ -3712,7 +3702,7 @@ * Searches all registered partitions for autorun RAID arrays * at boot time. */ -static int detected_devices[128]; +static kdev_t detected_devices[128]; static int dev_cnt; void md_autodetect_dev(kdev_t dev) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/Config.in linux.20pre2-ac1/drivers/media/video/Config.in --- linux.20pre2/drivers/media/video/Config.in 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/Config.in 2002-08-06 15:42:12.000000000 +0100 @@ -11,6 +11,8 @@ if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT fi +dep_tristate ' Luxsonor LS220 (EXPERIMENTAL)' CONFIG_VIDEO_LS220 $CONFIG_VIDEO_DEV +dep_tristate ' Margi DVD-to-Go (EXPERIMENTAL)' CONFIG_VIDEO_MARGI $CONFIG_PCMCIA $CONFIG_VIDEO_DEV dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV if [ "$CONFIG_ALL_PPC" = "y" ]; then dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/cpia.c linux.20pre2-ac1/drivers/media/video/cpia.c --- linux.20pre2/drivers/media/video/cpia.c 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/cpia.c 2002-08-06 15:42:12.000000000 +0100 @@ -56,7 +56,7 @@ #ifdef MODULE MODULE_PARM(video_nr,"i"); -MODULE_AUTHOR("Scott J. Bertin & Peter Pregler & Johannes Erdfelt "); +MODULE_AUTHOR("Scott J. Bertin & Peter Pregler & Johannes Erdfelt "); MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("video"); @@ -163,6 +163,7 @@ #define COMMAND_SETAPCOR 0x1000 #define COMMAND_SETFLICKERCTRL 0x2000 #define COMMAND_SETVLOFFSET 0x4000 +#define COMMAND_SETLIGHTS 0x8000 /* Developer's Guide Table 5 p 3-34 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ @@ -178,50 +179,17 @@ * * Memory management * - * This is a shameless copy from the USB-cpia driver (linux kernel - * version 2.3.29 or so, I have no idea what this code actually does ;). - * Actually it seems to be a copy of a shameless copy of the bttv-driver. - * Or that is a copy of a shameless copy of ... (To the powers: is there - * no generic kernel-function to do this sort of stuff?) - * - * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says - * there will be one, but apparentely not yet - jerdfelt - * **********************************************************************/ -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE-1)); - } - } - } - return ret; -} - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -229,12 +197,9 @@ static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -242,13 +207,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -256,23 +217,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } @@ -291,7 +245,7 @@ char *out = page; int len, tmp; struct cam_data *cam = data; - char tmpstr[20]; + char tmpstr[29]; /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ @@ -328,6 +282,13 @@ cam->params.status.vpStatus); out += sprintf(out, "error_code: %#04x\n", cam->params.status.errorCode); + /* QX3 specific entries */ + if (cam->params.qx3.qx3_detected) { + out += sprintf(out, "button: %4d\n", + cam->params.qx3.button); + out += sprintf(out, "cradled: %4d\n", + cam->params.qx3.cradled); + } out += sprintf(out, "video_size: %s\n", cam->params.format.videoSize == VIDEOSIZE_CIF ? "CIF " : "QCIF"); @@ -392,16 +353,17 @@ if (cam->params.version.firmwareVersion == 1 && cam->params.version.firmwareRevision == 2) /* 1-02 firmware limits gain to 2 */ - sprintf(tmpstr, "%8d %8d", 1, 2); + sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2); else - sprintf(tmpstr, "1,2,4,8"); + sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2); if (cam->params.exposure.gainMode == 0) - out += sprintf(out, "max_gain: unknown %18s" - " %8d\n", tmpstr, 2); + out += sprintf(out, "max_gain: unknown %28s" + " powers of 2\n", tmpstr); else - out += sprintf(out, "max_gain: %8d %18s %8d\n", - 1<<(cam->params.exposure.gainMode-1), tmpstr, 2); + out += sprintf(out, "max_gain: %8d %28s" + " 1,2,4 or 8 \n", + 1<<(cam->params.exposure.gainMode-1), tmpstr); switch(cam->params.exposure.expMode) { case 1: @@ -528,6 +490,15 @@ out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n", cam->params.compressionParams.decimationThreshMod, 0, 255, 2); + /* QX3 specific entries */ + if (cam->params.qx3.qx3_detected) { + out += sprintf(out, "toplight: %8s %8s %8s %8s\n", + cam->params.qx3.toplight ? "on" : "off", + "off", "on", "off"); + out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n", + cam->params.qx3.bottomlight ? "on" : "off", + "off", "on", "off"); + } len = out - page; len -= off; @@ -541,18 +512,45 @@ return len; } -static int cpia_write_proc(struct file *file, const char *buffer, +static int cpia_write_proc(struct file *file, const char *buf, unsigned long count, void *data) { - return -EINVAL; -#if 0 struct cam_data *cam = data; struct cam_params new_params; + char *page, *buffer; int retval, find_colon; int size = count; - unsigned long val; + unsigned long val = 0; u32 command_flags = 0; u8 new_mains; + + /* + * This code to copy from buf to page is shamelessly copied + * from the comx driver + */ + if (count > PAGE_SIZE) { + printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE); + return -ENOSPC; + } + + if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; + + if(copy_from_user(page, buf, count)) + { + retval = -EFAULT; + goto out; + } + + if (page[count-1] == '\n') + page[count-1] = '\0'; + else if (count < PAGE_SIZE) + page[count] = '\0'; + else if (page[count]) { + retval = -EINVAL; + goto out; + } + + buffer = page; if (down_interruptible(&cam->param_lock)) return -ERESTARTSYS; @@ -1210,6 +1208,22 @@ retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("toplight")) { + if (!retval && MATCH("on")) + new_params.qx3.toplight = 1; + else if (!retval && MATCH("off")) + new_params.qx3.toplight = 0; + else + retval = -EINVAL; + command_flags |= COMMAND_SETLIGHTS; + } else if (MATCH("bottomlight")) { + if (!retval && MATCH("on")) + new_params.qx3.bottomlight = 1; + else if (!retval && MATCH("off")) + new_params.qx3.bottomlight = 0; + else + retval = -EINVAL; + command_flags |= COMMAND_SETLIGHTS; } else { DBG("No match found\n"); retval = -EINVAL; @@ -1221,7 +1235,10 @@ ++buffer; } if (count) { - if (*buffer != '\n' && *buffer != ';') + if (*buffer == '\0' && count != 1) + retval = -EINVAL; + else if (*buffer != '\n' && *buffer != ';' && + *buffer != '\0') retval = -EINVAL; else { --count; @@ -1255,8 +1272,9 @@ up(&cam->param_lock); +out: + free_page((unsigned long)page); return retval; -#endif } static void create_proc_cpia_cam(struct cam_data *cam) @@ -1276,7 +1294,12 @@ ent->data = cam; ent->read_proc = cpia_read_proc; ent->write_proc = cpia_write_proc; - ent->size = 3626; + /* + size of the proc entry is 3672 bytes for the standard webcam; + the extra features of the QX3 microscope add 188 bytes. + (we have not yet probed the camera to see which type it is). + */ + ent->size = 3672 + 188; cam->proc_entry = ent; } @@ -1570,6 +1593,10 @@ down(&cam->param_lock); datasize=8; break; + case CPIA_COMMAND_ReadMCPorts: + case CPIA_COMMAND_ReadVCRegs: + datasize = 4; + break; default: datasize=0; break; @@ -1667,6 +1694,22 @@ } up(&cam->param_lock); break; + + case CPIA_COMMAND_ReadMCPorts: + if (!cam->params.qx3.qx3_detected) + break; + /* test button press */ + cam->params.qx3.button = ((data[1] & 0x02) == 0); + if (cam->params.qx3.button) { + /* button pressed - unlock the latch */ + do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0); + do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0); + } + + /* test whether microscope is cradled */ + cam->params.qx3.cradled = ((data[2] & 0x40) == 0); + break; + default: break; } @@ -1826,6 +1869,7 @@ { switch(fmt) { case VIDEO_PALETTE_GREY: + return count; case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_YUV422: @@ -2106,6 +2150,13 @@ if (cam->cmd_queue & COMMAND_RESUME) init_stream_cap(cam); + if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) { + int p1 = (cam->params.qx3.bottomlight == 0) << 1; + int p2 = (cam->params.qx3.toplight == 0) << 3; + do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0); + do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0); + } + up(&cam->param_lock); cam->cmd_queue = COMMAND_NONE; return; @@ -2182,9 +2233,10 @@ /* camera idle now so dispatch queued commands */ dispatch_commands(cam); - /* Update our knowledge of the camera state - FIXME: necessary? */ + /* Update our knowledge of the camera state */ do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); + do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); /* decompress and convert image to by copying it from * raw_image to decompressed_frame @@ -2396,7 +2448,11 @@ get_version_information(cam); if (cam->params.version.firmwareVersion != 1) return -ENODEV; - + + /* set QX3 detected flag */ + cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 && + cam->params.pnpID.product == 0x0001); + /* The fatal error checking should be done after * the camera powers up (developer's guide p 3-38) */ @@ -2526,7 +2582,7 @@ /* GotoLoPower */ goto_low_power(cam); - /* Update the camera ststus */ + /* Update the camera status */ do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); /* cleanup internal state stuff */ @@ -2566,7 +2622,7 @@ { struct cam_data *cam = dev->priv; - /* make this _really_ smp and multithredi-safe */ + /* make this _really_ smp and multithread-safe */ if (down_interruptible(&cam->busy_lock)) return -EINTR; @@ -2793,7 +2849,6 @@ cam->cmd_queue |= COMMAND_SETFORMAT; } - // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw)); up(&cam->param_lock); /* setformat ignored by camera during streaming, @@ -2835,10 +2890,8 @@ retval = -EFAULT; break; } -#if 1 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame, vm.width, vm.height); -#endif if (vm.frame<0||vm.frame>=FRAME_NUM) { retval = -EINVAL; break; @@ -2848,6 +2901,8 @@ cam->vp.palette = vm.format; switch(vm.format) { case VIDEO_PALETTE_GREY: + cam->vp.depth=8; + break; case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_YUV422: @@ -2880,10 +2935,6 @@ cam->cmd_queue |= COMMAND_SETFORMAT; dispatch_commands(cam); } -#if 0 - DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size, - cam->vw.width, cam->vw.height); -#endif /* according to v4l-spec we must start streaming here */ cam->mmap_kludge = 1; retval = capture_frame(cam, &vm); @@ -3035,7 +3086,7 @@ owner: THIS_MODULE, name: "CPiA Camera", type: VID_TYPE_CAPTURE, - hardware: VID_HARDWARE_CPIA, /* FIXME */ + hardware: VID_HARDWARE_CPIA, open: cpia_open, close: cpia_close, read: cpia_read, @@ -3100,8 +3151,8 @@ cam->params.sensorFps.divisor = 1; cam->params.sensorFps.baserate = 1; - cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */ - cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */ + cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */ + cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */ cam->params.format.subSample = SUBSAMPLE_422; cam->params.format.yuvOrder = YUVORDER_YUYV; @@ -3109,8 +3160,14 @@ cam->params.compression.mode = CPIA_COMPRESSION_AUTO; cam->params.compressionTarget.frTargeting = CPIA_COMPRESSION_TARGET_QUALITY; - cam->params.compressionTarget.targetFR = 7; /* FIXME? */ - cam->params.compressionTarget.targetQ = 10; /* FIXME? */ + cam->params.compressionTarget.targetFR = 15; /* From windows driver */ + cam->params.compressionTarget.targetQ = 5; /* From windows driver */ + + cam->params.qx3.qx3_detected = 0; + cam->params.qx3.toplight = 0; + cam->params.qx3.bottomlight = 0; + cam->params.qx3.button = 0; + cam->params.qx3.cradled = 0; cam->video_size = VIDEOSIZE_CIF; @@ -3119,8 +3176,8 @@ cam->vp.brightness = 32768; /* 50% */ cam->vp.contrast = 32768; /* 50% */ cam->vp.whiteness = 0; /* not used -> grayscale only */ - cam->vp.depth = 0; /* FIXME: to be set by user? */ - cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */ + cam->vp.depth = 24; /* to be set by user */ + cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */ cam->vw.x = 0; cam->vw.y = 0; @@ -3209,12 +3266,6 @@ /* close cpia */ camera->ops->close(camera->lowlevel_data); -/* Eh? Feeling happy? - jerdfelt */ -/* - camera->ops->open(camera->lowlevel_data); - camera->ops->close(camera->lowlevel_data); -*/ - printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n", camera->params.version.firmwareVersion, camera->params.version.firmwareRevision, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/cpia.h linux.20pre2-ac1/drivers/media/video/cpia.h --- linux.20pre2/drivers/media/video/cpia.h 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/cpia.h 2002-08-14 14:41:30.000000000 +0100 @@ -27,12 +27,12 @@ */ #define CPIA_MAJ_VER 0 -#define CPIA_MIN_VER 7 -#define CPIA_PATCH_VER 4 +#define CPIA_MIN_VER 8 +#define CPIA_PATCH_VER 1 #define CPIA_PP_MAJ_VER 0 -#define CPIA_PP_MIN_VER 7 -#define CPIA_PP_PATCH_VER 4 +#define CPIA_PP_MIN_VER 8 +#define CPIA_PP_PATCH_VER 1 #define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */ #define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */ @@ -204,6 +204,13 @@ u8 subSample; u8 yuvOrder; } format; + struct { /* Intel QX3 specific data */ + u8 qx3_detected; /* a QX3 is present */ + u8 toplight; /* top light lit , R/W */ + u8 bottomlight; /* bottom light lit, R/W */ + u8 button; /* snapshot button pressed (R/O) */ + u8 cradled; /* microscope is in cradle (R/O) */ + } qx3; struct { u8 colStart; /* skip first 8*colStart pixels */ u8 colEnd; /* finish at 8*colEnd pixels */ @@ -393,29 +400,6 @@ (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\ (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0); -#define ADD_TO_LIST(l, drv) \ - {\ - lock_kernel();\ - (drv)->next = l;\ - (drv)->previous = &(l);\ - (l) = drv;\ - unlock_kernel();\ - } while(0) - -#define REMOVE_FROM_LIST(drv) \ - {\ - if ((drv)->previous != NULL) {\ - lock_kernel();\ - if ((drv)->next != NULL)\ - (drv)->next->previous = (drv)->previous;\ - *((drv)->previous) = (drv)->next;\ - (drv)->previous = NULL;\ - (drv)->next = NULL;\ - unlock_kernel();\ - }\ - } while (0) - - static inline void cpia_add_to_list(struct cam_data* l, struct cam_data* drv) { drv->next = l; @@ -423,7 +407,6 @@ l = drv; } - static inline void cpia_remove_from_list(struct cam_data* drv) { if (drv->previous != NULL) { @@ -435,7 +418,6 @@ } } - #endif /* __KERNEL__ */ #endif /* cpia_h */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/cpia_pp.c linux.20pre2-ac1/drivers/media/video/cpia_pp.c --- linux.20pre2/drivers/media/video/cpia_pp.c 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/cpia_pp.c 2002-08-06 15:42:12.000000000 +0100 @@ -4,7 +4,7 @@ * Supports CPiA based parallel port Video Camera's. * * (C) Copyright 1999 Bas Huisman - * (C) Copyright 1999-2000 Scott J. Bertin , + * (C) Copyright 1999-2000 Scott J. Bertin , * (C) Copyright 1999-2000 Peter Pregler * * This program is free software; you can redistribute it and/or modify @@ -340,17 +340,6 @@ return 0; } -static int cpia_pp_read(struct parport *port, u8 *buffer, int len) -{ - int bytes_read, new_bytes; - for(bytes_read=0; bytes_readport, buffer, CPIA_MAX_IMAGE_SIZE ); + + EndTransferMode(cam); + DBG("read %d bytes\n", read_bytes); + if( read_bytes<0) return -EIO; endseen = 0; - block_size = PARPORT_CHUNK_SIZE; - while( !cam->image_complete ) { - if(current->need_resched) schedule(); - - new_bytes = cpia_pp_read(cam->port, buffer, block_size ); - if( new_bytes <= 0 ) { - break; - } - i=-1; - while(++iimage_complete=1; - break; - } - if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) { - block_size=CPIA_MAX_IMAGE_SIZE-read_bytes; - } + endseen = 0; + for( i=0; i3 ) { + cam->image_complete=1; + DBG("endseen at %d bytes\n", i); } - EndTransferMode(cam); return cam->image_complete ? read_bytes : -EIO; } @@ -716,15 +696,6 @@ static int __init cpia_pp_setup(char *str) { -#if 0 - /* Is this only a 2.2ism? -jerdfelt */ - if (!str) { - if (ints[0] == 0 || ints[1] == 0) { - /* disable driver on "cpia_pp=" or "cpia_pp=0" */ - parport_nr[0] = PPCPIA_PARPORT_OFF; - } - } else -#endif if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str + 7, NULL, 10); if (parport_ptr < PARPORT_MAX) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/cpia_usb.c linux.20pre2-ac1/drivers/media/video/cpia_usb.c --- linux.20pre2/drivers/media/video/cpia_usb.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/cpia_usb.c 2002-08-13 14:25:49.000000000 +0100 @@ -266,14 +266,16 @@ error_urb1: /* free urb 1 */ usb_free_urb(ucpia->sbuf[1].urb); - + ucpia->sbuf[1].urb = NULL; error_urb0: /* free urb 0 */ usb_free_urb(ucpia->sbuf[0].urb); - + ucpia->sbuf[0].urb = NULL; error_1: kfree (ucpia->sbuf[1].data); + ucpia->sbuf[1].data = NULL; error_0: kfree (ucpia->sbuf[0].data); + ucpia->sbuf[0].data = NULL; return retval; } @@ -620,8 +622,10 @@ ucpia->buffers[0] = NULL; } - if (!ucpia->open) + if (!ucpia->open) { kfree(ucpia); + cam->lowlevel_data = NULL; + } } static int __init usb_cpia_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/ac3_240.h linux.20pre2-ac1/drivers/media/video/ls220/ac3_240.h --- linux.20pre2/drivers/media/video/ls220/ac3_240.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/ac3_240.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,2835 @@ +static u32 AC3240Ucode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb500118f, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x80070800, 0x001f6193, + 0x800500d4, 0x8053ffff, 0x9842c7ff, 0x8039ff7c, + 0x1400b802, 0x003f6000, 0x94210007, 0xb0010001, + 0xb4200001, 0x98002800, 0xb0010000, 0xb4200001, + 0x98000800, 0x805300ff, 0x1800b802, 0x800600d4, + 0x8013001f, 0x9020c000, 0x003fb006, 0x803effe0, + 0x803effe8, 0x803effec, 0x9020e000, 0x9021ffe4, + 0x9020fa00, 0x803effd0, 0x803effdc, 0x803effd8, + 0x9020fe00, 0x803effd4, 0x90400000, 0x804600a2, + 0x90421800, 0x804600a3, 0x80134099, 0x98000040, + 0x800600a6, 0x80130000, 0x98003ca1, 0x800600a1, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x001f2324, 0x80070000, 0x001fb0ba, + 0x001f23f9, 0x801eb3f0, 0x80070800, 0x001f600f, + 0x80070000, 0x001f2012, 0x001fb0cb, 0x001fb010, + 0x801efff0, 0x98004000, 0x98008000, 0x001f600e, + 0x83e40123, 0x80070000, 0x801eb3f8, 0x801eff70, + 0x800500a0, 0xb0000001, 0xb4000009, 0x80070001, + 0x800600a0, 0x80050080, 0x98000020, 0x80060080, + 0x9400ffdf, 0x80060080, 0x80070000, 0x800600a0, + 0x81df0004, 0x00000000, 0x00000000, 0x801bfff0, + 0x00000000, 0x940000ff, 0xb0000000, 0xb420004e, + 0x003f400e, 0x94010010, 0xb0000000, 0xb400fff4, + 0x838413a4, 0x003f0013, 0xb0010001, 0xb420003b, + 0x803bffe8, 0x801bffec, 0x00000000, 0x3001b800, + 0xb4600001, 0x90212000, 0x0421b800, 0x005f4193, + 0x5841b802, 0x3001b802, 0xb460000d, 0x80050086, + 0x005f9016, 0xb0020000, 0xb4200002, 0x001fb016, + 0xb500ffdf, 0x0420b802, 0xb0010b50, 0xb4a0ffdc, + 0x80070000, 0x001fb016, 0x83e400ed, 0xb500ffd8, + 0x80070000, 0x001fb016, 0x001f400e, 0x9400000f, + 0xb0000000, 0xb4000014, 0xb0000001, 0xb4000010, + 0x003f400e, 0x9421fff0, 0x003f600e, 0x003f9006, + 0x9421ffff, 0x90210004, 0xb001e000, 0xb4800002, + 0x8421e000, 0x9021c000, 0x8013001f, 0x1021b800, + 0x003fb006, 0x003f90cb, 0x90210004, 0x003fb0cb, + 0x83e400df, 0x83e41383, 0x8007001f, 0x94000003, + 0x5810b800, 0x83e71aa8, 0x1bffb800, 0x003f9008, + 0x1821b800, 0x00ffb801, 0x83e413d6, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671ad4, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0xb500ffaa, 0x803bffc0, 0x805bffc4, + 0x807bffc8, 0x809bffcc, 0x5828b801, 0x5cb8b802, + 0x1821b805, 0x5848b802, 0x5cb8b803, 0x1842b805, + 0x5868b803, 0x5cb8b804, 0x1863b805, 0x5888b804, + 0x1884b800, 0x803effc0, 0x805effc4, 0x807effc8, + 0x809effcc, 0x003f400e, 0xb0000086, 0xb4400040, + 0xb0000084, 0xb400002a, 0xb0000085, 0xb4000030, + 0xb0000086, 0xb4000032, 0x001f4000, 0x94000080, + 0xb0000080, 0xb400006a, 0x80130000, 0x98003ca1, + 0x005f4000, 0x94420008, 0xb0020008, 0xb4000001, + 0xa0000080, 0x800600a1, 0x8013001f, 0x9040c000, + 0x005fb006, 0x805effe0, 0x805effe8, 0x805effec, + 0x9040e000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001fb0cb, + 0x001fb010, 0x001f2058, 0x80071f40, 0x001fb008, + 0x80075d70, 0x001fb009, 0x98214000, 0xb5000010, + 0x94011000, 0xb0001000, 0xb4200001, 0x9421efff, + 0x98210010, 0xb500000a, 0x80070000, 0x001fb0cb, + 0x83e4007f, 0x003f400e, 0x9421ffef, 0xb5000004, + 0x83e4007b, 0x003f400e, 0x98211000, 0x9421ffef, + 0x003f600e, 0x80070100, 0x801efff0, 0xb500ff54, + 0xb000008b, 0xb400001c, 0xb000008e, 0xb4000022, + 0xb000008d, 0xb400001c, 0xb000008c, 0xb4000021, + 0xb0000087, 0xb400ffe8, 0xb0000088, 0xb4000014, + 0xb000008a, 0xb4000015, 0xb0000089, 0xb400001d, + 0xb00000a0, 0xb400001f, 0xb00000a1, 0xb4000041, + 0xb00000a2, 0xb400004a, 0xb00000a3, 0xb4000046, + 0xb00000a4, 0xb4000048, 0xb00000a5, 0xb4000048, + 0xb00000a6, 0xb4000048, 0x803efff8, 0xb500ffdd, + 0x9421ffdf, 0xb500ffda, 0xb500ffda, 0x80270100, + 0x803efff8, 0xb500ffd7, 0x80070000, 0x001fb017, + 0xb500ffd4, 0x801bffb0, 0x00000000, 0x001fb003, + 0xb500ffd0, 0x803bff80, 0x00000000, 0x003f6001, + 0xb500ffcc, 0x003f90ba, 0x803efff8, 0xb500ffc9, + 0x80130001, 0x98003da1, 0x800600a1, 0x80070200, + 0x801ebf34, 0x83e4002e, 0x8013001f, 0x9840c000, + 0x805effe0, 0x005fb006, 0x805effe8, 0x805effec, + 0x90422000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001f2324, + 0x001fb0cb, 0x001fb010, 0x001f2058, 0x80077490, + 0x001fb008, 0x80077710, 0x001fb009, 0x98214000, + 0xb500ffa7, 0x80270000, 0x8047fef0, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x83641460, 0xb500ff9d, + 0x8364140e, 0xb500ff9b, 0x836413cd, 0xb500ff99, + 0x83441334, 0xb500ff97, 0x8344131d, 0xb500ff95, + 0x80070000, 0x80470000, 0xb6002003, 0xb6003002, + 0x001eb802, 0x90420004, 0x80171000, 0x8057ffff, + 0xb6002002, 0xb6001801, 0x001fa020, 0x00ffb81f, + 0x001f4000, 0x94000080, 0xb0000080, 0xb4200001, + 0xb500ffef, 0xb500000a, 0x80270000, 0x003f2013, + 0x8007001f, 0x94000003, 0x5810b800, 0x83671e40, + 0x1b7bb800, 0x003f9009, 0x1821b800, 0x00ffb801, + 0x003f0013, 0xb0010001, 0xb420fff3, 0x83a70000, + 0x803bff70, 0x00000000, 0xb0010000, 0xb4000011, + 0x80170300, 0x80070000, 0xb6000601, 0x001fa020, + 0x83640c6e, 0x00ff0325, 0x82870000, 0xb6270002, + 0x83640217, 0x92940001, 0x001f033b, 0xb0000000, + 0xb4000002, 0x80270000, 0xb5000001, 0x80270001, + 0x003f233b, 0x80270000, 0x003f2013, 0x8007001f, + 0x94000003, 0x5810b800, 0x83671ecc, 0x1b7bb800, + 0x003f9009, 0x1821b800, 0x00ffb801, 0x003f0013, + 0xb0010001, 0xb420fff3, 0x93bd0001, 0xb01d0004, + 0xb480ffdb, 0x803bff70, 0x00000000, 0xb0010000, + 0xb4000001, 0x83640c1a, 0x00000000, 0x00000000, + 0x00ffb81f, 0x007f90cb, 0x90630400, 0x007fb0cb, + 0x003f9006, 0x9421ffff, 0x90210400, 0xb001e000, + 0xb4800002, 0x8421e000, 0x9021c000, 0x8013001f, + 0x1021b800, 0x003fb006, 0x803effec, 0x00ffb81f, + 0x015f400e, 0x944a4000, 0xb0024000, 0xb4200084, + 0x954abfff, 0x015f600e, 0x820f001f, 0x802f001f, + 0x81470000, 0x015f23f9, 0x829702ec, 0x82d7ffff, + 0x82f70000, 0xb6000501, 0x029fa02a, 0x82970400, + 0xb6000702, 0xb6000001, 0x029fa02a, 0x8053ff00, + 0x98420000, 0x805ebf14, 0x805ebf18, 0x805ebf1c, + 0x805ebf20, 0x805ebf24, 0x805ebf28, 0x80270000, + 0x003f2328, 0x80275480, 0x005fb801, 0x8033001f, + 0x9821c000, 0x803effe0, 0x90212000, 0x803effe4, + 0x80dbff8c, 0x80fbff90, 0x80debf14, 0x80febf18, + 0x80dbff94, 0x80fbff98, 0x80debf1c, 0x80febf20, + 0x80dbff9c, 0x80fbffa0, 0x80debf24, 0x80febf28, + 0x80dbff84, 0x80e70001, 0x00dfb001, 0x80dbff88, + 0x00ff6191, 0x00dfb002, 0x80dbffb0, 0x80470000, + 0x00dfb003, 0x80d9ff80, 0x005fb0cf, 0x005fb0c6, + 0x00df6001, 0x80470001, 0x005f618f, 0x804700ff, + 0x005f231c, 0x005f231d, 0x80470000, 0x005f204e, + 0x8047e138, 0x5c42b802, 0x814f6300, 0x80cf00a9, + 0x005fb0bc, 0x5842b802, 0x01cfb802, 0x005f90bc, + 0xb520ffff, 0x8067e16c, 0x5c62b803, 0x80270040, + 0xb6000209, 0x814fffc0, 0x00cfb801, 0x007fb0bc, + 0x5862b803, 0x01cfb803, 0x007f90bc, 0xb520ffff, + 0x90210020, 0x90630020, 0x8047e398, 0x5c42b802, + 0x814fce40, 0x80cf0080, 0x005fb0bc, 0x5842b802, + 0x01cfb802, 0x005f90bc, 0xb520ffff, 0x8047e400, + 0x5c42b802, 0x814f7380, 0x80cf009a, 0x005fb0bc, + 0x5842b802, 0x01cfb802, 0x005f90bc, 0xb520ffff, + 0x8047e43c, 0x5c42b802, 0x814f18c0, 0x80cf00b6, + 0x005fb0bc, 0x5842b802, 0x01cfb802, 0x005f90bc, + 0xb520ffff, 0x80e70000, 0x00ffb0ba, 0x808f0000, + 0x806f001f, 0x80af001f, 0x8027b9fc, 0x5c22b801, + 0x80670700, 0xb600080a, 0x00cfb803, 0x003fb0bc, + 0x5822b801, 0x01cfb801, 0x003f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90210020, 0x90630020, + 0x834400d3, 0xb0180000, 0xb4200025, 0x83440680, + 0x80c70000, 0x00df2324, 0x83640026, 0x83440228, + 0x00df0324, 0x90c60001, 0x00df2324, 0xb0060006, + 0xb4000003, 0x81472178, 0x015fb008, 0x00ffb81f, + 0x00ff90ba, 0x90e70001, 0x00ffb0ba, 0x019f9006, + 0x958cffff, 0x00df4193, 0x58c1b806, 0x118cb806, + 0xb00ce000, 0xb4800002, 0x858ce000, 0x918cc000, + 0x8153001f, 0x118cb80a, 0x819effec, 0x019fb006, + 0x015f4193, 0x5941b80a, 0x019f90cb, 0x118cb80a, + 0x019fb0cb, 0x81472160, 0x015fb008, 0x00ffb81f, + 0x015f400e, 0x194ab818, 0x015f600e, 0x802500a5, + 0x00ffb81f, 0x803bff8c, 0x805bff90, 0x803ebf14, + 0x805ebf18, 0x803bff94, 0x805bff98, 0x803ebf1c, + 0x805ebf20, 0x803bff9c, 0x805bffa0, 0x803ebf24, + 0x805ebf28, 0x80470003, 0x805ebefc, 0x003f0384, + 0x5822b801, 0x9021eb50, 0x005bb801, 0x00000000, + 0xb0020001, 0xb4200002, 0x80470001, 0x805ebefc, + 0x8073ff80, 0x98630000, 0x8027bf14, 0x8047befc, + 0xb6000609, 0x009bb801, 0x00000000, 0x00a7b804, + 0x6081b804, 0x3004b803, 0xb4000001, 0x00beb802, + 0x90210004, 0x90420004, 0x00ffb81b, 0x00000000, + 0x81150010, 0x00000000, 0x00000000, 0x81350010, + 0x00000000, 0x00000000, 0x81550002, 0x00000000, + 0x015f2380, 0x81550006, 0x00000000, 0x015f2381, + 0x81550005, 0x00000000, 0x015f2382, 0x81550003, + 0x00000000, 0x015f2383, 0x81550003, 0x015f2384, + 0xb00a0001, 0xb4000005, 0x956a0001, 0xb00b0000, + 0xb4000002, 0x81750002, 0x017f2385, 0x956a0004, + 0xb00b0000, 0xb4000002, 0x81750002, 0x017f2386, + 0xb00a0002, 0xb4200003, 0x81750002, 0x00000000, + 0x017f2387, 0x81750001, 0x00000000, 0x017f2388, + 0x81750005, 0x00000000, 0x017f2389, 0x81750001, + 0x017f239f, 0xb00b0001, 0xb4200003, 0x81750008, + 0x5968b80b, 0x017f61c5, 0x81750001, 0x017f238c, + 0xb00b0001, 0xb4200003, 0x81750008, 0x00000000, + 0x017f238d, 0x81750001, 0x017f238e, 0xb00b0001, + 0xb4200005, 0x81750005, 0x00000000, 0x017f238f, + 0x81750002, 0x017f2390, 0xb00a0000, 0xb420001b, + 0x81750005, 0x00000000, 0x017f2391, 0x81750001, + 0x017f23a0, 0xb00b0001, 0xb4200003, 0x81750008, + 0x5968b80b, 0x017f61c9, 0x81750001, 0x017f2394, + 0xb00b0001, 0xb4200003, 0x81750008, 0x00000000, + 0x017f2395, 0x81750001, 0x017f2396, 0xb00b0001, + 0xb4200006, 0x81750005, 0x00000000, 0x017f2397, + 0x81750002, 0x00000000, 0x017f2398, 0x81750001, + 0x00000000, 0x017f2399, 0x81750001, 0x00000000, + 0x017f239a, 0x81750001, 0x017f239b, 0xb00b0001, + 0xb4200003, 0x8175000e, 0x00000000, 0x017f61be, + 0x81750001, 0x017f239c, 0xb00b0001, 0xb4200003, + 0x8175000e, 0x00000000, 0x017f237e, 0x81750001, + 0x017f239d, 0xb00b0001, 0xb4200006, 0x81750006, + 0x017f239e, 0x916b0001, 0x81550008, 0x856b0001, + 0xb4e0fffd, 0x00ffb81c, 0x00000000, 0x00000000, + 0x81470000, 0x015f2385, 0x015f2386, 0x015f2387, + 0x015f238d, 0x015f238f, 0x015f2390, 0x015f2391, + 0x015f2395, 0x015f2396, 0x015f2397, 0x015f2398, + 0x015f61be, 0x015f61bf, 0x82070028, 0x023f9006, + 0x83a4003a, 0x83270000, 0x003fb819, 0x003f9006, + 0x5823b801, 0x83338000, 0x1b39b801, 0x003fb819, + 0x00000000, 0x00000000, 0x81550000, 0x8384ff64, + 0x017f0380, 0xad4b0026, 0x013f0381, 0x114ab809, + 0x5941b80a, 0x914ae00c, 0x0199b80a, 0x00000000, + 0x019f6193, 0xb0080b77, 0xb4200016, 0x015f0380, + 0xb00a0003, 0xb4600017, 0xb0090026, 0xb4600019, + 0x017f90ba, 0xb00b0000, 0xb4200004, 0x017f0384, + 0x017f204d, 0x017f0383, 0x017f2057, 0x015f0383, + 0x017f0057, 0x300ab80b, 0xb4200012, 0x015f0384, + 0x017f004d, 0x300ab80b, 0xb420000e, 0x83070000, + 0x00ffb81a, 0x83070800, 0x031f6193, 0x83070001, + 0x00ffb81a, 0x83070800, 0x031f6193, 0x83070002, + 0x00ffb81a, 0x83070800, 0x031f6193, 0x83070003, + 0x00ffb81a, 0x83070003, 0x00ffb81a, 0x5e02b810, + 0x5a02b810, 0x00bf9011, 0x00df004f, 0xa5260020, + 0x81e70000, 0x82471000, 0x95d1ffff, 0xa5cee000, + 0x300eb810, 0xb4600002, 0x05f0b80e, 0x0207b80e, + 0x8267001f, 0x82c70020, 0x82971000, 0xb0100080, + 0xb480001f, 0x5a8bb813, 0x5aa6b813, 0x1a94b815, + 0x01efb812, 0x014fb814, 0x01cfb811, 0xb520ffff, + 0xb636000f, 0x81470000, 0x039f8014, 0xb6000404, + 0x5948b80a, 0x957c00ff, 0x194ab80b, 0x5f88b81c, + 0xb0060020, 0xb4200001, 0x80a70000, 0x64a6b805, + 0x68e9b80a, 0x18a5b807, 0x029fa025, 0x00a7b80a, + 0x01efb812, 0x014fb814, 0x01afb811, 0xb520ffff, + 0x5ae2b816, 0x1231b817, 0x0610b817, 0xb500ffde, + 0xb0100000, 0xb4000003, 0x5ec2b810, 0x86760001, + 0xb500ffdc, 0xb00f0000, 0xb4000005, 0x0207b80f, + 0x81f3001f, 0x9a2fc000, 0x81e70000, 0xb500ffd0, + 0x015fb011, 0x00ffb81d, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x82d7ffff, 0x8357ffff, 0x83d7ffff, + 0x80770000, 0x80f70000, 0x81770000, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x83f70000, + 0xaeb40080, 0x808f0000, 0x806f001f, 0x80af001f, + 0xb0140000, 0xb4400014, 0x806f001f, 0x80af001f, + 0x8027b9fc, 0x5c22b801, 0x80670700, 0xb6000208, + 0x00cfb803, 0x003fb0bc, 0x5822b801, 0x01cfb801, + 0x003f90bc, 0xb520ffff, 0x90630020, 0x90210020, + 0x80270000, 0x80171000, 0xb6000303, 0xb6000001, + 0x001fa021, 0x00000000, 0x82670000, 0xb6000268, + 0x80170a00, 0x80970afc, 0x81170b00, 0x81970bfc, + 0x80271c00, 0x1021b813, 0x1021b813, 0x0217b801, + 0x80271ffc, 0x0421b813, 0x0421b813, 0x0297b801, + 0x80270c00, 0x1021b813, 0x1021b813, 0x0317b801, + 0x80270ffc, 0x0421b813, 0x0421b813, 0x0397b801, + 0x80478500, 0x1042b813, 0x5c42b802, 0x1022b815, + 0x80670280, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0x009f033b, + 0x80478480, 0x0442b813, 0x5c42b802, 0x1022b815, + 0x806702a0, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0xb0040000, + 0xb4000002, 0x80479000, 0xb5000001, 0x80479c00, + 0x1042b813, 0x5c42b802, 0x1022b815, 0x806702c0, + 0x00cfb803, 0x003fb0bc, 0x5822b801, 0x01cfb801, + 0x003f90bc, 0xb520ffff, 0xb0040000, 0xb4000002, + 0x80479180, 0xb5000001, 0x80479d80, 0x0442b813, + 0x5c42b802, 0x1022b815, 0x806702e0, 0x00cfb803, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x81270000, 0x80370000, 0x80b70000, + 0x81370000, 0x81b70000, 0x82370004, 0x82b7fffc, + 0xb6002016, 0x41498008, 0x51498814, 0x51498814, + 0x51418810, 0x51418810, 0x41818814, 0x0308a02a, + 0x49958820, 0x51898810, 0x51918828, 0x414d8814, + 0x0388a7ec, 0x494d8814, 0x49458810, 0x49458810, + 0x418d8810, 0x0308a02a, 0x49918fec, 0x51858814, + 0x51958fe4, 0x00000000, 0x0388a7ec, 0x92730080, + 0x009f033b, 0x5802b814, 0x90400300, 0x001f9802, + 0x00000000, 0xb0000000, 0xb4200016, 0x80170a00, + 0x80070000, 0xb6002001, 0x001fa020, 0xb0040000, + 0xb4200002, 0x80279000, 0xb5000001, 0x80279c00, + 0xac740080, 0x5c22b801, 0x11e1b803, 0x806f001f, + 0x80af001f, 0xb6000407, 0x80cf0280, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x91ef0020, 0x007f0320, 0x011f90cd, 0xaca30006, + 0x80c7b004, 0x10a5b814, 0x58a1b805, 0x10a5b806, + 0x0099b805, 0x8027b3dc, 0x5841b804, 0x1021b802, + 0x0159b801, 0x8027b3d0, 0x5841b804, 0x1021b802, + 0x0139b801, 0x80170c00, 0x0097b80a, 0xb0090000, + 0xb4200004, 0xb6000002, 0x015f8020, 0x009fe0ca, + 0xb5000004, 0x015fc024, 0xb6000002, 0x015f8020, + 0x009fe0ca, 0x00ffb81b, 0x00000000, 0x00000000, + 0x009f0011, 0x015f0012, 0xb0060000, 0xb4200007, + 0x968a0001, 0xb0140000, 0xb400000d, 0x80870001, + 0x009f2011, 0x954a0002, 0x015f2012, 0xb0060002, + 0xb4200007, 0x968a0002, 0xb0140000, 0xb4000004, + 0x80870001, 0x009f2011, 0x81470000, 0x015f2012, + 0x8364002b, 0x00bf2010, 0xb0060000, 0xb4200003, + 0xb0050000, 0xb4200001, 0x8364008d, 0xb0050000, + 0xb4200001, 0x836400b2, 0x00bf0010, 0xb0050000, + 0xb4200006, 0x83640983, 0x8364029d, 0x00000000, + 0x8364092b, 0x00000000, 0xb5000005, 0x00bf0010, + 0xb0050001, 0xb4000002, 0x00000000, 0x83640924, + 0x00ff0325, 0x82870000, 0xb6270002, 0x8364ff00, + 0x92940001, 0x80070001, 0x801eff70, 0x001f0010, + 0xb0000001, 0xb4000007, 0x001f033b, 0xb0000000, + 0xb4000002, 0x80270000, 0xb5000001, 0x80270001, + 0x003f233b, 0x00ffb81a, 0x00000000, 0x00000000, + 0x027f4001, 0x5e2ab813, 0x96310003, 0x81c70000, + 0x820700ff, 0xb0110000, 0xb4000005, 0x5a21b811, + 0x81c70200, 0x8207000e, 0x69d1b80e, 0x1210b811, + 0x01dfb0cd, 0x5e2cb813, 0x96310003, 0x023f2323, + 0x5e28b813, 0x96310003, 0x023f2322, 0x5e27b813, + 0x96310001, 0x023f2328, 0x5e23b813, 0x96310001, + 0x023f2321, 0x95f30007, 0x01ff2320, 0x920fe004, + 0x0258b810, 0x00000000, 0x1252b811, 0x025f2325, + 0x8167befc, 0x017f6195, 0x021f031c, 0x01df031d, + 0x3010b80f, 0xb4200003, 0x3011b80e, 0xb4200001, + 0xb5000021, 0x80270000, 0x80471000, 0x0017b802, + 0x8057ffff, 0xb6002001, 0x001fa021, 0x80270400, + 0x80679000, 0x5c62b803, 0xb6001809, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01afb803, 0x007f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x80679c00, 0x5c62b803, 0xb6001809, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01afb803, 0x007f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x01ff231c, 0x023f231d, 0x83970300, 0x82070000, + 0xb6320001, 0x039fa030, 0x00bf0010, 0x021f0324, + 0xb0100000, 0xb4200001, 0x80a70000, 0xb0050000, + 0xb4200008, 0xb0040000, 0xb4a00002, 0x80a70001, + 0xb5000004, 0x82070000, 0x021f204e, 0xb4000001, + 0x80a70002, 0xb0050001, 0xb4200007, 0x021f004e, + 0xb0100002, 0xb4a00002, 0x80a70002, 0x00ffb81b, + 0x92100001, 0x021f204e, 0x00000000, 0x00ffb81b, + 0x81530000, 0x003fb80a, 0x00000000, 0x00000000, + 0x003fb819, 0x00000000, 0x00000000, 0x81550000, + 0x8384fd73, 0x81470000, 0x015f61ee, 0x015f61ef, + 0x015f23a4, 0x8297050c, 0x82d7ffff, 0xb6000501, + 0x029fa02a, 0x8167e004, 0x116b0384, 0x0158b80b, + 0x019f0382, 0x015f237b, 0x017f0388, 0x116bb80a, + 0xb00c0008, 0xb4a00003, 0x80a70003, 0x00bf2010, + 0x00ffb81b, 0xb00a0005, 0xb4400003, 0xb00b0006, + 0xb4400001, 0x00ffb81b, 0x80a70004, 0x00bf2010, + 0x00ffb81b, 0x00000000, 0x00000000, 0x00000000, + 0x027f0388, 0x02bf037b, 0x02df0384, 0x02ff03a1, + 0x82970400, 0x8257ffff, 0x82d7ffff, 0xb6350003, + 0x81550001, 0x8357ffff, 0x029fa02a, 0x82970414, + 0xb6350003, 0x81550001, 0x83d7ffff, 0x029fa02a, + 0x81550001, 0xb00a0001, 0xb4200004, 0x814d0008, + 0x6149b80a, 0x954affff, 0x015f61ee, 0xb0160000, + 0xb4200007, 0x81550001, 0xb00a0001, 0xb4200004, + 0x814d0008, 0x6149b80a, 0x954affff, 0x015f61ef, + 0x81550001, 0xb00a0001, 0xb4200036, 0x82f50001, + 0x02ff23a1, 0xb0170001, 0xb420002c, 0x82970428, + 0xb6350003, 0x81550001, 0x00000000, 0x029fa02a, + 0x82970428, 0x81470000, 0x017f8034, 0xb00b0001, + 0xb4000004, 0x914a0001, 0x300ab815, 0xb480fffa, + 0xb5000001, 0x015f23a5, 0x81670000, 0xb0160002, + 0xb4200002, 0x81750001, 0x00000000, 0x017f233a, + 0x81550004, 0xadaa000c, 0x015f23a2, 0x81750004, + 0x916b0003, 0x017f23a3, 0x91ad0025, 0x01bf23a6, + 0xadab000c, 0x81e70000, 0x91ad0025, 0x01bf23a7, + 0x920a0001, 0x05abb810, 0xb00d0000, 0xb400000d, + 0xb62d0004, 0x81b50001, 0x65b0b80d, 0x19efb80d, + 0x92100001, 0x01ffb0be, 0xb5000006, 0x81a70000, + 0x82970428, 0xb6350001, 0x029fa02d, 0x01bf233a, + 0x01bf23a5, 0x82070000, 0x82270000, 0x82170428, + 0xb635003a, 0x01bf8030, 0xb00d0001, 0xb4200036, + 0x81d50001, 0x65b1b80e, 0x1a10b80d, 0xb00e0001, + 0xb4200031, 0x81b50002, 0xadad0003, 0xae510048, + 0x91cd000f, 0x91320868, 0x015f03a2, 0xad4a0004, + 0x92920700, 0x1189b80a, 0x0297b80c, 0x1194b80a, + 0x0317b80c, 0x01ff90be, 0x015f03a2, 0x017f03a3, + 0x064bb80a, 0x0107b80a, 0xb0120000, 0xb400001e, + 0xb632001d, 0x6928b80f, 0x95290001, 0xb0090000, + 0xb420000e, 0x81350004, 0x1129b80d, 0x029fa029, + 0x824d0004, 0x5a48b812, 0x5e48b812, 0x3009b80e, + 0xb4200002, 0x5e41b812, 0xb500000d, 0x5e42b812, + 0x81330040, 0x1a52b809, 0xb5000009, 0x0127b854, + 0x85290004, 0x0397b809, 0x0287b858, 0x86940004, + 0x013f803c, 0x0397b814, 0x029fa029, 0x025f803c, + 0x031fa032, 0x91080001, 0x92310001, 0x015f03a2, + 0x017f03a3, 0x013f033a, 0xb0090001, 0xb420001f, + 0x95300002, 0x95900001, 0x1929b80c, 0xb0090000, + 0xb400001a, 0x064bb80a, 0x0107b80a, 0xb6320017, + 0x6928b80f, 0x95290001, 0xb0090000, 0xb4200002, + 0x81350001, 0x013f23f8, 0x81a70700, 0x91ad0048, + 0x5982b808, 0x11adb80c, 0x0397b80d, 0x013f03f8, + 0xb0090001, 0xb4200005, 0x019f801c, 0x0196b80c, + 0x81b3ff80, 0x418cb80d, 0xb5000002, 0x019f801c, + 0x0196b80c, 0x039fa00c, 0x91080001, 0xb0160002, + 0xb420001a, 0xb0170001, 0xb4200008, 0xb00a0000, + 0xb4200002, 0x81270002, 0xb5000005, 0xb00a0002, + 0xb4400002, 0x81270003, 0xb5000001, 0x81270004, + 0x013f23a9, 0x81950001, 0xb00c0001, 0xb420000d, + 0x81a70000, 0x8397043c, 0xb6290006, 0x81150001, + 0x039fa028, 0xb0080001, 0xb4200001, 0x81a70001, + 0x00000000, 0x01bf23a8, 0xb5000002, 0x81a70000, + 0x01bf23a8, 0xb0170001, 0xb4200001, 0x81b50002, + 0x82970c20, 0xb6350003, 0x81550002, 0x00000000, + 0x029fa02a, 0xb0130001, 0xb4200001, 0x81150001, + 0x81c70000, 0xb6350014, 0x922e0c20, 0x015ff011, + 0xb00a0000, 0xb400000f, 0x922e0428, 0x015ff011, + 0xb00a0001, 0xb4200005, 0x922e044c, 0x0297b811, + 0x015f03a6, 0x029fa00a, 0xb5000006, 0x81550006, + 0xad4a0003, 0x922e044c, 0x0297b811, 0x914a0049, + 0x029fa00a, 0x91ce0004, 0xb0170001, 0xb420001e, + 0xb00d0000, 0xb400001c, 0x852d0001, 0x81470001, + 0x6549b80a, 0xad6a0003, 0x019f03a7, 0x058c03a6, + 0x81270000, 0xb00b0000, 0xb4000005, 0x300cb80b, + 0xb4800003, 0x058cb80b, 0x91290001, 0xb500fffb, + 0x81750004, 0x5961b80b, 0x839704ec, 0x0187b860, + 0x039fa02c, 0x039fa02a, 0x039fa029, 0x039fa02b, + 0xb0090000, 0xb4000004, 0xb6290003, 0x81550007, + 0x00000000, 0x00000000, 0x81c70000, 0xb635002e, + 0x922e0c20, 0x01fff011, 0xb00f0000, 0xb4000029, + 0x852f0001, 0x81470001, 0x6549b80a, 0xad6a0003, + 0x922e044c, 0x025fd811, 0x86520001, 0x0227b812, + 0x81270000, 0xb00b0000, 0xb4000005, 0x3012b80b, + 0xb4800003, 0x0652b80b, 0x91290001, 0xb500fffb, + 0x2e09b80b, 0x00000000, 0x3010b811, 0xb4600001, + 0x91290001, 0xae4e0004, 0x82150004, 0x9232049c, + 0x0297b811, 0x0187b860, 0x029fa02c, 0x029fa02a, + 0x029fa029, 0x029fa030, 0xb0090000, 0xb4000004, + 0xb6290003, 0x81550007, 0x00000000, 0x00000000, + 0x82270460, 0x1231b80e, 0x0217b811, 0x81550002, + 0x021fa00a, 0x91ce0004, 0xb0130001, 0xb420000c, + 0xb0080000, 0xb400000a, 0x81550004, 0x839704fc, + 0x0167b860, 0x039fa02b, 0x81670001, 0x039fa02b, + 0x8175000e, 0x81670002, 0x039fa02b, 0x039fa02a, + 0x81150001, 0xb0080001, 0xb420000a, 0x8135000b, + 0x5d2923aa, 0x95490180, 0x5d4723ab, 0x95490060, + 0x5d4523ac, 0x95490018, 0x5d4323ad, 0x95490007, + 0x015f23ae, 0x81350001, 0xb0090001, 0xb4200017, + 0x81350006, 0x013f23af, 0xb0170001, 0xb4200005, + 0x81550004, 0x00000000, 0x015f23b0, 0x81550003, + 0x015f23b1, 0x82970474, 0x83170488, 0xb6350004, + 0x81550007, 0x5e83a02a, 0x954a0007, 0x031fa02a, + 0xb0130001, 0xb4200005, 0x81750004, 0x00000000, + 0x017f23b2, 0x81750003, 0x017f23b3, 0xb0170001, + 0xb420000b, 0x81b50001, 0xb00d0001, 0xb4200008, + 0x81d50003, 0x59c8b80e, 0x91ce0300, 0x01df61da, + 0x81d50003, 0x59c8b80e, 0x91ce0300, 0x01df61db, + 0x81550001, 0xb00a0001, 0xb420004b, 0xb0170001, + 0xb4200001, 0x81550002, 0x82470000, 0x82270000, + 0xb6350004, 0x81750002, 0x6571b80b, 0x92310002, + 0x1a52b80b, 0xb0170001, 0xb4200017, 0xb00a0001, + 0xb4200011, 0x81150003, 0x91080001, 0x011f23a4, + 0x829709d0, 0x831709f0, 0x83970060, 0xb6280009, + 0x81750005, 0x00000000, 0x029fa02b, 0x81750004, + 0x00000000, 0x031fa02b, 0x81750003, 0x00000000, + 0x039fa02b, 0xb5000004, 0xb00a0002, 0xb4800002, + 0x81070000, 0x011f23a4, 0x82270000, 0x81270000, + 0xb6350025, 0x6a11b812, 0x92310002, 0x96100003, + 0xb0100001, 0xb4200018, 0xada90020, 0x81750003, + 0x920d0520, 0x0217b810, 0x920d05c0, 0x0297b810, + 0x920d0660, 0x0317b810, 0x5942b809, 0x920a050c, + 0x0397b810, 0x916b0001, 0x039fa02b, 0xb62b0009, + 0x81750005, 0x00000000, 0x021fa02b, 0x81750004, + 0x00000000, 0x029fa02b, 0x81750003, 0x00000000, + 0x031fa02b, 0xb5000007, 0xb0100002, 0xb4800005, + 0x59a2b809, 0x91ad050c, 0x0397b80d, 0x82070000, + 0x039fa010, 0x91290001, 0x81550001, 0xb00a0001, + 0xb4200007, 0x81550009, 0xb00a0000, 0xb4000004, + 0xb62a0003, 0x82150008, 0x00000000, 0x00000000, + 0xb00a0100, 0xb4a00007, 0x954aff00, 0xb6008003, + 0x82150010, 0x00000000, 0x00000000, 0x854a0100, + 0xb4e0fffa, 0x00ffb81b, 0x00000000, 0x00000000, + 0x81070000, 0x011f61dc, 0x011f61de, 0x011f61e0, + 0x011f03aa, 0x9108e0f4, 0x0138b808, 0x011f03ab, + 0x013f61ac, 0x9108e0f0, 0x0138b808, 0x011f03ac, + 0x013f61ad, 0x5901b808, 0x9108e0f8, 0x0139b808, + 0x011f03ad, 0x013f61ae, 0x5901b808, 0x9108e100, + 0x0139b808, 0x011f03ae, 0x013f61b0, 0x5901b808, + 0x9108e108, 0x0179b808, 0x013f03af, 0x017f61b1, + 0x02bf037b, 0x82970474, 0xb6350002, 0x015f8034, + 0x1929b80a, 0x011f03a1, 0xb0080001, 0xb4200002, + 0x015f03b0, 0x1929b80a, 0x019f0388, 0xb00c0001, + 0xb4200002, 0x015f03b2, 0x1929b80a, 0x013f61b3, + 0x015f03a8, 0xb00a0001, 0xb420003a, 0x81a70000, + 0x01bf237a, 0x83840056, 0x806f001f, 0x80af001f, + 0x80270300, 0x8067a800, 0x5c62b803, 0xb600080a, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01afb803, + 0x007f90bc, 0x0047b86f, 0xb0020001, 0xb4c0fffd, + 0x90210020, 0x90630020, 0x81a70001, 0x01bf237a, + 0x83840043, 0x838403c6, 0x81a70000, 0x01bf237a, + 0x82470400, 0x01bff012, 0x01bf23fa, 0x83840418, + 0x8384048f, 0x8384053e, 0x83840595, 0x806f001f, + 0x80af001f, 0x80270300, 0x8067ac00, 0x5c62b803, + 0xb600080a, 0x00cfb801, 0x007fb0bc, 0x5862b803, + 0x01cfb803, 0x007f90bc, 0x0047b86f, 0xb0020001, + 0xb4c0fffd, 0x90210020, 0x90630020, 0x81a70001, + 0x01bf237a, 0x82470404, 0x015ff012, 0x015f23fa, + 0x838403ff, 0x83840476, 0x83840525, 0x8384057c, + 0xb5000011, 0x81a70000, 0x01bf237a, 0xb635000e, + 0x8384001b, 0x01bf037a, 0xad4d0004, 0x00000000, + 0x914a0400, 0x01bff00a, 0x01bf23fa, 0x838403f0, + 0x83840467, 0x83840516, 0x8384056d, 0x01df037a, + 0x91ce0001, 0x01df237a, 0x019f0388, 0xb00c0001, + 0xb4200009, 0x02bf037b, 0x02bf237a, 0x838400e8, + 0x82470000, 0x025f23fa, 0x838403e1, 0x83840458, + 0x83840507, 0x8384055e, 0x00ffb81b, 0x00000000, + 0x80770000, 0x80f70000, 0x81770000, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x83f70000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x82d7ffff, 0x8357ffff, 0x83d7ffff, + 0x017f037a, 0x5a42b80b, 0x01bf03a8, 0xb00d0001, + 0xb4200004, 0x011f9118, 0x013f9119, 0x7929b808, + 0xb5000002, 0x91b20460, 0x013ff00d, 0x91b20340, + 0x0297b80d, 0x00000000, 0x029fa009, 0x01df0384, + 0xb00e0000, 0xb4200005, 0xb00b0001, 0xb4200003, + 0x009f90c6, 0x00bf0391, 0xb5000002, 0x009f90cf, + 0x00bf0389, 0x83a4013a, 0x81870000, 0x019f61b5, + 0x019f61b4, 0x5a02b80b, 0x9190044c, 0x01dfd80c, + 0x01df61b6, 0x91900488, 0x01dff00c, 0x59c1b80e, + 0x918ee118, 0x01d9b80c, 0x019f03af, 0x01df61af, + 0x858c000f, 0x5986b80c, 0x91d00474, 0x01bff00e, + 0x59c2b80d, 0x11cc61b2, 0x81870000, 0x019f61b8, + 0x91900414, 0x01dfd80c, 0x01df61b7, 0xadab0010, + 0x00000000, 0x908d049c, 0x83a40189, 0xadcb0020, + 0x5982b80b, 0x908e0520, 0x90ae05c0, 0x90ce0660, + 0x928c050c, 0x00ff9814, 0x83a40161, 0x83a401b0, + 0x017f037a, 0x59c2b80b, 0x918e0428, 0x01fff00c, + 0xb00f0001, 0xb4200081, 0x023f03a5, 0x3011b80b, + 0xb420000f, 0x01c7b860, 0x01dfb0fa, 0x01df41dc, + 0x01df61e8, 0x01df41de, 0x01df61ea, 0x01df41e0, + 0x01df61ec, 0x01df41dd, 0x01df61e9, 0x01df41df, + 0x01df61eb, 0x01df41e1, 0x01df61ed, 0xb5000024, + 0x01c7b860, 0x01dfb0f9, 0x01df41dc, 0x01df61e2, + 0x01df41de, 0x01df61e4, 0x01df41e0, 0x01df61e6, + 0x01df41dd, 0x01df61e3, 0x01df41df, 0x01df61e5, + 0x01df41e1, 0x01df61e7, 0x803f0000, 0x00000000, + 0x00000000, 0x01df90fa, 0x003fb80e, 0x00000000, + 0x00000000, 0x81d50000, 0x00000000, 0x00000000, + 0x01df41e8, 0x01df61dc, 0x01df41ea, 0x01df61de, + 0x01df41ec, 0x01df61e0, 0x01df41e9, 0x01df61dd, + 0x01df41eb, 0x01df61df, 0x01df41ed, 0x01df61e1, + 0x029f03a6, 0x029f236a, 0x029f03a7, 0x029f236c, + 0x027f03a2, 0x92b3e128, 0x0298b815, 0x019f03b0, + 0x029f2368, 0x5982b80c, 0x01df03af, 0x85ce000f, + 0x59c6b80e, 0x11cc61b2, 0x82a70001, 0x02bf61b8, + 0x82a70000, 0x02bf61b9, 0x029f41da, 0x029f61ba, + 0x029f41db, 0x029f61bb, 0x019f03b1, 0x5981b80c, + 0x918ce118, 0x0299b80c, 0xad8b0048, 0x029f61af, + 0x59a2b813, 0x118cb80d, 0x928c0868, 0x029fb0fb, + 0x928c0700, 0x029fb0fc, 0x019f41bc, 0x918c0003, + 0x019f61bc, 0x5a02b80b, 0x91900414, 0x029fd80c, + 0x029f236e, 0x808704ec, 0x83a40119, 0x808709d0, + 0x80a709f0, 0x80c70060, 0x00ff03a4, 0x83a400f4, + 0x83a40143, 0x021f037a, 0x019f03a5, 0x300cb810, + 0xb4000016, 0x803f0000, 0x00000000, 0x00000000, + 0x01df90f9, 0x003fb80e, 0x00000000, 0x00000000, + 0x81d50000, 0x00000000, 0x00000000, 0x01df41e2, + 0x01df61dc, 0x01df41e4, 0x01df61de, 0x01df41e6, + 0x01df61e0, 0x01df41e3, 0x01df61dd, 0x01df41e5, + 0x01df61df, 0x01df41e7, 0x01df61e1, 0x029f41b6, + 0xa6d40100, 0xaeb40004, 0x81870000, 0x92b50c00, + 0x0397b815, 0xb6360001, 0x039fa02c, 0x00ffb81c, + 0x009f90cf, 0x00bf0389, 0x019f037a, 0x5982b80c, + 0x918c0340, 0x0397b80c, 0x81870000, 0x039fa00c, + 0x83a4007b, 0x81870000, 0x019f61b5, 0x019f61b4, + 0x81870007, 0x019f61b6, 0x019f03b3, 0x5981b80c, + 0x918ce118, 0x01b9b80c, 0x019f03af, 0x01bf61af, + 0x858c000f, 0x5986b80c, 0x01bf03b2, 0x59a2b80d, + 0x118cb80d, 0x019f61b2, 0x81870000, 0x019f61b7, + 0x019f61b8, 0x808704fc, 0x83a400d1, 0x80870000, + 0x80a70000, 0x80c70000, 0x80e70000, 0x83a400ac, + 0x83a400fb, 0x81470000, 0x81e70c1c, 0x0397b80f, + 0xb600f901, 0x039fa02a, 0x00ffb81c, 0x00000000, + 0x82270000, 0x023f2011, 0x0227b860, 0x023fb0ff, + 0x02bf9006, 0x92350028, 0x8213001f, 0x9210e000, + 0x3011b810, 0xb4800001, 0x86312000, 0x021f4193, + 0x5a01b810, 0x86100028, 0x83a4fa8c, 0x82270000, + 0x003fb811, 0x02bf9006, 0x5aa3b815, 0x82338000, + 0x1a31b815, 0x003fb811, 0x8067e950, 0x5c62b803, + 0x81f50000, 0x80270400, 0xb6000409, 0x814fffc0, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01cfb803, + 0x007f90bc, 0xb520ffff, 0x90210020, 0x90630020, + 0x82870000, 0x81f50010, 0x019f4193, 0x5d61b80c, + 0x5d43b80c, 0x114ab80b, 0x0187b80a, 0x960cff00, + 0x92100100, 0x858c0001, 0xb62c000c, 0x81f50010, + 0x5e28b80f, 0xb6000209, 0x5a48b814, 0x9652ff00, + 0x5e68b814, 0x5981b813, 0x918c1000, 0x01dfd80c, + 0x2252b811, 0x2292b80e, 0x962f00ff, 0x81870000, + 0x86100100, 0xb4e0fff0, 0xb00a0000, 0xb4000009, + 0x81670000, 0xb0140000, 0xb4000001, 0x81670001, + 0x017f2012, 0x258a4193, 0x918c0001, 0x81470000, + 0xb500ffe2, 0x81670000, 0xb0140000, 0xb4000001, + 0x81670002, 0x116b0012, 0x803f0000, 0x00000000, + 0x00000000, 0x003fb811, 0x00000000, 0x00000000, + 0x81f50000, 0x017f2012, 0x00ffb81a, 0x00000000, + 0x61f4b804, 0x91ef0001, 0x8233003f, 0x9a31ffff, + 0x5a02b804, 0x1610b811, 0x92510001, 0x1a10b812, + 0x029f03fb, 0xb0140001, 0xb4200012, 0x5a21b805, + 0x92b1e910, 0x0299b815, 0x5a22b805, 0x5a90b814, + 0x6290b814, 0x92b1e890, 0x11efb814, 0x029bb815, + 0x8233ff80, 0x3011b814, 0xb4000006, 0x4294b811, + 0x00000000, 0x0288b814, 0x4210b814, 0x00000000, + 0x0208b810, 0x029f9003, 0x82f3007f, 0x9af7ffff, + 0x3017b814, 0xb4000003, 0x4210b814, 0x00000000, + 0x0208b810, 0x82270000, 0x02c7b810, 0xb0160000, + 0xb400000a, 0x1676b812, 0x3013b812, 0xb4000003, + 0x5ac1b816, 0x92310001, 0xb500fffa, 0x81d3ff80, + 0x3010b80e, 0xb4200001, 0x1ad6b80e, 0x05efb811, + 0x027f037a, 0x5a62b813, 0x92730340, 0x0397b813, + 0x023fd813, 0x02dfb0fd, 0x5a30b811, 0x6230b811, + 0x0631b80f, 0x3010b812, 0xb4200001, 0x92310001, + 0x82470000, 0xb0110000, 0xb4800004, 0x82470003, + 0xb0110003, 0xb4400001, 0x0247b811, 0x039fa012, + 0x124f61bc, 0x00ffb81d, 0x00000000, 0x00000000, + 0x83970a10, 0x82070000, 0xb6003201, 0x039fa030, + 0xb0070000, 0xb4000019, 0x029f41b4, 0x0297b804, + 0x0317b805, 0x0397b806, 0xb6270014, 0x12948034, + 0x01df8038, 0xb00e0000, 0xb4a0000e, 0x02bf803c, + 0x5a02b814, 0x91b00a10, 0x0217b80d, 0xb62e0008, + 0x96150003, 0x91f00001, 0xadef0080, 0xb0150004, + 0xb4600001, 0x85ef0280, 0x021fa02f, 0x92940001, + 0xb5000001, 0x021f803c, 0x00000000, 0x00ffb81d, + 0x0397b804, 0x021f036a, 0x027f803c, 0x029f803c, + 0x02bf803c, 0x02df803c, 0x5a22b810, 0x92311000, + 0x0397b811, 0xb0100000, 0xb4200001, 0x039fa036, + 0xb0150000, 0xb4000021, 0x0227b860, 0x023fb0ff, + 0xb520ffff, 0x803f0000, 0x82138000, 0x1a10b813, + 0x003fb810, 0x00000000, 0x00000000, 0x82150000, + 0x00000000, 0xb635000d, 0x82550007, 0x5a42b812, + 0x9212e4b8, 0x025bb810, 0x8227000c, 0xb6000307, + 0x68d1b812, 0x94c6000f, 0x84c60002, 0x12d6b806, + 0xb6340001, 0x039fa036, 0x86310004, 0x803f0000, + 0x82138000, 0x023f90ff, 0x1a31b810, 0x003fb811, + 0x00000000, 0x00000000, 0x82150000, 0x00ffb81d, + 0x00ff41b5, 0x011f41b4, 0x019f41af, 0x01bf41ae, + 0x01df41ba, 0x01ff41bb, 0x82070000, 0x023f0380, + 0x82470000, 0xae310032, 0x029f41b3, 0x5862b807, + 0x90431000, 0x81970ad8, 0x0217b802, 0x90430c00, + 0x0297b802, 0x0317b802, 0x912802a4, 0x007ff009, + 0x58478030, 0x792341b6, 0x0529b807, 0x019fa029, + 0xb0080014, 0xb4800011, 0xa5420c00, 0x031fa02a, + 0x84690001, 0xb4a00011, 0xb623000b, 0x58678030, + 0xa4030c00, 0x031fa020, 0x044ab800, 0x0056b802, + 0x5c41b802, 0xf84200ff, 0x90620100, 0x005ff003, + 0x7d40b80a, 0x114ab802, 0xb5000004, 0xa5420c00, + 0x58478010, 0xa5620c00, 0x031fa02a, 0xb0080016, + 0xb4400043, 0xb0080013, 0xb440002c, 0xb0080006, + 0xb4400024, 0xb0080005, 0xb4400014, 0xb0080002, + 0xb4400006, 0x80440030, 0x015f619c, 0x05cab80c, + 0x05eab80d, 0x066eb810, 0xb500003c, 0x8044002a, + 0x300a419c, 0xb4800001, 0x82470001, 0x015f619c, + 0xb0120001, 0xb4200001, 0xb500001a, 0x05cab80c, + 0x05eab80d, 0x066eb810, 0xb5000030, 0x001f41b6, + 0xb0000007, 0xb4000001, 0x8044001b, 0x300a419c, + 0xb4800001, 0x82470001, 0xb0120001, 0xb4200001, + 0xb500000c, 0x05cab80c, 0x05eab80d, 0x066eb810, + 0xb5000022, 0x80440010, 0x840b0100, 0x300ab800, + 0xb4200001, 0x86100040, 0xb5000002, 0x86100080, + 0xfe100000, 0x046e41ad, 0x042ab80c, 0x7dc1b803, + 0x044f41ac, 0x042ab80d, 0x7de1b802, 0x046eb810, + 0x7e6fb803, 0xb5000011, 0x840b0100, 0x3000b80a, + 0xb4200002, 0x82070180, 0x00ffb802, 0x300ab80b, + 0xb4a00002, 0x86100040, 0xfe100000, 0x00ffb802, + 0x046e41ad, 0x042ab80c, 0x7dc1b803, 0x044f41ac, + 0x042ab80d, 0x7de1b802, 0x7e6eb80f, 0x380a41b0, + 0xb4600003, 0x242a41b0, 0x5c22b801, 0x1273b801, + 0xb0140000, 0xb4200002, 0x80071fe0, 0xb5000016, + 0x1011b808, 0x5801b800, 0x9020e26c, 0x0079b801, + 0x5842b808, 0x90420a10, 0x7c03b813, 0x003f9802, + 0x1000b801, 0x003f41b2, 0x5830b801, 0x6030b801, + 0x0400b801, 0x003f41b1, 0x5830b801, 0x6030b801, + 0x0400b801, 0xfc000000, 0xf8001fe0, 0x94001fe0, + 0x100041b1, 0x9400ffff, 0x8067003f, 0xb6290008, + 0x005f8014, 0x0442b800, 0x9442ffff, 0x5850b802, + 0x6050b802, 0xfc420000, 0x5c45b802, 0x7a82a023, + 0x10e7b809, 0x91080001, 0x300741b6, 0xb420ff6a, + 0x019f61af, 0x01bf61ae, 0x01df61ba, 0x01ff61bb, + 0x00ff41b5, 0x011f41b4, 0x019f41b8, 0x01bf41b7, + 0x01df41dd, 0x01ff41df, 0x021f41e1, 0x027f90fd, + 0x029f41bc, 0x02ff41dc, 0x031f41de, 0x033f41e0, + 0x5822b807, 0x91210c00, 0x0117b809, 0x81970ad8, + 0x91211000, 0x0217b809, 0x91210c00, 0x0317b809, + 0x80170ba0, 0x013f802c, 0xb629005f, 0x003f8038, + 0xb001000e, 0xb440001e, 0xb001000c, 0xb4400054, + 0xb001000a, 0xb4400043, 0xb0010007, 0xb440003c, + 0xb0010005, 0xb440002b, 0xb0010000, 0xb440001a, + 0xb00d0001, 0xb4200010, 0x005f418f, 0xac42bb75, + 0x8073005a, 0x9442ffff, 0x005f618f, 0x95628000, + 0x5848b802, 0xb00b8000, 0xb4200002, 0x8173ff00, + 0x1842b80b, 0x9863827a, 0x4043b802, 0x00000000, + 0x0048b802, 0xb500003f, 0x80470000, 0xb500003d, + 0x8401000f, 0x5c22b800, 0x902102d8, 0x001ff001, + 0x004db800, 0xb5000037, 0x86f70001, 0xb4600005, + 0x80750005, 0x5862b803, 0x9043e44c, 0x01d9b802, + 0x82e70002, 0x5c4cb80e, 0x9462000f, 0x5862b803, + 0x90630200, 0x005f9803, 0x59c4b80e, 0x95ceffff, + 0xb5000028, 0x87180001, 0xb4600005, 0x80750007, + 0x5862b803, 0x9043e4b8, 0x01f9b802, 0x83070002, + 0x5c4cb80f, 0x9462000f, 0x5862b803, 0x9063020c, + 0x005f9803, 0x59e4b80f, 0x95efffff, 0xb5000019, + 0x80750003, 0x5862b803, 0x90630220, 0x005f9803, + 0xb5000014, 0x87390001, 0xb4600005, 0x80750007, + 0x5862b803, 0x9043e6ac, 0x0219b802, 0x83270001, + 0x5c4cb810, 0x9462000f, 0x5862b803, 0x9063023c, + 0x005f9803, 0x5a04b810, 0x9610ffff, 0xb5000005, + 0x80750004, 0x5862b803, 0x90630268, 0x005f9803, + 0x00000000, 0x001fa022, 0x80170ba0, 0xb00c0001, + 0xb4200035, 0x023f90fb, 0x007f9811, 0x025f90fc, + 0x06d4b803, 0x007f9812, 0x4083b813, 0x00000000, + 0x0088b804, 0xb629002b, 0x24368030, 0x9421ffff, + 0x5830b801, 0x6030b801, 0x40448020, 0xb0010020, + 0xb4800003, 0x80470000, 0x80670000, 0xb500000e, + 0xb0010000, 0xb4a00004, 0x82b30080, 0x6aa1b815, + 0x4042b815, 0xb5000008, 0x6c41b802, 0x82a70017, + 0x12b5b801, 0x6875b803, 0x1842b803, 0x00000000, + 0x00000000, 0x00000000, 0x0108a022, 0x007f41b9, + 0x90630001, 0x007f61b9, 0xb003000c, 0xb420000c, + 0x92310004, 0x023fb0fb, 0x007f9811, 0x92520004, + 0x06d4b803, 0x025fb0fc, 0x007f9812, 0x80470000, + 0x4083b813, 0x00000000, 0x0088b804, 0x005f61b9, + 0x00000000, 0xb500001a, 0xb6290019, 0x24348030, + 0x9421ffff, 0x5830b801, 0x6030b801, 0x40538020, + 0xb0010020, 0xb4800003, 0x80470000, 0x80670000, + 0xb500000e, 0xb0010000, 0xb4a00004, 0x82b30080, + 0x6aa1b815, 0x4042b815, 0xb5000008, 0x6c41b802, + 0x82a70017, 0x12b5b801, 0x6875b803, 0x1842b803, + 0x00000000, 0x00000000, 0x00000000, 0x0108a022, + 0x10e7b809, 0x91080001, 0x300741b6, 0xb420ff48, + 0x00ff61b5, 0x011f61b4, 0x01df61dd, 0x01ff61df, + 0x021f61e1, 0x02ff61dc, 0x031f61de, 0x033f61e0, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x808f0000, 0x003f9113, 0x005f9114, + 0x7141b802, 0x80cf0700, 0x8027b064, 0x5c22b801, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x80cf0704, 0x8027b06c, 0x5c22b801, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x81e7043c, 0x82071c00, 0x82271c10, + 0x019f03a9, 0x806f001f, 0x80af001f, 0x80270400, + 0x8067a800, 0x5c62b803, 0xb6000808, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01cfb803, 0x007f90bc, + 0xb520ffff, 0x90210020, 0x90630020, 0x81971000, + 0x82170c00, 0xb6000004, 0x003f800c, 0x005f8010, + 0x021fa021, 0x019fa022, 0x00bfd810, 0x003fd811, + 0x70c1b80a, 0x001f980f, 0x91ef0004, 0x92100002, + 0x92310002, 0x5822b805, 0x90411000, 0x0197b802, + 0x90410c00, 0x0217b802, 0x0466b805, 0xb0000000, + 0xb4000005, 0xb6230004, 0x003f8010, 0x005f800c, + 0x1201a022, 0x0581a022, 0x858c0001, 0xb4e0ffea, + 0x80270400, 0x8067ac00, 0x5c62b803, 0xb6000808, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01afb803, + 0x007f90bc, 0xb520ffff, 0x90210020, 0x90630020, + 0x00ffb81c, 0x00000000, 0x00000000, 0x00000000, + 0x808f0000, 0x806f001f, 0x80af001f, 0x003f037a, + 0xb0010000, 0xb4400030, 0x81a7b7fc, 0x5da2b80d, + 0x80670500, 0xb6000208, 0x00cfb803, 0x01bfb0bc, + 0x59a2b80d, 0x01cfb80d, 0x01bf90bc, 0xb520ffff, + 0x90630020, 0x91ad0020, 0x81c7b8fc, 0x5dc2b80e, + 0x80670540, 0xb6000208, 0x00cfb803, 0x01dfb0bc, + 0x59c2b80e, 0x01cfb80e, 0x01df90bc, 0xb520ffff, + 0x90630020, 0x91ce0020, 0x81a7b3fc, 0x5da2b80d, + 0x80670600, 0xb6000408, 0x00cfb803, 0x01bfb0bc, + 0x59a2b80d, 0x01cfb80d, 0x01bf90bc, 0xb520ffff, + 0x90630020, 0x91ad0020, 0x81c7b5fc, 0x5dc2b80e, + 0x80670680, 0xb6000408, 0x00cfb803, 0x01dfb0bc, + 0x59c2b80e, 0x01cfb80e, 0x01df90bc, 0xb520ffff, + 0x90630020, 0x91ce0020, 0x005f03fa, 0xb0020000, + 0xb4000024, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x8257ffff, 0x82d7ffff, 0x8357ffff, + 0x83d7ffff, 0x83971300, 0x83171200, 0x82971100, + 0x82171000, 0x81170c00, 0x81970ff8, 0x80171400, + 0x80971500, 0x005f802c, 0x001f8028, 0xb6004010, + 0x41028000, 0x51008004, 0x007f876c, 0x0208a028, + 0x41008000, 0x49028004, 0x003f8068, 0x0388a028, + 0x41038000, 0x51018004, 0x005f802c, 0x0288a028, + 0x41018020, 0x49038024, 0x001f8028, 0x0308a028, + 0x00ffb81c, 0x83d7ffff, 0x8357ffff, 0x82d7ffff, + 0x8257ffff, 0x8157ffff, 0x81d7ffff, 0x8057ffff, + 0x80d7ffff, 0x82971200, 0x82171000, 0x81170c00, + 0x81970ffc, 0x83171800, 0x83971a00, 0x83370000, + 0x83b70000, 0x81370008, 0x81b7fff8, 0x4119880c, + 0xb6008006, 0x511d8808, 0x41498838, 0x0208a028, + 0x494d883c, 0x4119880c, 0x0288a02a, 0x00ffb81c, + 0x82670000, 0x82a70000, 0x003f037a, 0xb0010000, + 0xb4400018, 0x81a7bdfc, 0x5da2b80d, 0x80670580, + 0xb6000208, 0x00cfb803, 0x01bfb0bc, 0x59a2b80d, + 0x01cfb80d, 0x01bf90bc, 0xb520ffff, 0x90630020, + 0x91ad0020, 0x81a7eb70, 0x5da2b80d, 0x806705c0, + 0xb6000208, 0x00cfb803, 0x01bfb0bc, 0x59a2b80d, + 0x01cfb80d, 0x01bf90bc, 0xb520ffff, 0x90630020, + 0x91ad0020, 0x02bf03fa, 0x808f0000, 0xb0150000, + 0xb4000006, 0x81470040, 0x81670003, 0x81870002, + 0x81a71000, 0x81c71300, 0xb5000005, 0x81470080, + 0x81670004, 0x81870001, 0x81a71000, 0x81c71200, + 0x0017b80d, 0x0097b80e, 0x108db80a, 0x0117b804, + 0x108eb80a, 0x0197b804, 0x5841b80a, 0x108db802, + 0x0217b804, 0x108eb802, 0x0297b804, 0x106ab802, + 0x108db803, 0x0317b804, 0x108eb803, 0x0397b804, + 0x5ea2b80a, 0xb6350020, 0x001f8000, 0x003f8008, + 0x005f8004, 0x007f800c, 0x10c08010, 0x10a18018, + 0x10828014, 0x10e3801c, 0x1246b805, 0x0686b805, + 0x10c4b807, 0x0484b807, 0x80e70000, 0x80a70000, + 0x0008a032, 0x0108a034, 0x0088a026, 0x0188a024, + 0x04c08010, 0x04a18018, 0x04828014, 0x04e3801c, + 0x0646b807, 0x1286b807, 0x10c4b805, 0x0484b805, + 0x80e70000, 0x80a70000, 0x0208a032, 0x0308a034, + 0x0288a026, 0x0388a024, 0x5de1b80a, 0x82070004, + 0xb62b002a, 0x0017b80d, 0x0097b80e, 0x102db80f, + 0x0117b801, 0x104eb80f, 0x0197b802, 0x82171600, + 0x82971700, 0x0037b80f, 0x00b7b80f, 0x0137b80f, + 0x01b7b80f, 0xb630001b, 0x003f8030, 0x005f8034, + 0x5ee2b80f, 0x8013007f, 0x9800ffff, 0xb6370011, + 0x41008000, 0x51018008, 0x4902800c, 0x40c08000, + 0x0008a028, 0x48c18008, 0x50c2800c, 0x42808004, + 0x00c8b806, 0x52828008, 0x5281800c, 0x41008004, + 0x0088a034, 0x49028008, 0x4901800c, 0x011fa026, + 0x0188a028, 0x001f8001, 0x001f8005, 0x001f8009, + 0x001f800d, 0x5de1b80f, 0x5a01b810, 0x0017b80d, + 0x0097b80e, 0x902d0004, 0x0117b801, 0x904e0004, + 0x0197b802, 0x82171600, 0x82971700, 0x5ea1b80a, + 0x8013007f, 0x9800ffff, 0xb6350013, 0x003f8030, + 0x005f8034, 0x42408000, 0x52418008, 0x4a42800c, + 0x41008000, 0x0008a052, 0x49018008, 0x5102800c, + 0x42808004, 0x0108b808, 0x52828008, 0x5281800c, + 0x40c08004, 0x0088a054, 0x48c28008, 0x48c1800c, + 0x011fa048, 0x0188a046, 0x81a71100, 0x81c71200, + 0x858c0001, 0xb4e0ff7e, 0x00ffb81c, 0x00000000, + 0x005f03fa, 0x00000000, 0xb0020000, 0xb4000034, + 0x81b70080, 0x81d7ffff, 0x81f70001, 0x82370080, + 0x8257ffff, 0x82770001, 0x82b70080, 0x82d7ffff, + 0x82f70001, 0x83370080, 0x8357ffff, 0x83770001, + 0x81971000, 0x82171100, 0x82971200, 0x83171300, + 0x815703fc, 0x81370200, 0x81170c00, 0x83d703fc, + 0x83b70200, 0x83970f00, 0x8057ffff, 0x80d7ffff, + 0x80171400, 0x80971500, 0x001f800d, 0x003f8019, + 0xb6004012, 0x41008000, 0x51018004, 0x007f8011, + 0x0128a008, 0x41018000, 0x49008004, 0x009f8015, + 0x03a8a008, 0x41038000, 0x51048004, 0x001f800d, + 0x03a8a008, 0x41048020, 0x49038024, 0x003f8019, + 0x0128a008, 0x005f8028, 0x005f803c, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x00ffb81c, + 0x82370040, 0x8257ffff, 0x82770001, 0x82b70040, + 0x82d7ffff, 0x82f70001, 0x82171000, 0x82971200, + 0x8157ffff, 0x81170c00, 0x81d7ffff, 0x81970e00, + 0x8057ffff, 0x80d7ffff, 0x80171800, 0x80971a00, + 0xb600800a, 0x001f8011, 0x003f8015, 0x41008000, + 0x51018004, 0x00000000, 0x0108a028, 0x41018020, + 0x49008024, 0x00000000, 0x0188a028, 0x82770000, + 0x82f70000, 0x00ffb81c, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x808f0000, + 0x015f0384, 0x017f037a, 0xac4a0006, 0x8027b004, + 0x1042b80b, 0x5841b802, 0x1021b802, 0x0159b801, + 0x013f0325, 0x01bf0320, 0x5822b80b, 0x90210340, + 0x00ff9801, 0x8027b2e8, 0x5842b807, 0x1021b802, + 0x025bb801, 0x80070000, 0xac4d0006, 0x8027b004, + 0x1042b800, 0x5841b802, 0x1021b802, 0x0199b801, + 0x00000000, 0xac4c0006, 0x8027b078, 0x1042b80a, + 0x5842b802, 0x1021b802, 0x011bb801, 0x00000000, + 0x40d2b808, 0x00000000, 0xb0060000, 0xb4000080, + 0x005f033b, 0x80278400, 0xac600080, 0x5c22b801, + 0x10a1b803, 0xb0020000, 0xb4200002, 0x80279000, + 0xb5000001, 0x80279c00, 0x5c22b801, 0x11e1b803, + 0x80470300, 0x5822b800, 0x1042b801, 0x003f9802, + 0x806f001f, 0x80af001f, 0xb0010000, 0xb4200024, + 0x80170c00, 0x80971000, 0x003f8020, 0xb6000003, + 0x4201b806, 0x003f8020, 0x0088a030, 0x80270400, + 0xb6000208, 0x00cfb801, 0x00bfb0bc, 0x58a2b805, + 0x01afb805, 0x00bf90bc, 0xb520ffff, 0x90210020, + 0x90a50020, 0xb6000408, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x90210020, 0x91ef0020, 0xb6000208, 0x00cfb801, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x90210020, 0x90a50020, 0xb5000043, + 0x80270400, 0x0087b805, 0x01c7b80f, 0xb6000208, + 0x00cfb801, 0x009fb0bc, 0x5882b804, 0x01cfb804, + 0x009f90bc, 0xb520ffff, 0x90210020, 0x90840020, + 0xb6000408, 0x00cfb801, 0x01dfb0bc, 0x59c2b80e, + 0x01cfb80e, 0x01df90bc, 0xb520ffff, 0x90210020, + 0x91ce0020, 0xb6000208, 0x00cfb801, 0x009fb0bc, + 0x5882b804, 0x01cfb804, 0x009f90bc, 0xb520ffff, + 0x90210020, 0x90840020, 0x80170c00, 0x80971000, + 0x8053007f, 0x9842ffff, 0xb6000004, 0x42028004, + 0x4a068020, 0x00000000, 0x0088a030, 0x80270400, + 0xb6000208, 0x00cfb801, 0x00bfb0bc, 0x58a2b805, + 0x01afb805, 0x00bf90bc, 0xb520ffff, 0x90210020, + 0x90a50020, 0xb6000408, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x90210020, 0x91ef0020, 0xb6000208, 0x00cfb801, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x90210020, 0x90a50020, 0x5822b800, + 0x90210300, 0x0117b801, 0x80470001, 0x011fa002, + 0x90000001, 0x3000b809, 0xb480ff6b, 0x00ffb81c, + 0x8057ffff, 0x013f0325, 0x015f033b, 0x80171000, + 0x80070000, 0xb6002001, 0x001fa020, 0xb00a0001, + 0xb4c00002, 0x81679000, 0xb5000001, 0x81679c00, + 0x5d62b80b, 0x81878400, 0x5d82b80c, 0x80070000, + 0x5822b800, 0x90410300, 0x003f9802, 0x00000000, + 0xb0010000, 0xb4200019, 0xac400080, 0x00000000, + 0x10ccb802, 0x10abb802, 0x806f001f, 0x80af001f, + 0x80cf0400, 0xb6000408, 0xb520ffff, 0x00dfb0bc, + 0x58c2b806, 0x01afb806, 0x00df90bc, 0xb520ffff, + 0x80cf0400, 0x90c60020, 0x80cf0400, 0xb6000407, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x80cf0400, 0x90a50020, 0x90000001, + 0x3000b809, 0xb480ffde, 0x00ffb81b, 0x8057ffff, + 0x013f0325, 0x80171000, 0x80070000, 0xb6002001, + 0x001fa020, 0x81878400, 0x5d82b80c, 0x80070000, + 0x5822b800, 0x90410300, 0x003f9802, 0x00000000, + 0xb0010000, 0xb420000f, 0xac400080, 0x00000000, + 0x10ccb802, 0x806f001f, 0x80af001f, 0x80cf0400, + 0xb6000408, 0xb520ffff, 0x00dfb0bc, 0x58c2b806, + 0x01afb806, 0x00df90bc, 0xb520ffff, 0x80cf0400, + 0x90c60020, 0x90000001, 0x3000b809, 0xb480ffe8, + 0x00ffb81b, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x8139b000, 0x00000000, 0xb0090000, 0xb4000012, + 0x806f001f, 0x80af001f, 0x80cf0400, 0x013fb0bc, + 0x5922b809, 0x01cfb809, 0x013f90bc, 0xb520ffff, + 0x806f0003, 0x80af0003, 0x80cf0420, 0x91290020, + 0x013fb0bc, 0x5922b809, 0x01cfb809, 0x013f90bc, + 0xb520ffff, 0xb5000233, 0x80270000, 0x80171000, + 0xb6002401, 0x001fa021, 0x007f0384, 0x009f0320, + 0x00bf0385, 0x00df0386, 0x80e7b36c, 0x5821b803, + 0x1021b807, 0x0159b801, 0x5821b804, 0x1021b807, + 0x0179b801, 0x80e7b37c, 0x5821b803, 0x1021b807, + 0x0199b801, 0x5821b804, 0x1021b807, 0x01b9b801, + 0x80e7b38c, 0x5821b803, 0x1021b807, 0x01d9b801, + 0x5821b804, 0x1021b807, 0x01f9b801, 0x005f0385, + 0x8027b39c, 0x5842b802, 0x1021b802, 0x021bb801, + 0x005f0386, 0x8027b3ac, 0x5842b802, 0x1021b802, + 0x023bb801, 0x027f0383, 0x003f0328, 0x005f4195, + 0xb0130007, 0xb42000df, 0xb0010000, 0xb42000dd, + 0xb0020000, 0xb40000db, 0xb0030002, 0xb48000d9, + 0x029bb802, 0x82a7b108, 0xb00b0001, 0xb4200001, + 0xb5000005, 0xb00b0002, 0xb4200002, 0x92b500a0, + 0xb5000001, 0x92b50140, 0xb0030004, 0xb4600002, + 0x82870000, 0xb5000006, 0xb0030006, 0xb4600004, + 0xb0140001, 0xb4a00002, 0x82870001, 0xb5000000, + 0xac54000a, 0x806f0009, 0x80af0009, 0x5c22b815, + 0x80cf0440, 0x1021b802, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0xb0030003, + 0xb400000f, 0xb0030004, 0xb400001d, 0xb0030005, + 0xb400002b, 0xb0030006, 0xb4000042, 0xb0030007, + 0xb4000059, 0x80171000, 0x005f9440, 0x001fa002, + 0x80171038, 0x005f9440, 0x001fa002, 0xb5000073, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171004, + 0x005f9443, 0x001fa002, 0x8017101c, 0x005f9446, + 0x001fa002, 0x80171034, 0x005f9449, 0x001fa002, + 0x80171038, 0x005f9440, 0x001fa002, 0xb5000063, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171008, + 0x005f9441, 0x001fa002, 0x80171020, 0x005f9444, + 0x001fa002, 0x80171034, 0x005f9440, 0x001fa002, + 0x80171038, 0x005f9447, 0x001fa002, 0xb5000053, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171004, + 0x005f9443, 0x001fa002, 0x8017100c, 0x005f9441, + 0x001fa002, 0x8017101c, 0x005f9446, 0x001fa002, + 0x80171024, 0x005f9444, 0x001fa002, 0x80171034, + 0x005f9449, 0x001fa002, 0x80171038, 0x005f9440, + 0x001fa002, 0x8017103c, 0x005f9447, 0x001fa002, + 0xb500003a, 0x80171000, 0x005f9440, 0x001fa002, + 0x80171008, 0x005f9441, 0x001fa002, 0x8017100c, + 0x005f9442, 0x001fa002, 0x80171020, 0x005f9444, + 0x001fa002, 0x80171024, 0x005f9445, 0x001fa002, + 0x80171034, 0x005f9440, 0x001fa002, 0x80171038, + 0x005f9447, 0x001fa002, 0x8017103c, 0x005f9448, + 0x001fa002, 0xb5000021, 0x80171000, 0x005f9440, + 0x001fa002, 0x80171004, 0x005f9443, 0x001fa002, + 0x8017100c, 0x005f9441, 0x001fa002, 0x80171010, + 0x005f9442, 0x001fa002, 0x8017101c, 0x005f9446, + 0x001fa002, 0x80171024, 0x005f9444, 0x001fa002, + 0x80171028, 0x005f9445, 0x001fa002, 0x80171034, + 0x005f9449, 0x001fa002, 0x80171038, 0x005f9440, + 0x001fa002, 0x8017103c, 0x005f9447, 0x001fa002, + 0x80171040, 0x005f9448, 0x001fa002, 0x80270001, + 0x803eff90, 0x80171000, 0x82b30020, 0x9ab50000, + 0x40158020, 0xb6000501, 0x48158020, 0x82b30020, + 0x9ab50000, 0x80470000, 0x3015b800, 0xb4600006, + 0x80171000, 0x83840226, 0xb6000603, 0x40028000, + 0x00000000, 0x0008a020, 0x80171018, 0x82b30020, + 0x9ab50000, 0x40158020, 0xb6000501, 0x48158020, + 0x82b30020, 0x9ab50000, 0x80470000, 0x3015b800, + 0xb4600006, 0x80171018, 0x83840215, 0xb6000603, + 0x40028000, 0x00000000, 0x0008a020, 0x80171030, + 0x82b30020, 0x9ab50000, 0x40158020, 0xb6000501, + 0x48158020, 0x82b30020, 0x9ab50000, 0x80470000, + 0x3015b800, 0xb4600006, 0x80171030, 0x83840204, + 0xb6000603, 0x40028000, 0x00000000, 0x0008a020, + 0xb500011e, 0x80270000, 0x803eff90, 0xb0030000, + 0xb4200067, 0x025f0322, 0xb00b0001, 0xb4200016, + 0xb0120001, 0xb4200005, 0x80171018, 0x8033007f, + 0x9821ffff, 0x001fa001, 0xb5000110, 0xb0120002, + 0xb4200005, 0x80171020, 0x8033007f, 0x9821ffff, + 0x001fa001, 0xb5000109, 0x80171018, 0x80330040, + 0x98210000, 0x001fa001, 0x80171020, 0x00000000, + 0x001fa001, 0xb5000101, 0xb00b0002, 0xb420002c, + 0xb0120000, 0xb4200008, 0x80171000, 0x8033007f, + 0x9821ffff, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000f5, 0xb0120001, 0xb4200008, + 0x80171000, 0x8033005a, 0x98218279, 0x001fa001, + 0x80171030, 0x00000000, 0x001fa001, 0xb50000eb, + 0xb0120002, 0xb4200008, 0x80171008, 0x8033005a, + 0x98218279, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000e1, 0x80171000, 0x80330040, + 0x98210000, 0x001fa001, 0x80171008, 0x00000000, + 0x001fa001, 0x8017100c, 0x00000000, 0x001fa001, + 0x80171038, 0x00000000, 0x001fa001, 0xb50000d3, + 0xb0120000, 0xb4200008, 0x80171000, 0x8033007f, + 0x9821ffff, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000c9, 0xb0120001, 0xb4200005, + 0x80171018, 0x8033007f, 0x9821ffff, 0x001fa001, + 0xb50000c2, 0xb0120002, 0xb4200005, 0x80171020, + 0x8033007f, 0x9821ffff, 0x001fa001, 0xb50000bb, + 0x80171018, 0x80330040, 0x98210000, 0x001fa001, + 0x80171020, 0x00000000, 0x001fa001, 0xb50000b3, + 0x80070000, 0x8033007f, 0x9821ffff, 0xb600050e, + 0x144eb80f, 0xb0028000, 0xb4c00008, 0xac400006, + 0x00000000, 0x1042b800, 0x5842b802, 0x90421000, + 0x0017b802, 0x00000000, 0x001fa001, 0x90000001, + 0x59c1b80e, 0x59e1b80f, 0xb0040000, 0xb4200023, + 0xb00a0002, 0xb4000007, 0x80171004, 0x8033005a, + 0x98218279, 0x001fa001, 0x80171034, 0x00000000, + 0x001fa001, 0xb00c0002, 0xb4000009, 0x8017100c, + 0x8033ffa5, 0x98217d87, 0x001fa001, 0x8017103c, + 0x8033005a, 0x98218279, 0x001fa001, 0xb500008b, + 0x8017100c, 0x8033ffa5, 0x98217d87, 0x001fa001, + 0x80171010, 0x00000000, 0x001fa001, 0x8017103c, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171040, + 0x00000000, 0x001fa001, 0xb500007c, 0xb0040001, + 0xb420002a, 0xb00a0001, 0xb4000007, 0x80171018, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171020, + 0x00000000, 0x001fa001, 0xb00a0003, 0xb420000a, + 0x8053005a, 0x98428279, 0x4030b802, 0x8017101c, + 0x5821b801, 0x00000000, 0x00000000, 0x00000000, + 0x0028b801, 0x001fa001, 0xb00c0001, 0xb4200007, + 0x8053005a, 0x98428279, 0x4031b802, 0x80171024, + 0x0028b801, 0x001fa001, 0xb500005c, 0xb00c0002, + 0xb420005a, 0x8053005a, 0x98428279, 0x4031b802, + 0x80171024, 0x0028b801, 0x001fa001, 0x80171028, + 0x00000000, 0x001fa001, 0xb5000050, 0xb00b0002, + 0xb4200012, 0xb00a0001, 0xb4200008, 0x80171004, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171034, + 0x00000000, 0x001fa001, 0xb5000008, 0xb00a0003, + 0xb4200006, 0x80171004, 0x00000000, 0x001fa010, + 0x80171034, 0x00000000, 0x001fa010, 0xb00c0001, + 0xb4200025, 0x027f0383, 0x003f0328, 0xb0130007, + 0xb420000b, 0xb00b0003, 0xb4200009, 0xb0010000, + 0xb4200007, 0x80171024, 0x00000000, 0x001fa011, + 0x80171054, 0x80270000, 0x001fa001, 0xb500002b, + 0xb00d0000, 0xb420000a, 0x8033005a, 0x98218279, + 0x4041b811, 0x8017100c, 0x0048b802, 0x001fa002, + 0x8017103c, 0x00000000, 0x001fa002, 0xb500001f, + 0xb00d0002, 0xb420001d, 0x80171054, 0x8033005a, + 0x98218279, 0x001fa001, 0x8017106c, 0x00000000, + 0x001fa001, 0xb5000015, 0xb00c0002, 0xb4200013, + 0xb00d0000, 0xb4200007, 0x8017100c, 0x00000000, + 0x001fa011, 0x80171040, 0x00000000, 0x001fa011, + 0xb500000a, 0xb00d0001, 0xb4200008, 0x80171054, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171058, + 0x00000000, 0x001fa001, 0xb5000000, 0x029f0388, + 0x02bf0321, 0xb0140000, 0xb4000006, 0xb0150000, + 0xb4000004, 0x8017108c, 0x8033007f, 0x9821ffff, + 0x001fa001, 0x8027b078, 0x5c22b801, 0x806f001f, + 0x80af001f, 0x80cf0400, 0x003fb0bc, 0x5822b801, + 0x01afb801, 0x003f90bc, 0xb520ffff, 0x90210020, + 0x806f0003, 0x80af0003, 0x80cf0420, 0x003fb0bc, + 0x5822b801, 0x01afb801, 0x003f90bc, 0xb520ffff, + 0x81270000, 0x8033007f, 0x9821ffff, 0x80171000, + 0xb600060a, 0x80470000, 0xb6000603, 0x015f8020, + 0x0156b80a, 0x1042b80a, 0x3002b801, 0xb4a00001, + 0x81270001, 0x00000000, 0x00000000, 0x015f0323, + 0x00000000, 0xb00a0000, 0xb4200002, 0x81670000, + 0xb5000001, 0x81670001, 0x017f23fb, 0x01ff41ee, + 0x59f0b80f, 0x61f0b80f, 0x021f41ef, 0x5a10b810, + 0x6210b810, 0xb00a0003, 0xb420003b, 0x017f039f, + 0x019f41c5, 0x5990b80c, 0x6190b80c, 0xb00b0000, + 0xb400000c, 0xb00c0000, 0xb4000005, 0xac4c0100, + 0x8033001d, 0x98215500, 0x12c1b802, 0xb500000f, + 0xac4f0100, 0x8033001d, 0x98215500, 0x12c1b802, + 0xb500000a, 0xb0090000, 0xb4000005, 0xac4f0100, + 0x8033ffe2, 0x9821ab00, 0x12c1b802, 0xb5000003, + 0xac4f0100, 0x00000000, 0x02c7b802, 0xb0030000, + 0xb420007e, 0x01bf03a0, 0x01df41c9, 0x59d0b80e, + 0x61d0b80e, 0xb00d0000, 0xb400000c, 0xb00e0000, + 0xb4000005, 0xac4e0100, 0x8033001d, 0x98215500, + 0x12e1b802, 0xb5000071, 0xac500100, 0x8033001d, + 0x98215500, 0x12e1b802, 0xb500006c, 0xb0090000, + 0xb4000005, 0xac500100, 0x8033ffe2, 0x9821ab00, + 0x12e1b802, 0xb5000065, 0xac500100, 0x00000000, + 0x02e7b802, 0xb5000061, 0xb00a0002, 0xb420002f, + 0x023f9002, 0x025f9001, 0xb00f0000, 0xb4a00007, + 0xac4f0100, 0x00000000, 0x4022b811, 0x00000000, + 0x0028b801, 0x02c7b801, 0xb500000c, 0xb0090000, + 0xb4000004, 0xac4f0100, 0x00000000, 0x02c7b802, + 0xb5000006, 0xac4f0100, 0x00000000, 0x4022b812, + 0x00000000, 0x0028b801, 0x02c7b801, 0xb0030000, + 0xb4200046, 0xb0100000, 0xb4a00007, 0xac500100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02e7b801, 0xb500003d, 0xb0090000, 0xb4000004, + 0xac500100, 0x00000000, 0x02e7b802, 0xb5000037, + 0xac500100, 0x00000000, 0x4022b812, 0x00000000, + 0x0028b801, 0x02e7b801, 0xb5000030, 0x023f9002, + 0x025f9001, 0xb00f0000, 0xb4a00007, 0xac4f0100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02c7b801, 0xb5000006, 0xac4f0100, 0x00000000, + 0x4022b812, 0x00000000, 0x0028b801, 0x02c7b801, + 0xb0090000, 0xb4000005, 0x0047b816, 0x8033ffe2, + 0x9821ab00, 0x1042b801, 0x02c7b802, 0xb0030000, + 0xb4200016, 0xb0100000, 0xb4a00007, 0xac500100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02e7b801, 0xb5000006, 0xac500100, 0x00000000, + 0x4022b812, 0x00000000, 0x0028b801, 0x02e7b801, + 0xb0090000, 0xb4000005, 0x0047b817, 0x8033ffe2, + 0x9821ab00, 0x1042b801, 0x02e7b802, 0x00000000, + 0x00000000, 0x02c8b816, 0x02dfb0cf, 0xb0030000, + 0xb4200002, 0x02e8b817, 0x02ffb0c6, 0x00ffb81b, + 0xb6001807, 0x5841b802, 0x3015b800, 0xb4800002, + 0x06b5b800, 0x98420001, 0x5aa1b815, 0x00000000, + 0x00ffb81c, 0x00000000, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815bb3f0, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717f4, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00029, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200001, + 0x8384026c, 0x80af001f, 0x808f0000, 0x806f0000, + 0x80670400, 0x5d22b80a, 0xb600180a, 0x00cfb803, + 0x013fb0bc, 0x5922b809, 0x01afb809, 0x013f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x91290020, 0x801bb3f8, 0x80270001, 0xb0000001, + 0xb4000002, 0x802600a0, 0x803eb3f8, 0x81270c00, + 0xb00a0000, 0xb4000001, 0x81270000, 0x813eb3f0, + 0x80270001, 0x003f2013, 0x00ffb81b, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009d, 0x9a940008, 0x8286009d, + 0x8285009c, 0x96b48000, 0xb0158000, 0xb40001b5, + 0x96b40100, 0xb0150100, 0xb400020c, 0x96b40400, + 0xb0150400, 0xb400020d, 0x96b40001, 0xb0150001, + 0xb400000c, 0x96b40008, 0xb0150008, 0xb40001ad, + 0x96b44000, 0xb0154000, 0xb400020c, 0x96b40002, + 0xb0150002, 0xb4000182, 0x00000000, 0x00000000, + 0xb500021e, 0x02bf9017, 0x92b50001, 0x02bfb017, + 0x82850082, 0x96f40001, 0xb0170000, 0xb4000171, + 0x5efdb814, 0x96f70001, 0xb0170001, 0xb420000b, + 0x83050069, 0x9718003f, 0x82e50064, 0x12f7b818, + 0x86f70109, 0x82feff74, 0x02e7b86f, 0x9af74000, + 0x01ffb817, 0x96f7bfff, 0x01ffb817, 0x83050081, + 0x82a5009a, 0x96b50001, 0xb0150001, 0xb4200014, + 0x82a70000, 0x02bfb017, 0x96b41840, 0xb0150800, + 0xb420000c, 0x96b40008, 0x5aa9b815, 0x96d46000, + 0x5ec3b816, 0x82f3000f, 0x9af7c00f, 0x1718b817, + 0x1ab5b818, 0x1ab5b816, 0x9ab50340, 0x82a60081, + 0xb500014c, 0x9b180180, 0x83060081, 0xb5000149, + 0x82a5009a, 0x96b50002, 0xb0150002, 0xb420001b, + 0x82a70000, 0x02bfb017, 0x96b41800, 0xb0151800, + 0xb4000013, 0x96b40040, 0xb0150040, 0xb4200004, + 0xa3180c00, 0x9b180340, 0x83060081, 0xb5000139, + 0x96b40008, 0x5aa9b815, 0x96d46000, 0x5ec3b816, + 0x82f3000f, 0x9af7c00f, 0x1718b817, 0x1ab5b818, + 0x1ab5b816, 0x9ab50340, 0x82a60081, 0xb500012d, + 0x9b180180, 0x83060081, 0xb500012a, 0x82a500c1, + 0x96b5000f, 0xb015000b, 0xb420000e, 0x96b40020, + 0xb0150020, 0xb400000b, 0x96b40200, 0xb0150200, + 0xb4000008, 0x82c50086, 0x82e50094, 0x3016b817, + 0xb4400004, 0x06f7b816, 0xb017ff00, 0xb4400001, + 0xb5000118, 0x96b46000, 0xb0156000, 0xb4000011, + 0x96b41820, 0xb0150820, 0xb4200004, 0x9b391000, + 0x82a5009a, 0x96b5feff, 0x82a6009a, 0x96b40040, + 0xb0150040, 0xb4200001, 0x9739efff, 0x96b91000, + 0xb0151000, 0xb4200003, 0x82a5009a, 0x9ab50100, + 0x82a6009a, 0x96b40040, 0xb0150040, 0xb4200019, + 0x96b41800, 0xb0151800, 0xb4200006, 0x96b98000, + 0xb0158000, 0xb4200003, 0x9b180180, 0x83060081, + 0xb50000f8, 0x96d80c00, 0x82b300ff, 0x9ab5f3ff, + 0x1718b815, 0xb0160c00, 0xb4000007, 0x82e50098, + 0x96f70400, 0xb0170400, 0xb4200002, 0x82c70c00, + 0xb5000001, 0xa2d60c00, 0x1b18b816, 0x9b180340, + 0xb50000c4, 0x96b40220, 0xb0150000, 0xb4e00021, + 0x82a5009d, 0x82f3ffff, 0x16b5b817, 0x82f33800, + 0x3015b817, 0xb420001b, 0x96f98000, 0xb0178000, + 0xb4000018, 0x82a70000, 0x02bfb017, 0x82c5009d, + 0x96d6ffff, 0x82b3c800, 0x9ab58001, 0x82e500c1, + 0x96f7000f, 0xb017000b, 0xb4000002, 0x82b38800, + 0x9ab58001, 0x1ab5b816, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b3c800, 0x9ab58001, + 0x82a6009d, 0x02ff9017, 0x00000000, 0xb0170040, + 0xb4800000, 0x5eb5b814, 0x96b500f0, 0x96f46000, + 0x5eedb817, 0x1ab5b817, 0xb0170003, 0xb4000004, + 0x96b500ef, 0x96f70001, 0x5ae4b817, 0x1ab5b817, + 0x96d41800, 0xb0161800, 0xb400000a, 0x96f900ff, + 0x96b500ff, 0x9739ff00, 0x1b39b815, 0x02a7b817, + 0x96b500f3, 0x96d40008, 0x5ec1b816, 0x1ab5b816, + 0xb500000c, 0x96f98000, 0xb0178000, 0xb4200007, + 0x5efeb814, 0x96f70001, 0xb0170001, 0xb4000003, + 0x9b180180, 0x83060081, 0xb50000a2, 0x96b500f3, + 0x9ab50008, 0x9739fff3, 0x96d40020, 0xb0160020, + 0xb4200019, 0x82c7001f, 0x82c600c9, 0x9b398000, + 0x82c70000, 0x02dfb017, 0x96d40010, 0x5ac8b816, + 0x82f300ff, 0x9af7cfff, 0x1718b817, 0x1b18b816, + 0x9b180340, 0x82c5009d, 0x96d6ffff, 0x82f33800, + 0x9af78001, 0x1af7b816, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82f3c800, 0x9af78001, + 0x82e6009d, 0xb500005f, 0x97397fff, 0x96b500ff, + 0x5aaab815, 0x82f300fc, 0x9af703ff, 0x1718b817, + 0x1b18b815, 0x9b180340, 0x82c5009a, 0x96d60010, + 0xb0160010, 0xb4200027, 0x82c70000, 0x02dfb017, + 0x82c50086, 0x92d60bb8, 0x82c60086, 0x82c50094, + 0x5eefb818, 0x96f70003, 0xb0170003, 0xb4200002, + 0x82e70bb8, 0xb5000001, 0x82e70bb8, 0x12d6b817, + 0x82e50081, 0x9af70020, 0x82e60081, 0x82c60094, + 0xa2f70020, 0x82e60081, 0x82f30001, 0x16f7b818, + 0x5ef0b817, 0xb0170001, 0xb4000004, 0x96f84000, + 0x5ee4b817, 0x9718f3ff, 0x1b18b817, 0x82f32800, + 0x9af78000, 0x82e6009d, 0x83060081, 0x83070001, + 0x8306009f, 0x8305009c, 0xb0180001, 0xb4e0fffb, + 0xb50000f6, 0x82c5009d, 0x82f33800, 0x9af78001, + 0x3016b817, 0xb420000f, 0x82b3c800, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b38800, 0x9ab58001, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b3c800, 0x9ab58001, + 0x82a6009d, 0x82c5009a, 0x96d60080, 0xb0160080, + 0xb4000013, 0x02df9017, 0x00000000, 0xb0160010, + 0xb480000f, 0x82c500c1, 0x96d6000f, 0xb016000b, + 0xb400000b, 0x82c50087, 0x96d60080, 0x5ac7b816, + 0x82c50098, 0x96d60800, 0x5ac3b816, 0x96f84000, + 0x3017b816, 0xb4200002, 0x033f400f, 0x9b394000, + 0x9739bfff, 0x82e50061, 0x96f70008, 0xb0170008, + 0xb4000005, 0x5eefb818, 0x96f70003, 0xb0170003, + 0xb4000001, 0x9718ffff, 0x96b41800, 0xb0151800, + 0xb4000008, 0x5eb9b814, 0x96b5000f, 0x82c50099, + 0x5ed0b816, 0x96f6000f, 0x5ab0b815, 0x82a60099, + 0xb5000002, 0x5ef9b814, 0x96f7000f, 0x5aecb817, + 0x82c5009a, 0x96d60fff, 0x1ad6b817, 0x82c6009a, + 0x96b46000, 0xb0156000, 0xb4200005, 0x5ae2b817, + 0x82d30ffc, 0x9ad63fff, 0x1718b816, 0x1b18b817, + 0x83060081, 0x83070001, 0x8306009f, 0x8305009c, + 0xb0180001, 0xb4e0fffb, 0x00000000, 0xb500009f, + 0x82850083, 0x96b400ff, 0xb015003c, 0xb4200019, + 0x96b92000, 0xb0152000, 0xb4000002, 0x9b392000, + 0xb5000014, 0x9739d3ff, 0x82870000, 0x82860087, + 0x82870008, 0x82860083, 0x829bff78, 0x82a7001f, + 0xb0140400, 0xb4000001, 0x82a70010, 0x82a600c9, + 0x829bff78, 0x00000000, 0x828600cb, 0x8285009d, + 0x82b3ffff, 0x9ab5fffd, 0x1694b815, 0x8286009d, + 0xb5000000, 0x83070002, 0x8306009f, 0x00000000, + 0xb500007e, 0x83078000, 0x8306009f, 0x00000000, + 0xb500007a, 0x82850094, 0x82a50086, 0x06b5b814, + 0x02b6b815, 0xb0151700, 0xb440004c, 0x8285006c, + 0x969400ff, 0xb0140024, 0xb4000019, 0xb0140012, + 0xb4000017, 0x8285009a, 0x5eedb814, 0x96f70003, + 0xb0170003, 0xb4000009, 0x82a50083, 0x5ea8b815, + 0x96b500ff, 0xb0150020, 0xb4400002, 0x82c70bbc, + 0xb5000001, 0x82c70bb8, 0xb5000008, 0x82a50083, + 0x5ea8b815, 0x96b500ff, 0xb0150020, 0xb4400002, + 0x82c71199, 0xb5000001, 0x82c71197, 0xb5000017, + 0xb500002e, 0x8285009a, 0x5eedb814, 0x96f70003, + 0xb0170003, 0xb4000009, 0x82a50083, 0x5ea8b815, + 0x96b500ff, 0xb0150020, 0xb4400002, 0x82c70e12, + 0xb5000001, 0x82c70e0e, 0xb5000008, 0x82a50083, + 0x5ea8b815, 0x96b500ff, 0xb0150020, 0xb4400002, + 0x82c70e12, 0xb5000001, 0x82c70e0e, 0x82e50086, + 0x12f7b816, 0x02bf9017, 0xb0150020, 0xb480000b, + 0x82a5009a, 0x96b56000, 0xb0156000, 0xb4000007, + 0x82a50098, 0x96d50a00, 0xb0160a00, 0xb4000002, + 0xb0160000, 0xb4200001, 0x92f705dc, 0x82850081, + 0x9ab40020, 0x82a60081, 0x82c50094, 0x82e60094, + 0x82860081, 0x86b705dc, 0x82a6009b, 0x83070008, + 0x8306009f, 0x00000000, 0xb5000024, 0x83070100, + 0x8306009f, 0x00000000, 0xb5000020, 0x83070000, + 0x83050081, 0x9b180180, 0x83060081, 0x83070400, + 0x8306009f, 0x00000000, 0xb5000018, 0x82870000, + 0x82850082, 0x5eb7b814, 0x96b500fc, 0x96d40006, + 0x5ec1b816, 0x1ab5b816, 0x5aacb815, 0x83050081, + 0x82d3001c, 0x9ad600ff, 0x1718b816, 0x1b18b815, + 0x9b180e00, 0x83060081, 0x83074000, 0x8306009f, + 0x8305009d, 0x82d3ffff, 0x9ad6bfff, 0x1718b816, + 0x8306009d, 0x00000000, 0xb5000000, 0x029f9005, + 0x01ffb814, 0x033f600f, 0x029f900a, 0x02bf900b, + 0x02df900c, 0x02ff900d, 0x031f900e, 0x033f900f, + 0x00ffb81e, 0x02ff9010, 0x92f70b43, 0x02ffb010, + 0x02ff90cb, 0x82bbffdc, 0x829bffd8, 0x93150004, + 0x3014b815, 0xb400000f, 0x02dbb818, 0x029bb815, + 0x3017b816, 0xb480000b, 0x5a81b814, 0x029fb010, + 0x82860095, 0x8293001f, 0x9294fe00, 0x92b50008, + 0x3015b814, 0xb4800002, 0x82b3001f, 0x92b5fa00, + 0x82beffdc, 0x82850086, 0x83250094, 0x06d4b819, + 0x02d6b816, 0xb016ffff, 0xb4a00009, 0x82c50081, + 0x9ab60020, 0x82a60081, 0x82a50086, 0x92b50bbb, + 0x82a60094, 0x82c60081, 0x86b505df, 0x82a6009b, + 0x00ffb81c, 0x82870001, 0x829ef500, 0x82850086, + 0x83250094, 0x06d4b819, 0x02d6b816, 0xb016ffff, + 0xb4a0000b, 0x82870001, 0x829ef504, 0x82c50081, + 0x9ab60020, 0x82a60081, 0x82a50086, 0x92b50bbb, + 0x82a60094, 0x82c60081, 0x86b505df, 0x82a6009b, + 0x00ffb81c, 0x82070028, 0x023f9006, 0x83a4ef4f, + 0x80070000, 0x001fb011, 0x001f204f, 0x003fb800, + 0x001f9006, 0x5803b800, 0x80338000, 0x1800b801, + 0x003fb800, 0x005f4193, 0x5c41b802, 0x80350000, + 0x00000000, 0x0027b860, 0x80150010, 0x5810b800, + 0x80750010, 0x1863b800, 0x8087ffff, 0x80a7770b, + 0x80c70000, 0x1403b804, 0x3000b805, 0xb4000008, + 0x5888b804, 0x58a8b805, 0x90c60001, 0xb0060003, + 0xb4a0fff8, 0x84420001, 0xb4e0ffee, 0xb5000027, + 0xb0060003, 0xb4200007, 0x80150010, 0x5810b800, + 0x81150010, 0x950800ff, 0xb0080077, 0xb4000001, + 0xb500fff4, 0x001f400e, 0x98000010, 0x98004000, + 0x9400fffe, 0x001f600e, 0x80e71f40, 0x001f4000, + 0x94000080, 0xb0000080, 0xb4200001, 0x80e77490, + 0x00ffb008, 0x80e70020, 0xb0060000, 0xb400000e, + 0x58e3b806, 0x90210020, 0x81070000, 0x5938b803, + 0x1908b809, 0x9523ff00, 0x5928b809, 0x1908b809, + 0x5d28b803, 0x9529ff00, 0x1908b809, 0x5d38b803, + 0x1908b809, 0x011fb011, 0x00ff204f, 0x80137fff, + 0x9800ffe7, 0x1421b800, 0x5c23b801, 0x001f9006, + 0x0441b800, 0x3001b800, 0xb4600002, 0x0440b801, + 0xa4422000, 0x007f90cb, 0x1063b802, 0x007fb0cb, + 0x003fb006, 0x803effec, 0x80470001, 0x005f2013, + 0xb500ebdf, 0x001f400e, 0x9400000f, 0xb0000000, + 0xb4200001, 0x00ffb81f, 0xb0000001, 0xb4000005, + 0xb0000003, 0xb4000003, 0xb0000002, 0xb4000001, + 0x00ffb81f, 0x80070001, 0x001f2013, 0xb500ebd0, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x803bff68, 0x8078ff6c, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x803bff68, + 0x8078ff6c, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x83840126, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e7ef98, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x80270180, 0x81e7ee90, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801bef90, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x8018ef94, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x819eff68, 0x817cff6c, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801bef90, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x8018ef94, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801bef90, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x8018ef94, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e7ec70, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270240, + 0x81e7ed70, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e7ee90, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x806f0007, + 0x80af0007, 0x80270280, 0x81e7ee70, 0x5de2b80f, + 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, + 0x01ff90bc, 0xb520ffff, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x015f400e, 0x944a4000, 0xb0024000, 0xb420001a, + 0x954abfff, 0x015f600e, 0x820f001f, 0x802f001f, + 0x81470000, 0x015f23f9, 0x015fb0ba, 0x8057ffff, + 0x80770000, 0x82970400, 0x82d7ffff, 0x82f70000, + 0xb6000702, 0xb6000001, 0x029fa02a, 0x80275480, + 0x005fb801, 0x8033001f, 0x9821c000, 0x803effe0, + 0x90212000, 0x803effe4, 0x80d9ff80, 0x00df6001, + 0x81477508, 0x015fb008, 0x003f0324, 0xb0010000, + 0xb4200076, 0x8344ebe6, 0xb0180000, 0xb4000004, + 0x011f400e, 0x1908b818, 0x011f600e, 0x00ffb81f, + 0x8344f18f, 0xb00b0000, 0xb4000006, 0x023f400e, + 0x9a310002, 0x023f600e, 0x82270000, 0x023f2012, + 0x00ffb81f, 0x8364ed72, 0x82270000, 0x023f2011, + 0x80070000, 0x80170800, 0xb6002002, 0xb6003001, + 0x001fa020, 0x82270000, 0x003fb811, 0x02bf9006, + 0x5aa3b815, 0x82338000, 0x1a31b815, 0x003fb811, + 0x8067e950, 0x5c62b803, 0x81f50000, 0x019f4193, + 0x0267b80c, 0xadcc0010, 0x80170800, 0x80130000, + 0x9800f872, 0x001fa020, 0x80134e1f, 0x98000001, + 0x001fa020, 0x59d0b80e, 0x81150010, 0x1908b80e, + 0x001fa028, 0x858c0001, 0x5e01b80c, 0x5e25b810, + 0xb6310006, 0xb6002005, 0x81150010, 0x5910b808, + 0x00000000, 0x81350010, 0x1808a029, 0x9630001f, + 0xb0110000, 0xb4000006, 0xb6310005, 0x81150010, + 0x5910b808, 0x00000000, 0x81350010, 0x1808a029, + 0x962c0001, 0xb0110000, 0xb4000003, 0x81150010, + 0x5910b808, 0x001fa028, 0x019f9006, 0x958cffff, + 0x00df4193, 0x58c1b806, 0x118cb806, 0xb00ce000, + 0xb4800002, 0x858ce000, 0x918cc000, 0x8153001f, + 0x118cb80a, 0x819effec, 0x019fb006, 0x015f4193, + 0x5941b80a, 0x019f90cb, 0x118cb80a, 0x019fb0cb, + 0x019f90ba, 0x918c0001, 0x019fb0ba, 0xb00c0002, + 0xb4200016, 0x019f400e, 0x940c8000, 0xb0008000, + 0xb4200012, 0x958c7fff, 0x019f600e, 0x80070000, + 0x800600a0, 0x80073da1, 0x800600a1, 0x801bff60, + 0x00000000, 0x801eff60, 0x00000000, 0x801bff60, + 0x00000000, 0x801eff60, 0x80130001, 0x98003da1, + 0x800600a1, 0x80070001, 0x800600a0, 0x003f0324, + 0x90210001, 0xb0010005, 0xb4a00001, 0x80270000, + 0x003f2324, 0x00ffb81f, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815bb3f0, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x81271800, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a0002e, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200001, + 0x8384fc04, 0x80af001f, 0x808f0002, 0x806f0000, + 0x807bbf34, 0x5d22b80a, 0xb600080a, 0x00cfb803, + 0x013fb0bc, 0x5922b809, 0x01afb809, 0x013f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x91290060, 0x808f0000, 0x813bb3f8, 0x80270001, + 0xb0090001, 0xb4000002, 0x802600a0, 0x803eb3f8, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813eb3f0, 0xb0030800, 0xb4800001, 0x80670200, + 0x807ebf34, 0x80270001, 0x003f2013, 0x00ffb81b, + +}; + +static u32 AC3240Ucode1f8000[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00020000, 0xffff0005, 0xffffffff, + 0x00050001, 0xffffffff, 0xffffffff, 0x00020000, + 0xffff0005, 0xffffffff, 0x00010000, 0x00050002, + 0xffffffff, 0x00020000, 0x00050003, 0xffffffff, + 0x00010000, 0x00030002, 0xffff0005, 0x00020000, + 0x00040003, 0xffff0005, 0x00010000, 0x00030002, + 0x00050004, 0x0019000d, 0x003d0025, 0x00250019, + 0x00fd003d, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x007fffff, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x007fffff, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00599999, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00599999, + 0x007fffff, 0x00599999, 0x00000000, 0x00599999, + 0x00000000, 0x00000000, 0x00000000, 0x00599999, + 0x00000000, 0x00599999, 0x007fffff, 0x00000000, + 0x00599999, 0x00599999, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00599999, 0x00599999, + 0x007fffff, 0x007fffff, 0x00000000, 0x00599999, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00599999, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x007fffff, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x007fffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00400000, + 0x00200000, 0x00100000, 0x00080000, 0x00040000, + 0x00020000, 0x00010000, 0x00008000, 0x00004000, + 0x00002000, 0x00001000, 0x00000800, 0x00000400, + 0x00000200, 0x00000100, 0x00000080, 0x00000040, + 0x00000020, 0x00000010, 0x00000008, 0x00000004, + 0x00000002, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010002, + 0x00030002, 0x00030002, 0x00030002, 0x00000000, + 0x00000000, 0x00010001, 0x00020002, 0x4000a000, + 0xe000a000, 0xf000b000, 0xf800b800, 0x005a8279, + 0x004c1bf8, 0x00400000, 0x004c1bf8, 0x005a8279, + 0x00400000, 0x00000000, 0x00400000, 0x03020100, + 0x00000000, 0x00000080, 0x00000020, 0x00000008, + 0x00000000, 0x00000001, 0x00010001, 0x10081000, + 0x10041000, 0x10081004, 0x10081008, 0x10081008, + 0x00000000, 0x00000000, 0x00000000, 0xff80000a, + 0xff80031f, 0xff800b24, 0xff801818, 0xff8029fa, + 0xff8040c9, 0xff805c86, 0xff807d2e, 0xff80a2c1, + 0xff80cd3c, 0xff80fc9f, 0xff8130e8, 0xff816a14, + 0xff81a821, 0xff81eb0e, 0xff8232d6, 0xff827f79, + 0xff82d0f2, 0xff83273e, 0xff83825b, 0xff83e244, + 0xff8446f7, 0xff84b06e, 0xff851ea6, 0xff85919b, + 0xff860949, 0xff8685aa, 0xff8706ba, 0xff878c74, + 0xff8816d3, 0xff88a5d1, 0xff89396a, 0xff89d196, + 0xff8a6e51, 0xff8b0f94, 0xff8bb55a, 0xff8c5f9b, + 0xff8d0e51, 0xff8dc176, 0xff8e7902, 0xff8f34ef, + 0xff8ff535, 0xff90b9cc, 0xff9182ae, 0xff924fd3, + 0xff932132, 0xff93f6c3, 0xff94d07f, 0xff95ae5d, + 0xff969054, 0xff97765b, 0xff98606a, 0xff994e78, + 0xff9a407c, 0xff9b366b, 0xff9c303e, 0xff9d2de9, + 0xff9e2f64, 0xff9f34a4, 0xffa03da0, 0xffa14a4c, + 0xffa25aa0, 0xffa36e8f, 0xffa48610, 0xffa5a118, + 0xffa6bf9c, 0xffa7e191, 0xffa906ec, 0xffaa2fa0, + 0xffab5ba4, 0xffac8aeb, 0xffadbd6a, 0xffaef315, + 0xffb02bdf, 0xffb167be, 0xffb2a6a4, 0xffb3e886, + 0xffb52d56, 0xffb67509, 0xffb7bf92, 0xffb90ce4, + 0xffba5cf2, 0xffbbafb0, 0xffbd050f, 0xffbe5d04, + 0xffbfb780, 0xffc11477, 0xffc273db, 0xffc3d59f, + 0xffc539b4, 0xffc6a00d, 0xffc8089d, 0xffc97355, + 0xffcae027, 0xffcc4f05, 0xffcdbfe2, 0xffcf32af, + 0xffd0a75d, 0xffd21ddf, 0xffd39625, 0xffd51022, + 0xffd68bc7, 0xffd80904, 0xffd987cd, 0xffdb0810, + 0xffdc89c1, 0xffde0cd0, 0xffdf912d, 0xffe116cb, + 0xffe29d9a, 0xffe4258b, 0xffe5ae8f, 0xffe73896, + 0xffe8c392, 0xffea4f74, 0xffebdc2b, 0xffed69aa, + 0xffeef7df, 0xfff086bd, 0xfff21634, 0xfff3a634, + 0xfff536ad, 0xfff6c792, 0xfff858d1, 0xfff9ea5b, + 0xfffb7c22, 0xfffd0e16, 0xfffea026, 0xffffcdbc, + 0xfffe3ba0, 0xfffca995, 0xfffb17ac, 0xfff985f3, + 0xfff7f479, 0xfff6634f, 0xfff4d284, 0xfff34228, + 0xfff1b249, 0xfff022f7, 0xffee9442, 0xffed0638, + 0xffeb78ea, 0xffe9ec67, 0xffe860bd, 0xffe6d5fd, + 0xffe54c35, 0xffe3c374, 0xffe23bcb, 0xffe0b547, + 0xffdf2ff7, 0xffddabec, 0xffdc2933, 0xffdaa7dd, + 0xffd927f6, 0xffd7a98f, 0xffd62cb7, 0xffd4b17b, + 0xffd337ea, 0xffd1c013, 0xffd04a05, 0xffced5ce, + 0xffcd637c, 0xffcbf31d, 0xffca84c1, 0xffc91874, + 0xffc7ae45, 0xffc64641, 0xffc4e078, 0xffc37cf6, + 0xffc21bc9, 0xffc0bcff, 0xffbf60a5, 0xffbe06c9, + 0xffbcaf79, 0xffbb5ac0, 0xffba08ae, 0xffb8b94d, + 0xffb76cac, 0xffb622d8, 0xffb4dbdc, 0xffb397c6, + 0xffb256a2, 0xffb1187d, 0xffafdd62, 0xffaea55f, + 0xffad707e, 0xffac3ecc, 0xffab1054, 0xffa9e523, + 0xffa8bd44, 0xffa798c2, 0xffa677a8, 0xffa55a02, + 0xffa43fdb, 0xffa3293d, 0xffa21634, 0xffa106c9, + 0xff9ffb08, 0xff9ef2fa, 0xff9deeab, 0xff9cee23, + 0xff9bf16c, 0xff9af892, 0xff9a039c, 0xff991295, + 0xff982586, 0xff973c78, 0xff965774, 0xff957683, + 0xff9499ad, 0xff93c0fb, 0xff92ec75, 0xff921c24, + 0xff91500f, 0xff90883f, 0xff8fc4bb, 0xff8f058b, + 0xff8e4ab6, 0xff8d9443, 0xff8ce239, 0xff8c349f, + 0xff8b8b7d, 0xff8ae6d7, 0xff8a46b5, 0xff89ab1e, + 0xff891416, 0xff8881a3, 0xff87f3cc, 0xff876a96, + 0xff86e606, 0xff866621, 0xff85eaed, 0xff85746d, + 0xff8502a6, 0xff84959e, 0xff842d57, 0xff83c9d7, + 0xff836b20, 0xff831138, 0xff82bc20, 0xff826bdc, + 0xff822070, 0xff81d9de, 0xff819829, 0xff815b54, + 0xff812360, 0xff80f051, 0xff80c228, 0xff8098e6, + 0xff80748e, 0xff805521, 0xff803a9f, 0xff80250b, + 0xff801464, 0xff8008ad, 0xff8001e4, 0xff800027, + 0xff800c7e, 0xff802c8f, 0xff806056, 0xff80a7cb, + 0xff8102e4, 0xff817191, 0xff81f3c3, 0xff828964, + 0xff83325f, 0xff83ee98, 0xff84bdf3, 0xff85a04f, + 0xff86958b, 0xff879d7f, 0xff88b804, 0xff89e4ee, + 0xff8b240e, 0xff8c7533, 0xff8dd82a, 0xff8f4cbb, + 0xff90d2ad, 0xff9269c4, 0xff9411c1, 0xff95ca62, + 0xff979365, 0xff996c81, 0xff9b5570, 0xff9d4de4, + 0xff9f5590, 0xffa16c24, 0xffa3914e, 0xffa5c4b8, + 0xffa8060d, 0xffaa54f3, 0xffacb10e, 0xffaf1a03, + 0xffb18f70, 0xffb410f7, 0xffb69e33, 0xffb936c0, + 0xffbbda37, 0xffbe8830, 0xffc14042, 0xffc40201, + 0xffc6cd00, 0xffc9a0d2, 0xffcc7d05, 0xffcf612b, + 0xffd24ccf, 0xffd53f80, 0xffd838c8, 0xffdb3833, + 0xffde3d49, 0xffe14795, 0xffe4569d, 0xffe769e9, + 0xffea80ff, 0xffed9b67, 0xfff0b8a4, 0xfff3d83c, + 0xfff6f9b5, 0xfffa1c91, 0xfffd4056, 0xffff9b78, + 0xfffc7756, 0xfff953c0, 0xfff63130, 0xfff31025, + 0xffeff117, 0xffecd484, 0xffe9bae5, 0xffe6a4b6, + 0xffe39270, 0xffe0848b, 0xffdd7b82, 0xffda77cb, + 0xffd779de, 0xffd48231, 0xffd19138, 0xffcea769, + 0xffcbc535, 0xffc8eb10, 0xffc61969, 0xffc350af, + 0xffc09151, 0xffbddbbb, 0xffbb3059, 0xffb88f92, + 0xffb5f9d0, 0xffb36f78, 0xffb0f0ef, 0xffae7e96, + 0xffac18cf, 0xffa9bff9, 0xffa7746f, 0xffa5368c, + 0xffa306aa, 0xffa0e51e, 0xff9ed23c, 0xff9cce56, + 0xff9ad9bc, 0xff98f4bc, 0xff971f9f, 0xff955aae, + 0xff93a62f, 0xff920266, 0xff906f92, 0xff8eedf3, + 0xff8d7dc4, 0xff8c1f3c, 0xff8ad294, 0xff8997fd, + 0xff886fa8, 0xff8759c3, 0xff865679, 0xff8565f2, + 0xff848852, 0xff83bdbd, 0xff830651, 0xff82622b, + 0xff81d163, 0xff815411, 0xff80ea47, 0xff809416, + 0xff80518b, 0xff8022b1, 0xff80078e, 0x00000475, + 0x000007fe, 0x00000c02, 0x000010a3, 0x000015f5, + 0x00001c08, 0x000022ed, 0x00002ab5, 0x00003371, + 0x00003d32, 0x0000480a, 0x0000540d, 0x0000614b, + 0x00006fda, 0x00007fcd, 0x00009138, 0x0000a431, + 0x0000b8cc, 0x0000cf1f, 0x0000e741, 0x00010148, + 0x00011d4b, 0x00013b61, 0x00015ba2, 0x00017e25, + 0x0001a302, 0x0001ca51, 0x0001f42c, 0x000220a9, + 0x00024fe2, 0x000281f0, 0x0002b6ea, 0x0002eee9, + 0x00032a07, 0x0003685a, 0x0003a9fc, 0x0003ef04, + 0x0004378a, 0x000483a5, 0x0004d36d, 0x000526f7, + 0x00057e5b, 0x0005d9ae, 0x00063904, 0x00069c74, + 0x00070410, 0x00076feb, 0x0007e01a, 0x000854ac, + 0x0008cdb3, 0x00094b40, 0x0009cd61, 0x000a5425, + 0x000adf98, 0x000b6fc8, 0x000c04bf, 0x000c9e87, + 0x000d3d2a, 0x000de0ae, 0x000e891a, 0x000f3674, + 0x000fe8c0, 0x00109fff, 0x00115c34, 0x00121d5d, + 0x0012e37b, 0x0013ae89, 0x00147e84, 0x00155366, + 0x00162d27, 0x00170bbf, 0x0017ef23, 0x0018d748, + 0x0019c421, 0x001ab59f, 0x001babb2, 0x001ca648, + 0x001da54f, 0x001ea8b0, 0x001fb058, 0x0020bc2d, + 0x0021cc18, 0x0022dffd, 0x0023f7c2, 0x00251348, + 0x00263272, 0x00275520, 0x00287b31, 0x0029a482, + 0x002ad0f1, 0x002c0059, 0x002d3294, 0x002e677c, + 0x002f9ee8, 0x0030d8b1, 0x003214ac, 0x003352b0, + 0x00349290, 0x0035d422, 0x00371738, 0x00385ba5, + 0x0039a13b, 0x003ae7cc, 0x003c2f2a, 0x003d7725, + 0x003ebf8d, 0x00400834, 0x004150e9, 0x0042997d, + 0x0043e1c0, 0x00452981, 0x00467092, 0x0047b6c3, + 0x0048fbe3, 0x004a3fc6, 0x004b823b, 0x004cc316, + 0x004e0228, 0x004f3f45, 0x00507a40, 0x0051b2ef, + 0x0052e925, 0x00541cba, 0x00554d85, 0x00567b5e, + 0x0057a61d, 0x0058cd9e, 0x0059f1bb, 0x005b1252, + 0x005c2f3f, 0x005d4863, 0x005e5d9d, 0x005f6ed0, + 0x00607bde, 0x006184ad, 0x00628923, 0x00638927, + 0x006484a3, 0x00657b81, 0x00666daf, 0x00675b19, + 0x006843b1, 0x00692767, 0x006a062d, 0x006adff9, + 0x006bb4c2, 0x006c847d, 0x006d4f27, 0x006e14b8, + 0x006ed52f, 0x006f9089, 0x007046c6, 0x0070f7e9, + 0x0071a3f3, 0x00724aea, 0x0072ecd3, 0x007389b6, + 0x0074219d, 0x0074b490, 0x0075429b, 0x0075cbcc, + 0x00765031, 0x0076cfd8, 0x00774ad3, 0x0077c132, + 0x00783308, 0x0078a068, 0x00790968, 0x00796e1c, + 0x0079ce9a, 0x007a2af9, 0x007a8350, 0x007ad7b8, + 0x007b2849, 0x007b751d, 0x007bbe4c, 0x007c03f1, + 0x007c4625, 0x007c8504, 0x007cc0a8, 0x007cf92c, + 0x007d2eaa, 0x007d613e, 0x007d9101, 0x007dbe10, + 0x007de883, 0x007e1076, 0x007e3603, 0x007e5943, + 0x007e7a4f, 0x007e9942, 0x007eb633, 0x007ed13a, + 0x007eea6f, 0x007f01ea, 0x007f17c0, 0x007f2c08, + 0x007f3ed7, 0x007f5043, 0x007f605e, 0x007f6f3c, + 0x007f7cf1, 0x007f898e, 0x007f9525, 0x007f9fc6, + 0x007fa982, 0x007fb268, 0x007fba86, 0x007fc1eb, + 0x007fc8a4, 0x007fcebe, 0x007fd443, 0x007fd941, + 0x007fddc2, 0x007fe1cf, 0x007fe572, 0x007fe8b4, + 0x007feb9e, 0x007fee36, 0x007ff086, 0x007ff293, + 0x007ff463, 0x007ff5fd, 0x007ff765, 0x007ff8a1, + 0x007ff9b6, 0x007ffaa7, 0x007ffb79, 0x007ffc2f, + 0x007ffccb, 0x007ffd52, 0x007ffdc6, 0x007ffe28, + 0x007ffe7b, 0x007ffec2, 0x007ffefd, 0x007fff2f, + 0x007fff58, 0x007fff7b, 0x007fff97, 0x007fffae, + 0x007fffc0, 0x007fffcf, 0x007fffdb, 0x007fffe4, + 0x007fffec, 0x007ffff1, 0x007ffff6, 0x007ffff9, + 0x007ffffb, 0x007ffffd, 0x007ffffe, 0x007fffff, + 0x007fffff, 0x007fffff, 0x007fffff, 0xff800000, + 0x00000000, 0xffa57d86, 0x005a827a, 0xff89be51, + 0x0030fbc5, 0xffcf043b, 0x007641af, 0xff8275a1, + 0x0018f8b8, 0xffb8e313, 0x006a6d99, 0xff959267, + 0x00471ced, 0xffe70748, 0x007d8a5f, 0xff809dc9, + 0x000c8bd3, 0xffaecc33, 0x0062f202, 0xff8f1d34, + 0x003c56ba, 0xffdad7f4, 0x007a7d05, 0xff8582fb, + 0x0025280c, 0xffc3a946, 0x0070e2cc, 0xff9d0dfe, + 0x005133cd, 0xfff3742d, 0x007f6237, 0xff802778, + 0x000647d9, 0xffaa0a5b, 0x005ed77d, 0xff8c4a14, + 0x0036ba20, 0xffd4e0cb, 0x00788484, 0xff83d604, + 0x001f19f9, 0xffbe31e2, 0x006dca0d, 0xff99307f, + 0x004c3fe0, 0xffed37f0, 0x007e9d56, 0xff8162aa, + 0x0012c810, 0xffb3c020, 0x0066cf81, 0xff9235f3, + 0x0041ce1e, 0xffe0e607, 0x007c29fc, 0xff877b7c, + 0x002b1f35, 0xffc945e0, 0x0073b5ec, 0xffa12883, + 0x0055f5a5, 0xfff9b827, 0x007fd888, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + +}; + +static u32 AC3240Ucode1fe000[] = { + 0x00000000, 0x03020102, 0x05040403, 0x00400040, + 0x00500050, 0x00600060, 0x00700070, 0x00800080, + 0x00a000a0, 0x00c000c0, 0x00e000e0, 0x01000100, + 0x01400140, 0x01800180, 0x01c001c0, 0x02000200, + 0x02800280, 0x03000300, 0x03800380, 0x04000400, + 0x04800480, 0x05000500, 0x00460045, 0x00580057, + 0x00690068, 0x007a0079, 0x008c008b, 0x00af00ae, + 0x00d100d0, 0x00f400f3, 0x01170116, 0x015d015c, + 0x01a201a1, 0x01e801e7, 0x022e022d, 0x02b902b8, + 0x03440343, 0x03d003cf, 0x045b045a, 0x04e604e5, + 0x05720571, 0x00600060, 0x00780078, 0x00900090, + 0x00a800a8, 0x00c000c0, 0x00f000f0, 0x01200120, + 0x01500150, 0x01800180, 0x01e001e0, 0x02400240, + 0x02a002a0, 0x03000300, 0x03c003c0, 0x04800480, + 0x05400540, 0x06000600, 0x06c006c0, 0x07800780, + 0x7b67533f, 0x1513110f, 0x04d80540, 0x04100478, + 0x07000000, 0x0b000900, 0x02b002f0, 0x02300270, + 0x017001f0, 0xf80000f0, 0x01000080, 0x02000180, + 0x03000280, 0x04000380, 0x2725231f, 0x2c2b2a29, + 0x2e2e2d2d, 0x30302f2f, 0x04030201, 0x08070605, + 0x0c0b0a09, 0x100f0e0d, 0x14131211, 0x18171615, + 0x1c1b1a19, 0x2825221f, 0x37312e2b, 0x4f49433d, + 0x796d6155, 0xcdb59d85, 0x0000fde5, 0x3d3e3f40, + 0x393a3b3c, 0x35363738, 0x32333434, 0x2f2f3031, + 0x2c2c2d2e, 0x29292a2b, 0x26262728, 0x23242425, + 0x21212223, 0x1e1f2020, 0x1c1d1d1e, 0x1a1b1b1c, + 0x1819191a, 0x16171718, 0x15151516, 0x13131414, + 0x12121213, 0x10111111, 0x0f0f1010, 0x0e0e0e0f, + 0x0d0d0d0d, 0x0c0c0c0c, 0x0b0b0b0b, 0x0a0a0a0a, + 0x0909090a, 0x08080909, 0x08080808, 0x07070707, + 0x06060707, 0x06060606, 0x05050606, 0x05050505, + 0x04040505, 0x04040404, 0x04040404, 0x03030304, + 0x03030303, 0x03030303, 0x02030303, 0x02020202, + 0x02020202, 0x02020202, 0x02020202, 0x01010202, + 0x01010101, 0x01010101, 0x01010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010101, 0x00000101, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x04d004d0, + 0x04000440, 0x03c003e0, 0x03b003b0, 0x03a003a0, + 0x03a003a0, 0x039003a0, 0x03900390, 0x03800380, + 0x03700370, 0x03600360, 0x03500350, 0x03400340, + 0x03200330, 0x03000310, 0x02f002f0, 0x02f002f0, + 0x03100300, 0x03900340, 0x042003e0, 0x04900460, + 0x046004a0, 0x04400440, 0x08000520, 0x08400840, + 0x04f004f0, 0x04100460, 0x03d003e0, 0x03b003c0, + 0x03a003b0, 0x03a003a0, 0x03a003a0, 0x03900390, + 0x03800390, 0x03800380, 0x03700370, 0x03600360, + 0x03500350, 0x03400340, 0x03100320, 0x02f00300, + 0x02f002f0, 0x030002f0, 0x03500320, 0x03e00390, + 0x04500420, 0x049004a0, 0x04400460, 0x06300480, + 0x08400840, 0x05800580, 0x045004b0, 0x03f00420, + 0x03d003e0, 0x03b003c0, 0x03b003b0, 0x03a003a0, + 0x03a003a0, 0x03a003a0, 0x03a003a0, 0x03900390, + 0x03900390, 0x03800380, 0x03700380, 0x03500360, + 0x03300340, 0x03100320, 0x02f00300, 0x02f002f0, + 0x03100300, 0x03500330, 0x041003c0, 0x04a00470, + 0x04400460, 0x04e00450, 0xffaaaaab, 0x00000000, + 0x00555555, 0xff99999a, 0xffcccccd, 0x00000000, + 0x00333333, 0x00666666, 0xff924925, 0xffb6db6e, + 0xffdb6db7, 0x00000000, 0x00249249, 0x00492492, + 0x006db6db, 0xff8ba2e9, 0xffa2e8ba, 0xffba2e8c, + 0xffd1745d, 0xffe8ba2f, 0x00000000, 0x001745d1, + 0x002e8ba3, 0x0045d174, 0x005d1746, 0x00745d17, + 0xff888889, 0xff99999a, 0xffaaaaab, 0xffbbbbbc, + 0xffcccccd, 0xffddddde, 0xffeeeeef, 0x00000000, + 0x00111111, 0x00222222, 0x00333333, 0x00444444, + 0x00555555, 0x00666666, 0x00777777, 0x08070605, + 0x0c0b0a09, 0x10100e0e, 0x00000010, 0x00000000, + 0x00000010, 0x00000020, 0x00000100, 0x00000110, + 0x00000120, 0x00000200, 0x00000210, 0x00000220, + 0x00001000, 0x00001010, 0x00001020, 0x00001100, + 0x00001110, 0x00001120, 0x00001200, 0x00001210, + 0x00001220, 0x00002000, 0x00002010, 0x00002020, + 0x00002100, 0x00002110, 0x00002120, 0x00002200, + 0x00002210, 0x00002220, 0x00000000, 0x00000010, + 0x00000020, 0x00000030, 0x00000040, 0x00000100, + 0x00000110, 0x00000120, 0x00000130, 0x00000140, + 0x00000200, 0x00000210, 0x00000220, 0x00000230, + 0x00000240, 0x00000300, 0x00000310, 0x00000320, + 0x00000330, 0x00000340, 0x00000400, 0x00000410, + 0x00000420, 0x00000430, 0x00000440, 0x00001000, + 0x00001010, 0x00001020, 0x00001030, 0x00001040, + 0x00001100, 0x00001110, 0x00001120, 0x00001130, + 0x00001140, 0x00001200, 0x00001210, 0x00001220, + 0x00001230, 0x00001240, 0x00001300, 0x00001310, + 0x00001320, 0x00001330, 0x00001340, 0x00001400, + 0x00001410, 0x00001420, 0x00001430, 0x00001440, + 0x00002000, 0x00002010, 0x00002020, 0x00002030, + 0x00002040, 0x00002100, 0x00002110, 0x00002120, + 0x00002130, 0x00002140, 0x00002200, 0x00002210, + 0x00002220, 0x00002230, 0x00002240, 0x00002300, + 0x00002310, 0x00002320, 0x00002330, 0x00002340, + 0x00002400, 0x00002410, 0x00002420, 0x00002430, + 0x00002440, 0x00003000, 0x00003010, 0x00003020, + 0x00003030, 0x00003040, 0x00003100, 0x00003110, + 0x00003120, 0x00003130, 0x00003140, 0x00003200, + 0x00003210, 0x00003220, 0x00003230, 0x00003240, + 0x00003300, 0x00003310, 0x00003320, 0x00003330, + 0x00003340, 0x00003400, 0x00003410, 0x00003420, + 0x00003430, 0x00003440, 0x00004000, 0x00004010, + 0x00004020, 0x00004030, 0x00004040, 0x00004100, + 0x00004110, 0x00004120, 0x00004130, 0x00004140, + 0x00004200, 0x00004210, 0x00004220, 0x00004230, + 0x00004240, 0x00004300, 0x00004310, 0x00004320, + 0x00004330, 0x00004340, 0x00004400, 0x00004410, + 0x00004420, 0x00004430, 0x00004440, 0x00000000, + 0x00000100, 0x00000200, 0x00000300, 0x00000400, + 0x00000500, 0x00000600, 0x00000700, 0x00000800, + 0x00000900, 0x00000a00, 0x00001000, 0x00001100, + 0x00001200, 0x00001300, 0x00001400, 0x00001500, + 0x00001600, 0x00001700, 0x00001800, 0x00001900, + 0x00001a00, 0x00002000, 0x00002100, 0x00002200, + 0x00002300, 0x00002400, 0x00002500, 0x00002600, + 0x00002700, 0x00002800, 0x00002900, 0x00002a00, + 0x00003000, 0x00003100, 0x00003200, 0x00003300, + 0x00003400, 0x00003500, 0x00003600, 0x00003700, + 0x00003800, 0x00003900, 0x00003a00, 0x00004000, + 0x00004100, 0x00004200, 0x00004300, 0x00004400, + 0x00004500, 0x00004600, 0x00004700, 0x00004800, + 0x00004900, 0x00004a00, 0x00005000, 0x00005100, + 0x00005200, 0x00005300, 0x00005400, 0x00005500, + 0x00005600, 0x00005700, 0x00005800, 0x00005900, + 0x00005a00, 0x00006000, 0x00006100, 0x00006200, + 0x00006300, 0x00006400, 0x00006500, 0x00006600, + 0x00006700, 0x00006800, 0x00006900, 0x00006a00, + 0x00007000, 0x00007100, 0x00007200, 0x00007300, + 0x00007400, 0x00007500, 0x00007600, 0x00007700, + 0x00007800, 0x00007900, 0x00007a00, 0x00008000, + 0x00008100, 0x00008200, 0x00008300, 0x00008400, + 0x00008500, 0x00008600, 0x00008700, 0x00008800, + 0x00008900, 0x00008a00, 0x00009000, 0x00009100, + 0x00009200, 0x00009300, 0x00009400, 0x00009500, + 0x00009600, 0x00009700, 0x00009800, 0x00009900, + 0x00009a00, 0x0000a000, 0x0000a100, 0x0000a200, + 0x0000a300, 0x0000a400, 0x0000a500, 0x0000a600, + 0x0000a700, 0x0000a800, 0x0000a900, 0x0000aa00, + 0xff800000, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xffb82995, 0xffaf5d75, 0xffa57d87, 0xff9a6806, + 0xff8df708, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xffb82995, 0xffaf5d75, 0xffa57d87, 0xff9a6806, + 0xff8df708, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xfffb0000, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, + 0xfffdfffd, 0xfffdfffd, 0xfffdfffd, 0xfffefffe, + 0xfffefffe, 0xfffefffe, 0xffffffff, 0xffffffff, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x80050000, 0x000a800f, 0x001e801b, 0x80110014, + 0x00368033, 0x8039003c, 0x802d0028, 0x00228027, + 0x00668063, 0x8069006c, 0x807d0078, 0x00728077, + 0x80550050, 0x005a805f, 0x004e804b, 0x80410044, + 0x00c680c3, 0x80c900cc, 0x80dd00d8, 0x00d280d7, + 0x80f500f0, 0x00fa80ff, 0x00ee80eb, 0x80e100e4, + 0x80a500a0, 0x00aa80af, 0x00be80bb, 0x80b100b4, + 0x00968093, 0x8099009c, 0x808d0088, 0x00828087, + 0x01868183, 0x8189018c, 0x819d0198, 0x01928197, + 0x81b501b0, 0x01ba81bf, 0x01ae81ab, 0x81a101a4, + 0x81e501e0, 0x01ea81ef, 0x01fe81fb, 0x81f101f4, + 0x01d681d3, 0x81d901dc, 0x81cd01c8, 0x01c281c7, + 0x81450140, 0x014a814f, 0x015e815b, 0x81510154, + 0x01768173, 0x8179017c, 0x816d0168, 0x01628167, + 0x01268123, 0x8129012c, 0x813d0138, 0x01328137, + 0x81150110, 0x011a811f, 0x010e810b, 0x81010104, + 0x03068303, 0x8309030c, 0x831d0318, 0x03128317, + 0x83350330, 0x033a833f, 0x032e832b, 0x83210324, + 0x83650360, 0x036a836f, 0x037e837b, 0x83710374, + 0x03568353, 0x8359035c, 0x834d0348, 0x03428347, + 0x83c503c0, 0x03ca83cf, 0x03de83db, 0x83d103d4, + 0x03f683f3, 0x83f903fc, 0x83ed03e8, 0x03e283e7, + 0x03a683a3, 0x83a903ac, 0x83bd03b8, 0x03b283b7, + 0x83950390, 0x039a839f, 0x038e838b, 0x83810384, + 0x82850280, 0x028a828f, 0x029e829b, 0x82910294, + 0x02b682b3, 0x82b902bc, 0x82ad02a8, 0x02a282a7, + 0x02e682e3, 0x82e902ec, 0x82fd02f8, 0x02f282f7, + 0x82d502d0, 0x02da82df, 0x02ce82cb, 0x82c102c4, + 0x02468243, 0x8249024c, 0x825d0258, 0x02528257, + 0x82750270, 0x027a827f, 0x026e826b, 0x82610264, + 0x82250220, 0x022a822f, 0x023e823b, 0x82310234, + 0x02168213, 0x8219021c, 0x820d0208, 0x02028207, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000001, 0x00000002, 0x00000002, + 0x00000000, 0xff800000, 0xffa57d86, 0xffa57d86, + 0xffcf043b, 0xff89be51, 0xff89be51, 0xffcf043b, + 0xffe70748, 0xff8275a1, 0xff959267, 0xffb8e313, + 0xffb8e313, 0xff959267, 0xff8275a1, 0xffe70748, + 0xfff3742d, 0xff809dc9, 0xff9d0dfe, 0xffaecc33, + 0xffc3a946, 0xff8f1d34, 0xff8582fb, 0xffdad7f4, + 0xffdad7f4, 0xff8582fb, 0xff8f1d34, 0xffc3a946, + 0xffaecc33, 0xff9d0dfe, 0xff809dc9, 0xfff3742d, + 0xfff9b827, 0xff802778, 0xffa12883, 0xffaa0a5b, + 0xffc945e0, 0xff8c4a14, 0xff877b7c, 0xffd4e0cb, + 0xffe0e607, 0xff83d604, 0xff9235f3, 0xffbe31e2, + 0xffb3c020, 0xff99307f, 0xff8162aa, 0xffed37f0, + 0xffed37f0, 0xff8162aa, 0xff99307f, 0xffb3c020, + 0xffbe31e2, 0xff9235f3, 0xff83d604, 0xffe0e607, + 0xffd4e0cb, 0xff877b7c, 0xff8c4a14, 0xffc945e0, + 0xffaa0a5b, 0xffa12883, 0xff802778, 0xfff9b827, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, + +}; + +static u32 AC3240Ucode1fff80[] = { + 0x0000240f, 0x007fffff, 0x007fffff, 0x00000003, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/ac3.h linux.20pre2-ac1/drivers/media/video/ls220/ac3.h --- linux.20pre2/drivers/media/video/ls220/ac3.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/ac3.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,2850 @@ +static u32 AC3Ucode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb5001223, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x80070800, 0x001f6193, + 0x800500d4, 0x8053ffff, 0x9842c7ff, 0x8039ff7c, + 0x1400b802, 0x003f6000, 0x94210007, 0xb0010001, + 0xb4200001, 0x98002800, 0xb0010000, 0xb4200001, + 0x98000800, 0x805300ff, 0x1800b802, 0x800600d4, + 0x8013001f, 0x9020c000, 0x003fb006, 0x803effe0, + 0x803effe8, 0x803effec, 0x9020e000, 0x9021ffe4, + 0x9020fa00, 0x803effd0, 0x803effdc, 0x803effd8, + 0x9020fe00, 0x803effd4, 0x90400000, 0x804600a2, + 0x90421800, 0x804600a3, 0x80134099, 0x98000040, + 0x800600a6, 0x80130000, 0x98003ca1, 0x800600a1, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x001f2324, 0x80070000, 0x001fb0ba, + 0x001f23f9, 0x801eb3f0, 0x80070800, 0x001f600f, + 0x80070000, 0x001f2012, 0x001fb0cb, 0x001fb010, + 0x801efff0, 0x98004000, 0x98008000, 0x001f600e, + 0x83e40137, 0x80070000, 0x801eb3f8, 0x801eff70, + 0x800500a0, 0xb0000001, 0xb4000009, 0x80070001, + 0x800600a0, 0x80050080, 0x98000020, 0x80060080, + 0x9400ffdf, 0x80060080, 0x80070000, 0x800600a0, + 0x81df0004, 0x00000000, 0x00000000, 0x801bfff0, + 0x00000000, 0x940000ff, 0xb0000000, 0xb420004e, + 0x003f400e, 0x94010010, 0xb0000000, 0xb400fff4, + 0x838413d5, 0x003f0013, 0xb0010001, 0xb420003b, + 0x803bffe8, 0x801bffec, 0x00000000, 0x3001b800, + 0xb4600001, 0x90212000, 0x0421b800, 0x005f4193, + 0x5841b802, 0x3001b802, 0xb460000d, 0x80050086, + 0x005f9016, 0xb0020000, 0xb4200002, 0x001fb016, + 0xb500ffdf, 0x0420b802, 0xb0010b50, 0xb4a0ffdc, + 0x80070000, 0x001fb016, 0x83e40101, 0xb500ffd8, + 0x80070000, 0x001fb016, 0x001f400e, 0x9400000f, + 0xb0000000, 0xb4000014, 0xb0000001, 0xb4000010, + 0x003f400e, 0x9421fff0, 0x003f600e, 0x003f9006, + 0x9421ffff, 0x90210004, 0xb001e000, 0xb4800002, + 0x8421e000, 0x9021c000, 0x8013001f, 0x1021b800, + 0x003fb006, 0x003f90cb, 0x90210004, 0x003fb0cb, + 0x83e400f7, 0x83e413b4, 0x8007001f, 0x94000003, + 0x5810b800, 0x83e71aa8, 0x1bffb800, 0x003f9008, + 0x1821b800, 0x00ffb801, 0x83e41407, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671ad4, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0xb500ffaa, 0x803bffc0, 0x805bffc4, + 0x807bffc8, 0x809bffcc, 0x5828b801, 0x5cb8b802, + 0x1821b805, 0x5848b802, 0x5cb8b803, 0x1842b805, + 0x5868b803, 0x5cb8b804, 0x1863b805, 0x5888b804, + 0x1884b800, 0x803effc0, 0x805effc4, 0x807effc8, + 0x809effcc, 0x003f400e, 0xb0000086, 0xb4400040, + 0xb0000084, 0xb400002a, 0xb0000085, 0xb4000030, + 0xb0000086, 0xb4000032, 0x001f4000, 0x94000080, + 0xb0000080, 0xb400006a, 0x80130000, 0x98003ca1, + 0x005f4000, 0x94420008, 0xb0020008, 0xb4000001, + 0xa0000080, 0x800600a1, 0x8013001f, 0x9040c000, + 0x005fb006, 0x805effe0, 0x805effe8, 0x805effec, + 0x9040e000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001fb0cb, + 0x001fb010, 0x001f2058, 0x80071fc0, 0x001fb008, + 0x80075fb0, 0x001fb009, 0x98214000, 0xb5000010, + 0x94011000, 0xb0001000, 0xb4200001, 0x9421efff, + 0x98210010, 0xb500000a, 0x80070000, 0x001fb0cb, + 0x83e40097, 0x003f400e, 0x9421ffef, 0xb5000004, + 0x83e40093, 0x003f400e, 0x98211000, 0x9421ffef, + 0x003f600e, 0x80070100, 0x801efff0, 0xb500ff54, + 0xb000008b, 0xb400001c, 0xb000008e, 0xb4000022, + 0xb000008d, 0xb400001c, 0xb000008c, 0xb4000021, + 0xb0000087, 0xb400ffe8, 0xb0000088, 0xb4000014, + 0xb000008a, 0xb4000015, 0xb0000089, 0xb400001d, + 0xb00000a0, 0xb400001f, 0xb00000a1, 0xb4000041, + 0xb00000a2, 0xb400004e, 0xb00000a3, 0xb4000046, + 0xb00000a4, 0xb4000050, 0xb00000a5, 0xb4000054, + 0xb00000a6, 0xb4000058, 0x803efff8, 0xb500ffdd, + 0x9421ffdf, 0xb500ffda, 0xb500ffda, 0x80270100, + 0x803efff8, 0xb500ffd7, 0x80070000, 0x001fb017, + 0xb500ffd4, 0x801bffb0, 0x00000000, 0x001fb003, + 0xb500ffd0, 0x803bff80, 0x00000000, 0x003f6001, + 0xb500ffcc, 0x003f90ba, 0x803efff8, 0xb500ffc9, + 0x80130001, 0x98003da1, 0x800600a1, 0x80070200, + 0x801ebf34, 0x83e40042, 0x8013001f, 0x9840c000, + 0x805effe0, 0x005fb006, 0x805effe8, 0x805effec, + 0x90422000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001f2324, + 0x001fb0cb, 0x001fb010, 0x001f2058, 0x80077560, + 0x001fb008, 0x80077810, 0x001fb009, 0x98214000, + 0xb500ffa7, 0x80270000, 0x8047fef0, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x81df0000, 0x00000000, + 0x00000000, 0x83641491, 0x81df0004, 0xb500ff99, + 0x81df0000, 0x00000000, 0x00000000, 0x8364143b, + 0x81df0004, 0xb500ff93, 0x81df0000, 0x00000000, + 0x00000000, 0x836413f6, 0x81df0004, 0xb500ff8d, + 0x81df0000, 0x00000000, 0x00000000, 0x83441359, + 0x81df0004, 0xb500ff87, 0x81df0000, 0x00000000, + 0x00000000, 0x8344133e, 0x81df0004, 0xb500ff81, + 0x80070000, 0x80470000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002003, 0xb6003002, 0x001eb802, + 0x90420004, 0x80171000, 0x8057ffff, 0xb6002002, + 0xb6001801, 0x001fa020, 0x81df0004, 0x00ffb81f, + 0x001f4000, 0x94000080, 0xb0000080, 0xb4200001, + 0xb500ffeb, 0xb500000a, 0x80270000, 0x003f2013, + 0x8007001f, 0x94000003, 0x5810b800, 0x83671ea0, + 0x1b7bb800, 0x003f9009, 0x1821b800, 0x00ffb801, + 0x003f0013, 0xb0010001, 0xb420fff3, 0x83a70000, + 0x803bff70, 0x00000000, 0xb0010000, 0xb4000015, + 0x80170300, 0x80070000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6000601, 0x001fa020, 0x83640ce3, + 0x00ff0325, 0x82870000, 0xb6270002, 0x83640228, + 0x92940001, 0x81df0004, 0x001f033b, 0xb0000000, + 0xb4000002, 0x80270000, 0xb5000001, 0x80270001, + 0x003f233b, 0x80270000, 0x003f2013, 0x8007001f, + 0x94000003, 0x5810b800, 0x83671f3c, 0x1b7bb800, + 0x003f9009, 0x1821b800, 0x00ffb801, 0x003f0013, + 0xb0010001, 0xb420fff3, 0x93bd0001, 0xb01d0004, + 0xb480ffd7, 0x803bff70, 0x00000000, 0xb0010000, + 0xb4000005, 0x81df0000, 0x00000000, 0x00000000, + 0x83640c8b, 0x81df0004, 0x00000000, 0x00000000, + 0x00ffb81f, 0x007f90cb, 0x90630400, 0x007fb0cb, + 0x003f9006, 0x9421ffff, 0x90210400, 0xb001e000, + 0xb4800002, 0x8421e000, 0x9021c000, 0x8013001f, + 0x1021b800, 0x003fb006, 0x803effec, 0x00ffb81f, + 0x015f400e, 0x944a4000, 0xb0024000, 0xb4200090, + 0x954abfff, 0x015f600e, 0x820f001f, 0x802f001f, + 0x81470000, 0x015f23f9, 0x829702ec, 0x82d7ffff, + 0x82f70000, 0x81df0000, 0x00000000, 0x00000000, + 0xb6000501, 0x029fa02a, 0x82970400, 0xb6000702, + 0xb6000001, 0x029fa02a, 0x81df0004, 0x8053ff00, + 0x98420000, 0x805ebf14, 0x805ebf18, 0x805ebf1c, + 0x805ebf20, 0x805ebf24, 0x805ebf28, 0x80270000, + 0x003f2328, 0x80275480, 0x005fb801, 0x8033001f, + 0x9821c000, 0x803effe0, 0x90212000, 0x803effe4, + 0x80dbff8c, 0x80fbff90, 0x80debf14, 0x80febf18, + 0x80dbff94, 0x80fbff98, 0x80debf1c, 0x80febf20, + 0x80dbff9c, 0x80fbffa0, 0x80debf24, 0x80febf28, + 0x80dbff84, 0x80e70001, 0x00dfb001, 0x80dbff88, + 0x00ff6191, 0x00dfb002, 0x80dbffb0, 0x80470000, + 0x00dfb003, 0x80d9ff80, 0x005fb0cf, 0x005fb0c6, + 0x00df6001, 0x80470001, 0x005f618f, 0x804700ff, + 0x005f231c, 0x005f231d, 0x80470000, 0x005f204e, + 0x8047e138, 0x5c42b802, 0x814f6300, 0x80cf00a9, + 0x005fb0bc, 0x5842b802, 0x01cfb802, 0x005f90bc, + 0xb520ffff, 0x8067e16c, 0x5c62b803, 0x80270040, + 0x81df0000, 0x00000000, 0x00000000, 0xb6000209, + 0x814fffc0, 0x00cfb801, 0x007fb0bc, 0x5862b803, + 0x01cfb803, 0x007f90bc, 0xb520ffff, 0x90210020, + 0x90630020, 0x81df0004, 0x8047e398, 0x5c42b802, + 0x814fce40, 0x80cf0080, 0x005fb0bc, 0x5842b802, + 0x01cfb802, 0x005f90bc, 0xb520ffff, 0x8047e400, + 0x5c42b802, 0x814f7380, 0x80cf009a, 0x005fb0bc, + 0x5842b802, 0x01cfb802, 0x005f90bc, 0xb520ffff, + 0x8047e43c, 0x5c42b802, 0x814f18c0, 0x80cf00b6, + 0x005fb0bc, 0x5842b802, 0x01cfb802, 0x005f90bc, + 0xb520ffff, 0x80e70000, 0x00ffb0ba, 0x808f0000, + 0x806f001f, 0x80af001f, 0x8027b9fc, 0x5c22b801, + 0x80670700, 0x81df0000, 0x00000000, 0x00000000, + 0xb600080a, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0x0047b86f, 0xb0020001, + 0xb4c0fffd, 0x90210020, 0x90630020, 0x81df0004, + 0x834400d7, 0xb0180000, 0xb4200025, 0x834406dc, + 0x80c70000, 0x00df2324, 0x83640026, 0x83440228, + 0x00df0324, 0x90c60001, 0x00df2324, 0xb0060006, + 0xb4000003, 0x81472228, 0x015fb008, 0x00ffb81f, + 0x00ff90ba, 0x90e70001, 0x00ffb0ba, 0x019f9006, + 0x958cffff, 0x00df4193, 0x58c1b806, 0x118cb806, + 0xb00ce000, 0xb4800002, 0x858ce000, 0x918cc000, + 0x8153001f, 0x118cb80a, 0x819effec, 0x019fb006, + 0x015f4193, 0x5941b80a, 0x019f90cb, 0x118cb80a, + 0x019fb0cb, 0x81472210, 0x015fb008, 0x00ffb81f, + 0x015f400e, 0x194ab818, 0x015f600e, 0x802500a5, + 0x00ffb81f, 0x803bff8c, 0x805bff90, 0x803ebf14, + 0x805ebf18, 0x803bff94, 0x805bff98, 0x803ebf1c, + 0x805ebf20, 0x803bff9c, 0x805bffa0, 0x803ebf24, + 0x805ebf28, 0x80470003, 0x805ebefc, 0x003f0384, + 0x5822b801, 0x9021eb50, 0x005bb801, 0x00000000, + 0xb0020001, 0xb4200002, 0x80470001, 0x805ebefc, + 0x8073ff80, 0x98630000, 0x8027bf14, 0x8047befc, + 0x81df0000, 0x00000000, 0x00000000, 0xb6000609, + 0x009bb801, 0x00000000, 0x00a7b804, 0x6081b804, + 0x3004b803, 0xb4000001, 0x00beb802, 0x90210004, + 0x90420004, 0x81df0004, 0x00ffb81b, 0x00000000, + 0x81150010, 0x00000000, 0x00000000, 0x81350010, + 0x00000000, 0x00000000, 0x81550002, 0x00000000, + 0x015f2380, 0x81550006, 0x00000000, 0x015f2381, + 0x81550005, 0x00000000, 0x015f2382, 0x81550003, + 0x00000000, 0x015f2383, 0x81550003, 0x015f2384, + 0xb00a0001, 0xb4000005, 0x956a0001, 0xb00b0000, + 0xb4000002, 0x81750002, 0x017f2385, 0x956a0004, + 0xb00b0000, 0xb4000002, 0x81750002, 0x017f2386, + 0xb00a0002, 0xb4200003, 0x81750002, 0x00000000, + 0x017f2387, 0x81750001, 0x00000000, 0x017f2388, + 0x81750005, 0x00000000, 0x017f2389, 0x81750001, + 0x017f239f, 0xb00b0001, 0xb4200003, 0x81750008, + 0x5968b80b, 0x017f61c5, 0x81750001, 0x017f238c, + 0xb00b0001, 0xb4200003, 0x81750008, 0x00000000, + 0x017f238d, 0x81750001, 0x017f238e, 0xb00b0001, + 0xb4200005, 0x81750005, 0x00000000, 0x017f238f, + 0x81750002, 0x017f2390, 0xb00a0000, 0xb420001b, + 0x81750005, 0x00000000, 0x017f2391, 0x81750001, + 0x017f23a0, 0xb00b0001, 0xb4200003, 0x81750008, + 0x5968b80b, 0x017f61c9, 0x81750001, 0x017f2394, + 0xb00b0001, 0xb4200003, 0x81750008, 0x00000000, + 0x017f2395, 0x81750001, 0x017f2396, 0xb00b0001, + 0xb4200006, 0x81750005, 0x00000000, 0x017f2397, + 0x81750002, 0x00000000, 0x017f2398, 0x81750001, + 0x00000000, 0x017f2399, 0x81750001, 0x00000000, + 0x017f239a, 0x81750001, 0x017f239b, 0xb00b0001, + 0xb4200003, 0x8175000e, 0x00000000, 0x017f61be, + 0x81750001, 0x017f239c, 0xb00b0001, 0xb4200003, + 0x8175000e, 0x00000000, 0x017f237e, 0x81750001, + 0x017f239d, 0xb00b0001, 0xb4200006, 0x81750006, + 0x017f239e, 0x916b0001, 0x81550008, 0x856b0001, + 0xb4e0fffd, 0x00ffb81c, 0x00000000, 0x00000000, + 0x81470000, 0x015f2385, 0x015f2386, 0x015f2387, + 0x015f238d, 0x015f238f, 0x015f2390, 0x015f2391, + 0x015f2395, 0x015f2396, 0x015f2397, 0x015f2398, + 0x015f61be, 0x015f61bf, 0x82070028, 0x023f9006, + 0x83a40034, 0x83270000, 0x003fb819, 0x003f9006, + 0x5823b801, 0x83338000, 0x1b39b801, 0x003fb819, + 0x00000000, 0x00000000, 0x81550000, 0x8384ff64, + 0x017f0380, 0xad4b0026, 0x013f0381, 0x114ab809, + 0x5941b80a, 0x914ae00c, 0x0199b80a, 0x00000000, + 0x019f6193, 0xb0080b77, 0xb4200010, 0x015f0380, + 0xb00a0003, 0xb4600011, 0xb0090026, 0xb4600013, + 0x017f90ba, 0xb00b0000, 0xb4200002, 0x017f0383, + 0x017f2057, 0x015f0383, 0x017f0057, 0x300ab80b, + 0xb420000e, 0x83070000, 0x00ffb81a, 0x83070800, + 0x031f6193, 0x83070001, 0x00ffb81a, 0x83070800, + 0x031f6193, 0x83070002, 0x00ffb81a, 0x83070800, + 0x031f6193, 0x83070003, 0x00ffb81a, 0x83070003, + 0x00ffb81a, 0x5e02b810, 0x5a02b810, 0x00bf9011, + 0x00df004f, 0xa5260020, 0x81e70000, 0x82471000, + 0x95d1ffff, 0xa5cee000, 0x300eb810, 0xb4600002, + 0x05f0b80e, 0x0207b80e, 0x8267001f, 0x82c70020, + 0x82971000, 0xb0100080, 0xb4800023, 0x5a8bb813, + 0x5aa6b813, 0x1a94b815, 0x01efb812, 0x014fb814, + 0x01cfb811, 0xb520ffff, 0x81df0000, 0x00000000, + 0x00000000, 0xb636000f, 0x81470000, 0x039f8014, + 0xb6000404, 0x5948b80a, 0x957c00ff, 0x194ab80b, + 0x5f88b81c, 0xb0060020, 0xb4200001, 0x80a70000, + 0x64a6b805, 0x68e9b80a, 0x18a5b807, 0x029fa025, + 0x00a7b80a, 0x81df0004, 0x01efb812, 0x014fb814, + 0x01afb811, 0xb520ffff, 0x5ae2b816, 0x1231b817, + 0x0610b817, 0xb500ffda, 0xb0100000, 0xb4000003, + 0x5ec2b810, 0x86760001, 0xb500ffd8, 0xb00f0000, + 0xb4000005, 0x0207b80f, 0x81f3001f, 0x9a2fc000, + 0x81e70000, 0xb500ffcc, 0x015fb011, 0x00ffb81d, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x82d7ffff, 0x8357ffff, 0x83d7ffff, + 0x80770000, 0x80f70000, 0x81770000, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x83f70000, + 0xaeb40080, 0x808f0000, 0x806f001f, 0x80af001f, + 0xb0140000, 0xb4400014, 0x806f001f, 0x80af001f, + 0x8027b9fc, 0x5c22b801, 0x80670700, 0xb6000208, + 0x00cfb803, 0x003fb0bc, 0x5822b801, 0x01cfb801, + 0x003f90bc, 0xb520ffff, 0x90630020, 0x90210020, + 0x80270000, 0x80171000, 0xb6000303, 0xb6000001, + 0x001fa021, 0x00000000, 0x82670000, 0xb6000268, + 0x80170a00, 0x80970afc, 0x81170b00, 0x81970bfc, + 0x80271c00, 0x1021b813, 0x1021b813, 0x0217b801, + 0x80271ffc, 0x0421b813, 0x0421b813, 0x0297b801, + 0x80270c00, 0x1021b813, 0x1021b813, 0x0317b801, + 0x80270ffc, 0x0421b813, 0x0421b813, 0x0397b801, + 0x80478500, 0x1042b813, 0x5c42b802, 0x1022b815, + 0x80670280, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0x009f033b, + 0x80478480, 0x0442b813, 0x5c42b802, 0x1022b815, + 0x806702a0, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0xb0040000, + 0xb4000002, 0x80479000, 0xb5000001, 0x80479c00, + 0x1042b813, 0x5c42b802, 0x1022b815, 0x806702c0, + 0x00cfb803, 0x003fb0bc, 0x5822b801, 0x01cfb801, + 0x003f90bc, 0xb520ffff, 0xb0040000, 0xb4000002, + 0x80479180, 0xb5000001, 0x80479d80, 0x0442b813, + 0x5c42b802, 0x1022b815, 0x806702e0, 0x00cfb803, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x81270000, 0x80370000, 0x80b70000, + 0x81370000, 0x81b70000, 0x82370004, 0x82b7fffc, + 0xb6002016, 0x41498008, 0x51498814, 0x51498814, + 0x51418810, 0x51418810, 0x41818814, 0x0308a02a, + 0x49958820, 0x51898810, 0x51918828, 0x414d8814, + 0x0388a7ec, 0x494d8814, 0x49458810, 0x49458810, + 0x418d8810, 0x0308a02a, 0x49918fec, 0x51858814, + 0x51958fe4, 0x00000000, 0x0388a7ec, 0x92730080, + 0x009f033b, 0x5802b814, 0x90400300, 0x001f9802, + 0x00000000, 0xb0000000, 0xb4200016, 0x80170a00, + 0x80070000, 0xb6002001, 0x001fa020, 0xb0040000, + 0xb4200002, 0x80279000, 0xb5000001, 0x80279c00, + 0xac740080, 0x5c22b801, 0x11e1b803, 0x806f001f, + 0x80af001f, 0xb6000407, 0x80cf0280, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x91ef0020, 0x007f0320, 0x011f90cd, 0xaca30006, + 0x80c7b004, 0x10a5b814, 0x58a1b805, 0x10a5b806, + 0x0099b805, 0x8027b3dc, 0x5841b804, 0x1021b802, + 0x0159b801, 0x8027b3d0, 0x5841b804, 0x1021b802, + 0x0139b801, 0x80170c00, 0x0097b80a, 0xb0090000, + 0xb4200004, 0xb6000002, 0x015f8020, 0x009fe0ca, + 0xb5000004, 0x015fc024, 0xb6000002, 0x015f8020, + 0x009fe0ca, 0x00ffb81b, 0x00000000, 0x00000000, + 0x009f0011, 0x015f0012, 0xb0060000, 0xb4200007, + 0x968a0001, 0xb0140000, 0xb400000d, 0x80870001, + 0x009f2011, 0x954a0002, 0x015f2012, 0xb0060002, + 0xb4200007, 0x968a0002, 0xb0140000, 0xb4000004, + 0x80870001, 0x009f2011, 0x81470000, 0x015f2012, + 0x83640037, 0x00bf2010, 0xb0060000, 0xb4200003, + 0xb0050000, 0xb4200001, 0x836400a1, 0xb0050000, + 0xb4200001, 0x836400ca, 0x00bf0010, 0xb0050000, + 0xb420000a, 0x81df0000, 0x00000000, 0x00000000, + 0x836409e4, 0x836402f6, 0x00000000, 0x8364098c, + 0x81df0004, 0x00000000, 0xb5000009, 0x00bf0010, + 0xb0050001, 0xb4000006, 0x00000000, 0x81df0000, + 0x00000000, 0x00000000, 0x83640981, 0x81df0004, + 0x00ff0325, 0x82870000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6270002, 0x8364fef5, 0x92940001, + 0x81df0004, 0x80070001, 0x801eff70, 0x001f0010, + 0xb0000001, 0xb4000007, 0x001f033b, 0xb0000000, + 0xb4000002, 0x80270000, 0xb5000001, 0x80270001, + 0x003f233b, 0x00ffb81a, 0x00000000, 0x00000000, + 0x027f4001, 0x5e2ab813, 0x96310003, 0x81c70000, + 0x820700ff, 0xb0110000, 0xb4000005, 0x5a21b811, + 0x81c70200, 0x8207000e, 0x69d1b80e, 0x1210b811, + 0x01dfb0cd, 0x5e2cb813, 0x96310003, 0x023f2323, + 0x5e28b813, 0x96310003, 0x023f2322, 0x5e27b813, + 0x96310001, 0x023f2328, 0x5e23b813, 0x96310001, + 0x023f2321, 0x95f30007, 0x01ff2320, 0x920fe004, + 0x0258b810, 0x00000000, 0x1252b811, 0x025f2325, + 0x8167befc, 0x017f6195, 0x021f031c, 0x01df031d, + 0x3010b80f, 0xb4200003, 0x3011b80e, 0xb4200001, + 0xb5000025, 0x80270000, 0x80471000, 0x0017b802, + 0x8057ffff, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002001, 0x001fa021, 0x80270400, 0x80679000, + 0x5c62b803, 0xb6001809, 0x00cfb801, 0x007fb0bc, + 0x5862b803, 0x01afb803, 0x007f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x80679c00, + 0x5c62b803, 0xb6001809, 0x00cfb801, 0x007fb0bc, + 0x5862b803, 0x01afb803, 0x007f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x81df0004, + 0x01ff231c, 0x023f231d, 0x83970300, 0x82070000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6320001, + 0x039fa030, 0x81df0004, 0x00bf0010, 0x021f0324, + 0xb0100000, 0xb4200001, 0x80a70000, 0xb0050000, + 0xb4200008, 0xb0040000, 0xb4a00002, 0x80a70001, + 0xb5000004, 0x82070000, 0x021f204e, 0xb4000001, + 0x80a70002, 0xb0050001, 0xb4200007, 0x021f004e, + 0xb0100002, 0xb4a00002, 0x80a70002, 0x00ffb81b, + 0x92100001, 0x021f204e, 0x00000000, 0x00ffb81b, + 0x81530000, 0x003fb80a, 0x00000000, 0x00000000, + 0x003fb819, 0x00000000, 0x00000000, 0x81550000, + 0x8384fd63, 0x81470000, 0x015f61ee, 0x015f61ef, + 0x015f23a4, 0x8297050c, 0x82d7ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6000501, 0x029fa02a, + 0x81df0004, 0x8167e004, 0x116b0384, 0x0158b80b, + 0x019f0382, 0x015f237b, 0x017f0388, 0x116bb80a, + 0xb00c0008, 0xb4a00003, 0x80a70003, 0x00bf2010, + 0x00ffb81b, 0xb00a0005, 0xb4400003, 0xb00b0006, + 0xb4400001, 0x00ffb81b, 0x80a70004, 0x00bf2010, + 0x00ffb81b, 0x00000000, 0x00000000, 0x00000000, + 0x027f0388, 0x02bf037b, 0x02df0384, 0x02ff03a1, + 0x82970400, 0x8257ffff, 0x82d7ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6350003, 0x81550001, + 0x8357ffff, 0x029fa02a, 0x82970414, 0xb6350003, + 0x81550001, 0x83d7ffff, 0x029fa02a, 0x81df0004, + 0x81550001, 0xb00a0001, 0xb4200004, 0x814d0008, + 0x6149b80a, 0x954affff, 0x015f61ee, 0xb0160000, + 0xb4200007, 0x81550001, 0xb00a0001, 0xb4200004, + 0x814d0008, 0x6149b80a, 0x954affff, 0x015f61ef, + 0x81550001, 0xb00a0001, 0xb4200042, 0x82f50001, + 0x02ff23a1, 0xb0170001, 0xb4200034, 0x82970428, + 0x81df0000, 0x00000000, 0x00000000, 0xb6350003, + 0x81550001, 0x00000000, 0x029fa02a, 0x81df0004, + 0x82970428, 0x81470000, 0x017f8034, 0xb00b0001, + 0xb4000004, 0x914a0001, 0x300ab815, 0xb480fffa, + 0xb5000001, 0x015f23a5, 0x81670000, 0xb0160002, + 0xb4200002, 0x81750001, 0x00000000, 0x017f233a, + 0x81550004, 0xadaa000c, 0x015f23a2, 0x81750004, + 0x916b0003, 0x017f23a3, 0x91ad0025, 0x01bf23a6, + 0xadab000c, 0x81e70000, 0x91ad0025, 0x01bf23a7, + 0x920a0001, 0x05abb810, 0xb00d0000, 0xb4000015, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0004, + 0x81b50001, 0x65b0b80d, 0x19efb80d, 0x92100001, + 0x81df0004, 0x01ffb0be, 0xb500000a, 0x81a70000, + 0x82970428, 0x81df0000, 0x00000000, 0x00000000, + 0xb6350001, 0x029fa02d, 0x81df0004, 0x01bf233a, + 0x01bf23a5, 0x82070000, 0x82270000, 0x82170428, + 0x81df0000, 0x00000000, 0x00000000, 0xb635003a, + 0x01bf8030, 0xb00d0001, 0xb4200036, 0x81d50001, + 0x65b1b80e, 0x1a10b80d, 0xb00e0001, 0xb4200031, + 0x81b50002, 0xadad0003, 0xae510048, 0x91cd000f, + 0x91320868, 0x015f03a2, 0xad4a0004, 0x92920700, + 0x1189b80a, 0x0297b80c, 0x1194b80a, 0x0317b80c, + 0x01ff90be, 0x015f03a2, 0x017f03a3, 0x064bb80a, + 0x0107b80a, 0xb0120000, 0xb400001e, 0xb632001d, + 0x6928b80f, 0x95290001, 0xb0090000, 0xb420000e, + 0x81350004, 0x1129b80d, 0x029fa029, 0x824d0004, + 0x5a48b812, 0x5e48b812, 0x3009b80e, 0xb4200002, + 0x5e41b812, 0xb500000d, 0x5e42b812, 0x81330040, + 0x1a52b809, 0xb5000009, 0x0127b854, 0x85290004, + 0x0397b809, 0x0287b858, 0x86940004, 0x013f803c, + 0x0397b814, 0x029fa029, 0x025f803c, 0x031fa032, + 0x91080001, 0x92310001, 0x81df0004, 0x015f03a2, + 0x017f03a3, 0x013f033a, 0xb0090001, 0xb4200023, + 0x95300002, 0x95900001, 0x1929b80c, 0xb0090000, + 0xb400001e, 0x064bb80a, 0x0107b80a, 0x81df0000, + 0x00000000, 0x00000000, 0xb6320017, 0x6928b80f, + 0x95290001, 0xb0090000, 0xb4200002, 0x81350001, + 0x013f23f8, 0x81a70700, 0x91ad0048, 0x5982b808, + 0x11adb80c, 0x0397b80d, 0x013f03f8, 0xb0090001, + 0xb4200005, 0x019f801c, 0x0196b80c, 0x81b3ff80, + 0x418cb80d, 0xb5000002, 0x019f801c, 0x0196b80c, + 0x039fa00c, 0x91080001, 0x81df0004, 0xb0160002, + 0xb420001e, 0xb0170001, 0xb4200008, 0xb00a0000, + 0xb4200002, 0x81270002, 0xb5000005, 0xb00a0002, + 0xb4400002, 0x81270003, 0xb5000001, 0x81270004, + 0x013f23a9, 0x81950001, 0xb00c0001, 0xb4200011, + 0x81a70000, 0x8397043c, 0x81df0000, 0x00000000, + 0x00000000, 0xb6290006, 0x81150001, 0x039fa028, + 0xb0080001, 0xb4200001, 0x81a70001, 0x00000000, + 0x81df0004, 0x01bf23a8, 0xb5000002, 0x81a70000, + 0x01bf23a8, 0xb0170001, 0xb4200001, 0x81b50002, + 0x82970c20, 0x81df0000, 0x00000000, 0x00000000, + 0xb6350003, 0x81550002, 0x00000000, 0x029fa02a, + 0x81df0004, 0xb0130001, 0xb4200001, 0x81150001, + 0x81c70000, 0x81df0000, 0x00000000, 0x00000000, + 0xb6350014, 0x922e0c20, 0x015ff011, 0xb00a0000, + 0xb400000f, 0x922e0428, 0x015ff011, 0xb00a0001, + 0xb4200005, 0x922e044c, 0x0297b811, 0x015f03a6, + 0x029fa00a, 0xb5000006, 0x81550006, 0xad4a0003, + 0x922e044c, 0x0297b811, 0x914a0049, 0x029fa00a, + 0x91ce0004, 0x81df0004, 0xb0170001, 0xb4200022, + 0xb00d0000, 0xb4000020, 0x852d0001, 0x81470001, + 0x6549b80a, 0xad6a0003, 0x019f03a7, 0x058c03a6, + 0x81270000, 0xb00b0000, 0xb4000005, 0x300cb80b, + 0xb4800003, 0x058cb80b, 0x91290001, 0xb500fffb, + 0x81750004, 0x5961b80b, 0x839704ec, 0x0187b860, + 0x039fa02c, 0x039fa02a, 0x039fa029, 0x039fa02b, + 0xb0090000, 0xb4000007, 0x81df0000, 0x00000000, + 0x00000000, 0xb6290003, 0x81550007, 0x00000000, + 0x00000000, 0x81df0004, 0x81c70000, 0x81df0000, + 0x00000000, 0x00000000, 0xb635002e, 0x922e0c20, + 0x01fff011, 0xb00f0000, 0xb4000029, 0x852f0001, + 0x81470001, 0x6549b80a, 0xad6a0003, 0x922e044c, + 0x025fd811, 0x86520001, 0x0227b812, 0x81270000, + 0xb00b0000, 0xb4000005, 0x3012b80b, 0xb4800003, + 0x0652b80b, 0x91290001, 0xb500fffb, 0x2e09b80b, + 0x00000000, 0x3010b811, 0xb4600001, 0x91290001, + 0xae4e0004, 0x82150004, 0x9232049c, 0x0297b811, + 0x0187b860, 0x029fa02c, 0x029fa02a, 0x029fa029, + 0x029fa030, 0xb0090000, 0xb4000004, 0xb6290003, + 0x81550007, 0x00000000, 0x00000000, 0x82270460, + 0x1231b80e, 0x0217b811, 0x81550002, 0x021fa00a, + 0x91ce0004, 0x81df0004, 0xb0130001, 0xb420000c, + 0xb0080000, 0xb400000a, 0x81550004, 0x839704fc, + 0x0167b860, 0x039fa02b, 0x81670001, 0x039fa02b, + 0x8175000e, 0x81670002, 0x039fa02b, 0x039fa02a, + 0x81150001, 0xb0080001, 0xb420000a, 0x8135000b, + 0x5d2923aa, 0x95490180, 0x5d4723ab, 0x95490060, + 0x5d4523ac, 0x95490018, 0x5d4323ad, 0x95490007, + 0x015f23ae, 0x81350001, 0xb0090001, 0xb420001b, + 0x81350006, 0x013f23af, 0xb0170001, 0xb4200005, + 0x81550004, 0x00000000, 0x015f23b0, 0x81550003, + 0x015f23b1, 0x82970474, 0x83170488, 0x81df0000, + 0x00000000, 0x00000000, 0xb6350004, 0x81550007, + 0x5e83a02a, 0x954a0007, 0x031fa02a, 0x81df0004, + 0xb0130001, 0xb4200005, 0x81750004, 0x00000000, + 0x017f23b2, 0x81750003, 0x017f23b3, 0xb0170001, + 0xb420000b, 0x81b50001, 0xb00d0001, 0xb4200008, + 0x81d50003, 0x59c8b80e, 0x91ce0300, 0x01df61da, + 0x81d50003, 0x59c8b80e, 0x91ce0300, 0x01df61db, + 0x81550001, 0xb00a0001, 0xb4200057, 0xb0170001, + 0xb4200001, 0x81550002, 0x82470000, 0x82270000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6350004, + 0x81750002, 0x6571b80b, 0x92310002, 0x1a52b80b, + 0x81df0004, 0xb0170001, 0xb420001b, 0xb00a0001, + 0xb4200015, 0x81150003, 0x91080001, 0x011f23a4, + 0x829709d0, 0x831709f0, 0x83970060, 0x81df0000, + 0x00000000, 0x00000000, 0xb6280009, 0x81750005, + 0x00000000, 0x029fa02b, 0x81750004, 0x00000000, + 0x031fa02b, 0x81750003, 0x00000000, 0x039fa02b, + 0x81df0004, 0xb5000004, 0xb00a0002, 0xb4800002, + 0x81070000, 0x011f23a4, 0x82270000, 0x81270000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6350025, + 0x6a11b812, 0x92310002, 0x96100003, 0xb0100001, + 0xb4200018, 0xada90020, 0x81750003, 0x920d0520, + 0x0217b810, 0x920d05c0, 0x0297b810, 0x920d0660, + 0x0317b810, 0x5942b809, 0x920a050c, 0x0397b810, + 0x916b0001, 0x039fa02b, 0xb62b0009, 0x81750005, + 0x00000000, 0x021fa02b, 0x81750004, 0x00000000, + 0x029fa02b, 0x81750003, 0x00000000, 0x031fa02b, + 0xb5000007, 0xb0100002, 0xb4800005, 0x59a2b809, + 0x91ad050c, 0x0397b80d, 0x82070000, 0x039fa010, + 0x91290001, 0x81df0004, 0x81550001, 0xb00a0001, + 0xb420000a, 0x81550009, 0xb00a0000, 0xb4000007, + 0x81df0000, 0x00000000, 0x00000000, 0xb62a0003, + 0x82150008, 0x00000000, 0x00000000, 0x81df0004, + 0xb00a0100, 0xb4a0000b, 0x954aff00, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008003, 0x82150010, + 0x00000000, 0x00000000, 0x81df0004, 0x854a0100, + 0xb4e0fff6, 0x00ffb81b, 0x00000000, 0x00000000, + 0x81070000, 0x011f61dc, 0x011f61de, 0x011f61e0, + 0x011f03aa, 0x9108e0f4, 0x0138b808, 0x011f03ab, + 0x013f61ac, 0x9108e0f0, 0x0138b808, 0x011f03ac, + 0x013f61ad, 0x5901b808, 0x9108e0f8, 0x0139b808, + 0x011f03ad, 0x013f61ae, 0x5901b808, 0x9108e100, + 0x0139b808, 0x011f03ae, 0x013f61b0, 0x5901b808, + 0x9108e108, 0x0179b808, 0x013f03af, 0x017f61b1, + 0x02bf037b, 0x82970474, 0xb6350002, 0x015f8034, + 0x1929b80a, 0x011f03a1, 0xb0080001, 0xb4200002, + 0x015f03b0, 0x1929b80a, 0x019f0388, 0xb00c0001, + 0xb4200002, 0x015f03b2, 0x1929b80a, 0x013f61b3, + 0x015f03a8, 0xb00a0001, 0xb420003a, 0x81a70000, + 0x01bf237a, 0x83840056, 0x806f001f, 0x80af001f, + 0x80270300, 0x8067a800, 0x5c62b803, 0xb600080a, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01afb803, + 0x007f90bc, 0x0047b86f, 0xb0020001, 0xb4c0fffd, + 0x90210020, 0x90630020, 0x81a70001, 0x01bf237a, + 0x83840043, 0x838403ce, 0x81a70000, 0x01bf237a, + 0x82470400, 0x01bff012, 0x01bf23fa, 0x83840420, + 0x83840497, 0x83840546, 0x8384059d, 0x806f001f, + 0x80af001f, 0x80270300, 0x8067ac00, 0x5c62b803, + 0xb600080a, 0x00cfb801, 0x007fb0bc, 0x5862b803, + 0x01cfb803, 0x007f90bc, 0x0047b86f, 0xb0020001, + 0xb4c0fffd, 0x90210020, 0x90630020, 0x81a70001, + 0x01bf237a, 0x82470404, 0x015ff012, 0x015f23fa, + 0x83840407, 0x8384047e, 0x8384052d, 0x83840584, + 0xb5000011, 0x81a70000, 0x01bf237a, 0xb635000e, + 0x8384001b, 0x01bf037a, 0xad4d0004, 0x00000000, + 0x914a0400, 0x01bff00a, 0x01bf23fa, 0x838403f8, + 0x8384046f, 0x8384051e, 0x83840575, 0x01df037a, + 0x91ce0001, 0x01df237a, 0x019f0388, 0xb00c0001, + 0xb4200009, 0x02bf037b, 0x02bf237a, 0x838400e8, + 0x82470000, 0x025f23fa, 0x838403e9, 0x83840460, + 0x8384050f, 0x83840566, 0x00ffb81b, 0x00000000, + 0x80770000, 0x80f70000, 0x81770000, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x83f70000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x82d7ffff, 0x8357ffff, 0x83d7ffff, + 0x017f037a, 0x5a42b80b, 0x01bf03a8, 0xb00d0001, + 0xb4200004, 0x011f9118, 0x013f9119, 0x7929b808, + 0xb5000002, 0x91b20460, 0x013ff00d, 0x91b20340, + 0x0297b80d, 0x00000000, 0x029fa009, 0x01df0384, + 0xb00e0000, 0xb4200005, 0xb00b0001, 0xb4200003, + 0x009f90c6, 0x00bf0391, 0xb5000002, 0x009f90cf, + 0x00bf0389, 0x83a40142, 0x81870000, 0x019f61b5, + 0x019f61b4, 0x5a02b80b, 0x9190044c, 0x01dfd80c, + 0x01df61b6, 0x91900488, 0x01dff00c, 0x59c1b80e, + 0x918ee118, 0x01d9b80c, 0x019f03af, 0x01df61af, + 0x858c000f, 0x5986b80c, 0x91d00474, 0x01bff00e, + 0x59c2b80d, 0x11cc61b2, 0x81870000, 0x019f61b8, + 0x91900414, 0x01dfd80c, 0x01df61b7, 0xadab0010, + 0x00000000, 0x908d049c, 0x83a40191, 0xadcb0020, + 0x5982b80b, 0x908e0520, 0x90ae05c0, 0x90ce0660, + 0x928c050c, 0x00ff9814, 0x83a40169, 0x83a401b8, + 0x017f037a, 0x59c2b80b, 0x918e0428, 0x01fff00c, + 0xb00f0001, 0xb4200081, 0x023f03a5, 0x3011b80b, + 0xb420000f, 0x01c7b860, 0x01dfb0fa, 0x01df41dc, + 0x01df61e8, 0x01df41de, 0x01df61ea, 0x01df41e0, + 0x01df61ec, 0x01df41dd, 0x01df61e9, 0x01df41df, + 0x01df61eb, 0x01df41e1, 0x01df61ed, 0xb5000024, + 0x01c7b860, 0x01dfb0f9, 0x01df41dc, 0x01df61e2, + 0x01df41de, 0x01df61e4, 0x01df41e0, 0x01df61e6, + 0x01df41dd, 0x01df61e3, 0x01df41df, 0x01df61e5, + 0x01df41e1, 0x01df61e7, 0x803f0000, 0x00000000, + 0x00000000, 0x01df90fa, 0x003fb80e, 0x00000000, + 0x00000000, 0x81d50000, 0x00000000, 0x00000000, + 0x01df41e8, 0x01df61dc, 0x01df41ea, 0x01df61de, + 0x01df41ec, 0x01df61e0, 0x01df41e9, 0x01df61dd, + 0x01df41eb, 0x01df61df, 0x01df41ed, 0x01df61e1, + 0x029f03a6, 0x029f236a, 0x029f03a7, 0x029f236c, + 0x027f03a2, 0x92b3e128, 0x0298b815, 0x019f03b0, + 0x029f2368, 0x5982b80c, 0x01df03af, 0x85ce000f, + 0x59c6b80e, 0x11cc61b2, 0x82a70001, 0x02bf61b8, + 0x82a70000, 0x02bf61b9, 0x029f41da, 0x029f61ba, + 0x029f41db, 0x029f61bb, 0x019f03b1, 0x5981b80c, + 0x918ce118, 0x0299b80c, 0xad8b0048, 0x029f61af, + 0x59a2b813, 0x118cb80d, 0x928c0868, 0x029fb0fb, + 0x928c0700, 0x029fb0fc, 0x019f41bc, 0x918c0003, + 0x019f61bc, 0x5a02b80b, 0x91900414, 0x029fd80c, + 0x029f236e, 0x808704ec, 0x83a40121, 0x808709d0, + 0x80a709f0, 0x80c70060, 0x00ff03a4, 0x83a400fc, + 0x83a4014b, 0x021f037a, 0x019f03a5, 0x300cb810, + 0xb4000016, 0x803f0000, 0x00000000, 0x00000000, + 0x01df90f9, 0x003fb80e, 0x00000000, 0x00000000, + 0x81d50000, 0x00000000, 0x00000000, 0x01df41e2, + 0x01df61dc, 0x01df41e4, 0x01df61de, 0x01df41e6, + 0x01df61e0, 0x01df41e3, 0x01df61dd, 0x01df41e5, + 0x01df61df, 0x01df41e7, 0x01df61e1, 0x029f41b6, + 0xa6d40100, 0xaeb40004, 0x81870000, 0x92b50c00, + 0x0397b815, 0xb6360001, 0x039fa02c, 0x00ffb81c, + 0x009f90cf, 0x00bf0389, 0x019f037a, 0x5982b80c, + 0x918c0340, 0x0397b80c, 0x81870000, 0x039fa00c, + 0x83a40083, 0x81870000, 0x019f61b5, 0x019f61b4, + 0x81870007, 0x019f61b6, 0x019f03b3, 0x5981b80c, + 0x918ce118, 0x01b9b80c, 0x019f03af, 0x01bf61af, + 0x858c000f, 0x5986b80c, 0x01bf03b2, 0x59a2b80d, + 0x118cb80d, 0x019f61b2, 0x81870000, 0x019f61b7, + 0x019f61b8, 0x808704fc, 0x83a400d9, 0x80870000, + 0x80a70000, 0x80c70000, 0x80e70000, 0x83a400b4, + 0x83a40103, 0x81470000, 0x81e70c1c, 0x0397b80f, + 0xb600f901, 0x039fa02a, 0x00ffb81c, 0x00000000, + 0x82270000, 0x023f2011, 0x0227b860, 0x023fb0ff, + 0x02bf9006, 0x92350028, 0x8213001f, 0x9210e000, + 0x3011b810, 0xb4800001, 0x86312000, 0x021f4193, + 0x5a01b810, 0x86100028, 0x83a4fa2e, 0x82270000, + 0x003fb811, 0x02bf9006, 0x5aa3b815, 0x82338000, + 0x1a31b815, 0x003fb811, 0x8067e950, 0x5c62b803, + 0x81f50000, 0x80270400, 0x81df0000, 0x00000000, + 0x00000000, 0xb6000409, 0x814fffc0, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01cfb803, 0x007f90bc, + 0xb520ffff, 0x90210020, 0x90630020, 0x81df0004, + 0x82870000, 0x81f50010, 0x019f4193, 0x5d61b80c, + 0x5d43b80c, 0x114ab80b, 0x0187b80a, 0x960cff00, + 0x92100100, 0x858c0001, 0x81df0000, 0x00000000, + 0x00000000, 0xb62c000c, 0x81f50010, 0x5e28b80f, + 0xb6000209, 0x5a48b814, 0x9652ff00, 0x5e68b814, + 0x5981b813, 0x918c1000, 0x01dfd80c, 0x2252b811, + 0x2292b80e, 0x962f00ff, 0x81df0004, 0x81870000, + 0x86100100, 0xb4e0ffec, 0xb00a0000, 0xb4000009, + 0x81670000, 0xb0140000, 0xb4000001, 0x81670001, + 0x017f2012, 0x258a4193, 0x918c0001, 0x81470000, + 0xb500ffde, 0x81670000, 0xb0140000, 0xb4000001, + 0x81670002, 0x116b0012, 0x803f0000, 0x00000000, + 0x00000000, 0x003fb811, 0x00000000, 0x00000000, + 0x81f50000, 0x017f2012, 0x00ffb81a, 0x00000000, + 0x61f4b804, 0x91ef0001, 0x8233003f, 0x9a31ffff, + 0x5a02b804, 0x1610b811, 0x92510001, 0x1a10b812, + 0x029f03fb, 0xb0140001, 0xb4200012, 0x5a21b805, + 0x92b1e910, 0x0299b815, 0x5a22b805, 0x5a90b814, + 0x6290b814, 0x92b1e890, 0x11efb814, 0x029bb815, + 0x8233ff80, 0x3011b814, 0xb4000006, 0x4294b811, + 0x00000000, 0x0288b814, 0x4210b814, 0x00000000, + 0x0208b810, 0x029f9003, 0x82f3007f, 0x9af7ffff, + 0x3017b814, 0xb4000003, 0x4210b814, 0x00000000, + 0x0208b810, 0x82270000, 0x02c7b810, 0xb0160000, + 0xb400000a, 0x1676b812, 0x3013b812, 0xb4000003, + 0x5ac1b816, 0x92310001, 0xb500fffa, 0x81d3ff80, + 0x3010b80e, 0xb4200001, 0x1ad6b80e, 0x05efb811, + 0x027f037a, 0x5a62b813, 0x92730340, 0x0397b813, + 0x023fd813, 0x02dfb0fd, 0x5a30b811, 0x6230b811, + 0x0631b80f, 0x3010b812, 0xb4200001, 0x92310001, + 0x82470000, 0xb0110000, 0xb4800004, 0x82470003, + 0xb0110003, 0xb4400001, 0x0247b811, 0x039fa012, + 0x124f61bc, 0x00ffb81d, 0x00000000, 0x00000000, + 0x83970a10, 0x82070000, 0xb6003201, 0x039fa030, + 0xb0070000, 0xb4000019, 0x029f41b4, 0x0297b804, + 0x0317b805, 0x0397b806, 0xb6270014, 0x12948034, + 0x01df8038, 0xb00e0000, 0xb4a0000e, 0x02bf803c, + 0x5a02b814, 0x91b00a10, 0x0217b80d, 0xb62e0008, + 0x96150003, 0x91f00001, 0xadef0080, 0xb0150004, + 0xb4600001, 0x85ef0280, 0x021fa02f, 0x92940001, + 0xb5000001, 0x021f803c, 0x00000000, 0x00ffb81d, + 0x0397b804, 0x021f036a, 0x027f803c, 0x029f803c, + 0x02bf803c, 0x02df803c, 0x5a22b810, 0x92311000, + 0x0397b811, 0xb0100000, 0xb4200001, 0x039fa036, + 0xb0150000, 0xb4000021, 0x0227b860, 0x023fb0ff, + 0xb520ffff, 0x803f0000, 0x82138000, 0x1a10b813, + 0x003fb810, 0x00000000, 0x00000000, 0x82150000, + 0x00000000, 0xb635000d, 0x82550007, 0x5a42b812, + 0x9212e4b8, 0x025bb810, 0x8227000c, 0xb6000307, + 0x68d1b812, 0x94c6000f, 0x84c60002, 0x12d6b806, + 0xb6340001, 0x039fa036, 0x86310004, 0x803f0000, + 0x82138000, 0x023f90ff, 0x1a31b810, 0x003fb811, + 0x00000000, 0x00000000, 0x82150000, 0x00ffb81d, + 0x00ff41b5, 0x011f41b4, 0x019f41af, 0x01bf41ae, + 0x01df41ba, 0x01ff41bb, 0x82070000, 0x023f0380, + 0x82470000, 0xae310032, 0x029f41b3, 0x5862b807, + 0x90431000, 0x81970ad8, 0x0217b802, 0x90430c00, + 0x0297b802, 0x0317b802, 0x912802a4, 0x007ff009, + 0x58478030, 0x792341b6, 0x0529b807, 0x019fa029, + 0xb0080014, 0xb4800011, 0xa5420c00, 0x031fa02a, + 0x84690001, 0xb4a00011, 0xb623000b, 0x58678030, + 0xa4030c00, 0x031fa020, 0x044ab800, 0x0056b802, + 0x5c41b802, 0xf84200ff, 0x90620100, 0x005ff003, + 0x7d40b80a, 0x114ab802, 0xb5000004, 0xa5420c00, + 0x58478010, 0xa5620c00, 0x031fa02a, 0xb0080016, + 0xb4400043, 0xb0080013, 0xb440002c, 0xb0080006, + 0xb4400024, 0xb0080005, 0xb4400014, 0xb0080002, + 0xb4400006, 0x80440030, 0x015f619c, 0x05cab80c, + 0x05eab80d, 0x066eb810, 0xb500003c, 0x8044002a, + 0x300a419c, 0xb4800001, 0x82470001, 0x015f619c, + 0xb0120001, 0xb4200001, 0xb500001a, 0x05cab80c, + 0x05eab80d, 0x066eb810, 0xb5000030, 0x001f41b6, + 0xb0000007, 0xb4000001, 0x8044001b, 0x300a419c, + 0xb4800001, 0x82470001, 0xb0120001, 0xb4200001, + 0xb500000c, 0x05cab80c, 0x05eab80d, 0x066eb810, + 0xb5000022, 0x80440010, 0x840b0100, 0x300ab800, + 0xb4200001, 0x86100040, 0xb5000002, 0x86100080, + 0xfe100000, 0x046e41ad, 0x042ab80c, 0x7dc1b803, + 0x044f41ac, 0x042ab80d, 0x7de1b802, 0x046eb810, + 0x7e6fb803, 0xb5000011, 0x840b0100, 0x3000b80a, + 0xb4200002, 0x82070180, 0x00ffb802, 0x300ab80b, + 0xb4a00002, 0x86100040, 0xfe100000, 0x00ffb802, + 0x046e41ad, 0x042ab80c, 0x7dc1b803, 0x044f41ac, + 0x042ab80d, 0x7de1b802, 0x7e6eb80f, 0x380a41b0, + 0xb4600003, 0x242a41b0, 0x5c22b801, 0x1273b801, + 0xb0140000, 0xb4200002, 0x80071fe0, 0xb5000016, + 0x1011b808, 0x5801b800, 0x9020e26c, 0x0079b801, + 0x5842b808, 0x90420a10, 0x7c03b813, 0x003f9802, + 0x1000b801, 0x003f41b2, 0x5830b801, 0x6030b801, + 0x0400b801, 0x003f41b1, 0x5830b801, 0x6030b801, + 0x0400b801, 0xfc000000, 0xf8001fe0, 0x94001fe0, + 0x100041b1, 0x9400ffff, 0x8067003f, 0xb6290008, + 0x005f8014, 0x0442b800, 0x9442ffff, 0x5850b802, + 0x6050b802, 0xfc420000, 0x5c45b802, 0x7a82a023, + 0x10e7b809, 0x91080001, 0x300741b6, 0xb420ff6a, + 0x019f61af, 0x01bf61ae, 0x01df61ba, 0x01ff61bb, + 0x00ff41b5, 0x011f41b4, 0x019f41b8, 0x01bf41b7, + 0x01df41dd, 0x01ff41df, 0x021f41e1, 0x027f90fd, + 0x029f41bc, 0x02ff41dc, 0x031f41de, 0x033f41e0, + 0x5822b807, 0x91210c00, 0x0117b809, 0x81970ad8, + 0x91211000, 0x0217b809, 0x91210c00, 0x0317b809, + 0x80170ba0, 0x013f802c, 0xb629005f, 0x003f8038, + 0xb001000e, 0xb440001e, 0xb001000c, 0xb4400054, + 0xb001000a, 0xb4400043, 0xb0010007, 0xb440003c, + 0xb0010005, 0xb440002b, 0xb0010000, 0xb440001a, + 0xb00d0001, 0xb4200010, 0x005f418f, 0xac42bb75, + 0x8073005a, 0x9442ffff, 0x005f618f, 0x95628000, + 0x5848b802, 0xb00b8000, 0xb4200002, 0x8173ff00, + 0x1842b80b, 0x9863827a, 0x4043b802, 0x00000000, + 0x0048b802, 0xb500003f, 0x80470000, 0xb500003d, + 0x8401000f, 0x5c22b800, 0x902102d8, 0x001ff001, + 0x004db800, 0xb5000037, 0x86f70001, 0xb4600005, + 0x80750005, 0x5862b803, 0x9043e44c, 0x01d9b802, + 0x82e70002, 0x5c4cb80e, 0x9462000f, 0x5862b803, + 0x90630200, 0x005f9803, 0x59c4b80e, 0x95ceffff, + 0xb5000028, 0x87180001, 0xb4600005, 0x80750007, + 0x5862b803, 0x9043e4b8, 0x01f9b802, 0x83070002, + 0x5c4cb80f, 0x9462000f, 0x5862b803, 0x9063020c, + 0x005f9803, 0x59e4b80f, 0x95efffff, 0xb5000019, + 0x80750003, 0x5862b803, 0x90630220, 0x005f9803, + 0xb5000014, 0x87390001, 0xb4600005, 0x80750007, + 0x5862b803, 0x9043e6ac, 0x0219b802, 0x83270001, + 0x5c4cb810, 0x9462000f, 0x5862b803, 0x9063023c, + 0x005f9803, 0x5a04b810, 0x9610ffff, 0xb5000005, + 0x80750004, 0x5862b803, 0x90630268, 0x005f9803, + 0x00000000, 0x001fa022, 0x80170ba0, 0xb00c0001, + 0xb4200035, 0x023f90fb, 0x007f9811, 0x025f90fc, + 0x06d4b803, 0x007f9812, 0x4083b813, 0x00000000, + 0x0088b804, 0xb629002b, 0x24368030, 0x9421ffff, + 0x5830b801, 0x6030b801, 0x40448020, 0xb0010020, + 0xb4800003, 0x80470000, 0x80670000, 0xb500000e, + 0xb0010000, 0xb4a00004, 0x82b30080, 0x6aa1b815, + 0x4042b815, 0xb5000008, 0x6c41b802, 0x82a70017, + 0x12b5b801, 0x6875b803, 0x1842b803, 0x00000000, + 0x00000000, 0x00000000, 0x0108a022, 0x007f41b9, + 0x90630001, 0x007f61b9, 0xb003000c, 0xb420000c, + 0x92310004, 0x023fb0fb, 0x007f9811, 0x92520004, + 0x06d4b803, 0x025fb0fc, 0x007f9812, 0x80470000, + 0x4083b813, 0x00000000, 0x0088b804, 0x005f61b9, + 0x00000000, 0xb500001a, 0xb6290019, 0x24348030, + 0x9421ffff, 0x5830b801, 0x6030b801, 0x40538020, + 0xb0010020, 0xb4800003, 0x80470000, 0x80670000, + 0xb500000e, 0xb0010000, 0xb4a00004, 0x82b30080, + 0x6aa1b815, 0x4042b815, 0xb5000008, 0x6c41b802, + 0x82a70017, 0x12b5b801, 0x6875b803, 0x1842b803, + 0x00000000, 0x00000000, 0x00000000, 0x0108a022, + 0x10e7b809, 0x91080001, 0x300741b6, 0xb420ff48, + 0x00ff61b5, 0x011f61b4, 0x01df61dd, 0x01ff61df, + 0x021f61e1, 0x02ff61dc, 0x031f61de, 0x033f61e0, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x808f0000, 0x003f9113, 0x005f9114, + 0x7141b802, 0x80cf0700, 0x8027b064, 0x5c22b801, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x80cf0704, 0x8027b06c, 0x5c22b801, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x81e7043c, 0x82071c00, 0x82271c10, + 0x019f03a9, 0x806f001f, 0x80af001f, 0x80270400, + 0x8067a800, 0x5c62b803, 0xb6000808, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01cfb803, 0x007f90bc, + 0xb520ffff, 0x90210020, 0x90630020, 0x81971000, + 0x82170c00, 0xb6000004, 0x003f800c, 0x005f8010, + 0x021fa021, 0x019fa022, 0x00bfd810, 0x003fd811, + 0x70c1b80a, 0x001f980f, 0x91ef0004, 0x92100002, + 0x92310002, 0x5822b805, 0x90411000, 0x0197b802, + 0x90410c00, 0x0217b802, 0x0466b805, 0xb0000000, + 0xb4000005, 0xb6230004, 0x003f8010, 0x005f800c, + 0x1201a022, 0x0581a022, 0x858c0001, 0xb4e0ffea, + 0x80270400, 0x8067ac00, 0x5c62b803, 0xb6000808, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01afb803, + 0x007f90bc, 0xb520ffff, 0x90210020, 0x90630020, + 0x00ffb81c, 0x00000000, 0x00000000, 0x00000000, + 0x808f0000, 0x806f001f, 0x80af001f, 0x003f037a, + 0xb0010000, 0xb4400030, 0x81a7b7fc, 0x5da2b80d, + 0x80670500, 0xb6000208, 0x00cfb803, 0x01bfb0bc, + 0x59a2b80d, 0x01cfb80d, 0x01bf90bc, 0xb520ffff, + 0x90630020, 0x91ad0020, 0x81c7b8fc, 0x5dc2b80e, + 0x80670540, 0xb6000208, 0x00cfb803, 0x01dfb0bc, + 0x59c2b80e, 0x01cfb80e, 0x01df90bc, 0xb520ffff, + 0x90630020, 0x91ce0020, 0x81a7b3fc, 0x5da2b80d, + 0x80670600, 0xb6000408, 0x00cfb803, 0x01bfb0bc, + 0x59a2b80d, 0x01cfb80d, 0x01bf90bc, 0xb520ffff, + 0x90630020, 0x91ad0020, 0x81c7b5fc, 0x5dc2b80e, + 0x80670680, 0xb6000408, 0x00cfb803, 0x01dfb0bc, + 0x59c2b80e, 0x01cfb80e, 0x01df90bc, 0xb520ffff, + 0x90630020, 0x91ce0020, 0x005f03fa, 0xb0020000, + 0xb4000024, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x8257ffff, 0x82d7ffff, 0x8357ffff, + 0x83d7ffff, 0x83971300, 0x83171200, 0x82971100, + 0x82171000, 0x81170c00, 0x81970ff8, 0x80171400, + 0x80971500, 0x005f802c, 0x001f8028, 0xb6004010, + 0x41028000, 0x51008004, 0x007f876c, 0x0208a028, + 0x41008000, 0x49028004, 0x003f8068, 0x0388a028, + 0x41038000, 0x51018004, 0x005f802c, 0x0288a028, + 0x41018020, 0x49038024, 0x001f8028, 0x0308a028, + 0x00ffb81c, 0x83d7ffff, 0x8357ffff, 0x82d7ffff, + 0x8257ffff, 0x8157ffff, 0x81d7ffff, 0x8057ffff, + 0x80d7ffff, 0x82971200, 0x82171000, 0x81170c00, + 0x81970ffc, 0x83171800, 0x83971a00, 0x83370000, + 0x83b70000, 0x81370008, 0x81b7fff8, 0x4119880c, + 0xb6008006, 0x511d8808, 0x41498838, 0x0208a028, + 0x494d883c, 0x4119880c, 0x0288a02a, 0x00ffb81c, + 0x82670000, 0x82a70000, 0x003f037a, 0xb0010000, + 0xb4400018, 0x81a7bdfc, 0x5da2b80d, 0x80670580, + 0xb6000208, 0x00cfb803, 0x01bfb0bc, 0x59a2b80d, + 0x01cfb80d, 0x01bf90bc, 0xb520ffff, 0x90630020, + 0x91ad0020, 0x81a7eb70, 0x5da2b80d, 0x806705c0, + 0xb6000208, 0x00cfb803, 0x01bfb0bc, 0x59a2b80d, + 0x01cfb80d, 0x01bf90bc, 0xb520ffff, 0x90630020, + 0x91ad0020, 0x02bf03fa, 0x808f0000, 0xb0150000, + 0xb4000006, 0x81470040, 0x81670003, 0x81870002, + 0x81a71000, 0x81c71300, 0xb5000005, 0x81470080, + 0x81670004, 0x81870001, 0x81a71000, 0x81c71200, + 0x0017b80d, 0x0097b80e, 0x108db80a, 0x0117b804, + 0x108eb80a, 0x0197b804, 0x5841b80a, 0x108db802, + 0x0217b804, 0x108eb802, 0x0297b804, 0x106ab802, + 0x108db803, 0x0317b804, 0x108eb803, 0x0397b804, + 0x5ea2b80a, 0xb6350020, 0x001f8000, 0x003f8008, + 0x005f8004, 0x007f800c, 0x10c08010, 0x10a18018, + 0x10828014, 0x10e3801c, 0x1246b805, 0x0686b805, + 0x10c4b807, 0x0484b807, 0x80e70000, 0x80a70000, + 0x0008a032, 0x0108a034, 0x0088a026, 0x0188a024, + 0x04c08010, 0x04a18018, 0x04828014, 0x04e3801c, + 0x0646b807, 0x1286b807, 0x10c4b805, 0x0484b805, + 0x80e70000, 0x80a70000, 0x0208a032, 0x0308a034, + 0x0288a026, 0x0388a024, 0x5de1b80a, 0x82070004, + 0xb62b002a, 0x0017b80d, 0x0097b80e, 0x102db80f, + 0x0117b801, 0x104eb80f, 0x0197b802, 0x82171600, + 0x82971700, 0x0037b80f, 0x00b7b80f, 0x0137b80f, + 0x01b7b80f, 0xb630001b, 0x003f8030, 0x005f8034, + 0x5ee2b80f, 0x8013007f, 0x9800ffff, 0xb6370011, + 0x41008000, 0x51018008, 0x4902800c, 0x40c08000, + 0x0008a028, 0x48c18008, 0x50c2800c, 0x42808004, + 0x00c8b806, 0x52828008, 0x5281800c, 0x41008004, + 0x0088a034, 0x49028008, 0x4901800c, 0x011fa026, + 0x0188a028, 0x001f8001, 0x001f8005, 0x001f8009, + 0x001f800d, 0x5de1b80f, 0x5a01b810, 0x0017b80d, + 0x0097b80e, 0x902d0004, 0x0117b801, 0x904e0004, + 0x0197b802, 0x82171600, 0x82971700, 0x5ea1b80a, + 0x8013007f, 0x9800ffff, 0xb6350013, 0x003f8030, + 0x005f8034, 0x42408000, 0x52418008, 0x4a42800c, + 0x41008000, 0x0008a052, 0x49018008, 0x5102800c, + 0x42808004, 0x0108b808, 0x52828008, 0x5281800c, + 0x40c08004, 0x0088a054, 0x48c28008, 0x48c1800c, + 0x011fa048, 0x0188a046, 0x81a71100, 0x81c71200, + 0x858c0001, 0xb4e0ff7e, 0x00ffb81c, 0x00000000, + 0x005f03fa, 0x00000000, 0xb0020000, 0xb4000034, + 0x81b70080, 0x81d7ffff, 0x81f70001, 0x82370080, + 0x8257ffff, 0x82770001, 0x82b70080, 0x82d7ffff, + 0x82f70001, 0x83370080, 0x8357ffff, 0x83770001, + 0x81971000, 0x82171100, 0x82971200, 0x83171300, + 0x815703fc, 0x81370200, 0x81170c00, 0x83d703fc, + 0x83b70200, 0x83970f00, 0x8057ffff, 0x80d7ffff, + 0x80171400, 0x80971500, 0x001f800d, 0x003f8019, + 0xb6004012, 0x41008000, 0x51018004, 0x007f8011, + 0x0128a008, 0x41018000, 0x49008004, 0x009f8015, + 0x03a8a008, 0x41038000, 0x51048004, 0x001f800d, + 0x03a8a008, 0x41048020, 0x49038024, 0x003f8019, + 0x0128a008, 0x005f8028, 0x005f803c, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x00ffb81c, + 0x82370040, 0x8257ffff, 0x82770001, 0x82b70040, + 0x82d7ffff, 0x82f70001, 0x82171000, 0x82971200, + 0x8157ffff, 0x81170c00, 0x81d7ffff, 0x81970e00, + 0x8057ffff, 0x80d7ffff, 0x80171800, 0x80971a00, + 0xb600800a, 0x001f8011, 0x003f8015, 0x41008000, + 0x51018004, 0x00000000, 0x0108a028, 0x41018020, + 0x49008024, 0x00000000, 0x0188a028, 0x82770000, + 0x82f70000, 0x00ffb81c, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x808f0000, + 0x015f0384, 0x017f037a, 0xac4a0006, 0x8027b004, + 0x1042b80b, 0x5841b802, 0x1021b802, 0x0159b801, + 0x013f0325, 0x01bf0320, 0x5822b80b, 0x90210340, + 0x00ff9801, 0x8027b2e8, 0x5842b807, 0x1021b802, + 0x025bb801, 0x80070000, 0xac4d0006, 0x8027b004, + 0x1042b800, 0x5841b802, 0x1021b802, 0x0199b801, + 0x00000000, 0xac4c0006, 0x8027b078, 0x1042b80a, + 0x5842b802, 0x1021b802, 0x011bb801, 0x00000000, + 0x40d2b808, 0x00000000, 0xb0060000, 0xb4000080, + 0x005f033b, 0x80278400, 0xac600080, 0x5c22b801, + 0x10a1b803, 0xb0020000, 0xb4200002, 0x80279000, + 0xb5000001, 0x80279c00, 0x5c22b801, 0x11e1b803, + 0x80470300, 0x5822b800, 0x1042b801, 0x003f9802, + 0x806f001f, 0x80af001f, 0xb0010000, 0xb4200024, + 0x80170c00, 0x80971000, 0x003f8020, 0xb6000003, + 0x4201b806, 0x003f8020, 0x0088a030, 0x80270400, + 0xb6000208, 0x00cfb801, 0x00bfb0bc, 0x58a2b805, + 0x01afb805, 0x00bf90bc, 0xb520ffff, 0x90210020, + 0x90a50020, 0xb6000408, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x90210020, 0x91ef0020, 0xb6000208, 0x00cfb801, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x90210020, 0x90a50020, 0xb5000043, + 0x80270400, 0x0087b805, 0x01c7b80f, 0xb6000208, + 0x00cfb801, 0x009fb0bc, 0x5882b804, 0x01cfb804, + 0x009f90bc, 0xb520ffff, 0x90210020, 0x90840020, + 0xb6000408, 0x00cfb801, 0x01dfb0bc, 0x59c2b80e, + 0x01cfb80e, 0x01df90bc, 0xb520ffff, 0x90210020, + 0x91ce0020, 0xb6000208, 0x00cfb801, 0x009fb0bc, + 0x5882b804, 0x01cfb804, 0x009f90bc, 0xb520ffff, + 0x90210020, 0x90840020, 0x80170c00, 0x80971000, + 0x8053007f, 0x9842ffff, 0xb6000004, 0x42028004, + 0x4a068020, 0x00000000, 0x0088a030, 0x80270400, + 0xb6000208, 0x00cfb801, 0x00bfb0bc, 0x58a2b805, + 0x01afb805, 0x00bf90bc, 0xb520ffff, 0x90210020, + 0x90a50020, 0xb6000408, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x90210020, 0x91ef0020, 0xb6000208, 0x00cfb801, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x90210020, 0x90a50020, 0x5822b800, + 0x90210300, 0x0117b801, 0x80470001, 0x011fa002, + 0x90000001, 0x3000b809, 0xb480ff6b, 0x00ffb81c, + 0x8057ffff, 0x013f0325, 0x015f033b, 0x80171000, + 0x80070000, 0xb6002001, 0x001fa020, 0xb00a0001, + 0xb4c00002, 0x81679000, 0xb5000001, 0x81679c00, + 0x5d62b80b, 0x81878400, 0x5d82b80c, 0x80070000, + 0x5822b800, 0x90410300, 0x003f9802, 0x00000000, + 0xb0010000, 0xb4200019, 0xac400080, 0x00000000, + 0x10ccb802, 0x10abb802, 0x806f001f, 0x80af001f, + 0x80cf0400, 0xb6000408, 0xb520ffff, 0x00dfb0bc, + 0x58c2b806, 0x01afb806, 0x00df90bc, 0xb520ffff, + 0x80cf0400, 0x90c60020, 0x80cf0400, 0xb6000407, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x80cf0400, 0x90a50020, 0x90000001, + 0x3000b809, 0xb480ffde, 0x00ffb81b, 0x8057ffff, + 0x013f0325, 0x80171000, 0x80070000, 0xb6002001, + 0x001fa020, 0x81878400, 0x5d82b80c, 0x80070000, + 0x5822b800, 0x90410300, 0x003f9802, 0x00000000, + 0xb0010000, 0xb420000f, 0xac400080, 0x00000000, + 0x10ccb802, 0x806f001f, 0x80af001f, 0x80cf0400, + 0xb6000408, 0xb520ffff, 0x00dfb0bc, 0x58c2b806, + 0x01afb806, 0x00df90bc, 0xb520ffff, 0x80cf0400, + 0x90c60020, 0x90000001, 0x3000b809, 0xb480ffe8, + 0x00ffb81b, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x8139b000, 0x00000000, 0xb0090000, 0xb4000012, + 0x806f001f, 0x80af001f, 0x80cf0400, 0x013fb0bc, + 0x5922b809, 0x01cfb809, 0x013f90bc, 0xb520ffff, + 0x806f0003, 0x80af0003, 0x80cf0420, 0x91290020, + 0x013fb0bc, 0x5922b809, 0x01cfb809, 0x013f90bc, + 0xb520ffff, 0xb5000233, 0x80270000, 0x80171000, + 0xb6002401, 0x001fa021, 0x007f0384, 0x009f0320, + 0x00bf0385, 0x00df0386, 0x80e7b36c, 0x5821b803, + 0x1021b807, 0x0159b801, 0x5821b804, 0x1021b807, + 0x0179b801, 0x80e7b37c, 0x5821b803, 0x1021b807, + 0x0199b801, 0x5821b804, 0x1021b807, 0x01b9b801, + 0x80e7b38c, 0x5821b803, 0x1021b807, 0x01d9b801, + 0x5821b804, 0x1021b807, 0x01f9b801, 0x005f0385, + 0x8027b39c, 0x5842b802, 0x1021b802, 0x021bb801, + 0x005f0386, 0x8027b3ac, 0x5842b802, 0x1021b802, + 0x023bb801, 0x027f0383, 0x003f0328, 0x005f4195, + 0xb0130007, 0xb42000df, 0xb0010000, 0xb42000dd, + 0xb0020000, 0xb40000db, 0xb0030002, 0xb48000d9, + 0x029bb802, 0x82a7b108, 0xb00b0001, 0xb4200001, + 0xb5000005, 0xb00b0002, 0xb4200002, 0x92b500a0, + 0xb5000001, 0x92b50140, 0xb0030004, 0xb4600002, + 0x82870000, 0xb5000006, 0xb0030006, 0xb4600004, + 0xb0140001, 0xb4a00002, 0x82870001, 0xb5000000, + 0xac54000a, 0x806f0009, 0x80af0009, 0x5c22b815, + 0x80cf0440, 0x1021b802, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0xb0030003, + 0xb400000f, 0xb0030004, 0xb400001d, 0xb0030005, + 0xb400002b, 0xb0030006, 0xb4000042, 0xb0030007, + 0xb4000059, 0x80171000, 0x005f9440, 0x001fa002, + 0x80171038, 0x005f9440, 0x001fa002, 0xb5000073, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171004, + 0x005f9443, 0x001fa002, 0x8017101c, 0x005f9446, + 0x001fa002, 0x80171034, 0x005f9449, 0x001fa002, + 0x80171038, 0x005f9440, 0x001fa002, 0xb5000063, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171008, + 0x005f9441, 0x001fa002, 0x80171020, 0x005f9444, + 0x001fa002, 0x80171034, 0x005f9440, 0x001fa002, + 0x80171038, 0x005f9447, 0x001fa002, 0xb5000053, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171004, + 0x005f9443, 0x001fa002, 0x8017100c, 0x005f9441, + 0x001fa002, 0x8017101c, 0x005f9446, 0x001fa002, + 0x80171024, 0x005f9444, 0x001fa002, 0x80171034, + 0x005f9449, 0x001fa002, 0x80171038, 0x005f9440, + 0x001fa002, 0x8017103c, 0x005f9447, 0x001fa002, + 0xb500003a, 0x80171000, 0x005f9440, 0x001fa002, + 0x80171008, 0x005f9441, 0x001fa002, 0x8017100c, + 0x005f9442, 0x001fa002, 0x80171020, 0x005f9444, + 0x001fa002, 0x80171024, 0x005f9445, 0x001fa002, + 0x80171034, 0x005f9440, 0x001fa002, 0x80171038, + 0x005f9447, 0x001fa002, 0x8017103c, 0x005f9448, + 0x001fa002, 0xb5000021, 0x80171000, 0x005f9440, + 0x001fa002, 0x80171004, 0x005f9443, 0x001fa002, + 0x8017100c, 0x005f9441, 0x001fa002, 0x80171010, + 0x005f9442, 0x001fa002, 0x8017101c, 0x005f9446, + 0x001fa002, 0x80171024, 0x005f9444, 0x001fa002, + 0x80171028, 0x005f9445, 0x001fa002, 0x80171034, + 0x005f9449, 0x001fa002, 0x80171038, 0x005f9440, + 0x001fa002, 0x8017103c, 0x005f9447, 0x001fa002, + 0x80171040, 0x005f9448, 0x001fa002, 0x80270001, + 0x803eff90, 0x80171000, 0x82b30020, 0x9ab50000, + 0x40158020, 0xb6000501, 0x48158020, 0x82b30020, + 0x9ab50000, 0x80470000, 0x3015b800, 0xb4600006, + 0x80171000, 0x83840226, 0xb6000603, 0x40028000, + 0x00000000, 0x0008a020, 0x80171018, 0x82b30020, + 0x9ab50000, 0x40158020, 0xb6000501, 0x48158020, + 0x82b30020, 0x9ab50000, 0x80470000, 0x3015b800, + 0xb4600006, 0x80171018, 0x83840215, 0xb6000603, + 0x40028000, 0x00000000, 0x0008a020, 0x80171030, + 0x82b30020, 0x9ab50000, 0x40158020, 0xb6000501, + 0x48158020, 0x82b30020, 0x9ab50000, 0x80470000, + 0x3015b800, 0xb4600006, 0x80171030, 0x83840204, + 0xb6000603, 0x40028000, 0x00000000, 0x0008a020, + 0xb500011e, 0x80270000, 0x803eff90, 0xb0030000, + 0xb4200067, 0x025f0322, 0xb00b0001, 0xb4200016, + 0xb0120001, 0xb4200005, 0x80171018, 0x8033007f, + 0x9821ffff, 0x001fa001, 0xb5000110, 0xb0120002, + 0xb4200005, 0x80171020, 0x8033007f, 0x9821ffff, + 0x001fa001, 0xb5000109, 0x80171018, 0x80330040, + 0x98210000, 0x001fa001, 0x80171020, 0x00000000, + 0x001fa001, 0xb5000101, 0xb00b0002, 0xb420002c, + 0xb0120000, 0xb4200008, 0x80171000, 0x8033007f, + 0x9821ffff, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000f5, 0xb0120001, 0xb4200008, + 0x80171000, 0x8033005a, 0x98218279, 0x001fa001, + 0x80171030, 0x00000000, 0x001fa001, 0xb50000eb, + 0xb0120002, 0xb4200008, 0x80171008, 0x8033005a, + 0x98218279, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000e1, 0x80171000, 0x80330040, + 0x98210000, 0x001fa001, 0x80171008, 0x00000000, + 0x001fa001, 0x8017100c, 0x00000000, 0x001fa001, + 0x80171038, 0x00000000, 0x001fa001, 0xb50000d3, + 0xb0120000, 0xb4200008, 0x80171000, 0x8033007f, + 0x9821ffff, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000c9, 0xb0120001, 0xb4200005, + 0x80171018, 0x8033007f, 0x9821ffff, 0x001fa001, + 0xb50000c2, 0xb0120002, 0xb4200005, 0x80171020, + 0x8033007f, 0x9821ffff, 0x001fa001, 0xb50000bb, + 0x80171018, 0x80330040, 0x98210000, 0x001fa001, + 0x80171020, 0x00000000, 0x001fa001, 0xb50000b3, + 0x80070000, 0x8033007f, 0x9821ffff, 0xb600050e, + 0x144eb80f, 0xb0028000, 0xb4c00008, 0xac400006, + 0x00000000, 0x1042b800, 0x5842b802, 0x90421000, + 0x0017b802, 0x00000000, 0x001fa001, 0x90000001, + 0x59c1b80e, 0x59e1b80f, 0xb0040000, 0xb4200023, + 0xb00a0002, 0xb4000007, 0x80171004, 0x8033005a, + 0x98218279, 0x001fa001, 0x80171034, 0x00000000, + 0x001fa001, 0xb00c0002, 0xb4000009, 0x8017100c, + 0x8033ffa5, 0x98217d87, 0x001fa001, 0x8017103c, + 0x8033005a, 0x98218279, 0x001fa001, 0xb500008b, + 0x8017100c, 0x8033ffa5, 0x98217d87, 0x001fa001, + 0x80171010, 0x00000000, 0x001fa001, 0x8017103c, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171040, + 0x00000000, 0x001fa001, 0xb500007c, 0xb0040001, + 0xb420002a, 0xb00a0001, 0xb4000007, 0x80171018, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171020, + 0x00000000, 0x001fa001, 0xb00a0003, 0xb420000a, + 0x8053005a, 0x98428279, 0x4030b802, 0x8017101c, + 0x5821b801, 0x00000000, 0x00000000, 0x00000000, + 0x0028b801, 0x001fa001, 0xb00c0001, 0xb4200007, + 0x8053005a, 0x98428279, 0x4031b802, 0x80171024, + 0x0028b801, 0x001fa001, 0xb500005c, 0xb00c0002, + 0xb420005a, 0x8053005a, 0x98428279, 0x4031b802, + 0x80171024, 0x0028b801, 0x001fa001, 0x80171028, + 0x00000000, 0x001fa001, 0xb5000050, 0xb00b0002, + 0xb4200012, 0xb00a0001, 0xb4200008, 0x80171004, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171034, + 0x00000000, 0x001fa001, 0xb5000008, 0xb00a0003, + 0xb4200006, 0x80171004, 0x00000000, 0x001fa010, + 0x80171034, 0x00000000, 0x001fa010, 0xb00c0001, + 0xb4200025, 0x027f0383, 0x003f0328, 0xb0130007, + 0xb420000b, 0xb00b0003, 0xb4200009, 0xb0010000, + 0xb4200007, 0x80171024, 0x00000000, 0x001fa011, + 0x80171054, 0x80270000, 0x001fa001, 0xb500002b, + 0xb00d0000, 0xb420000a, 0x8033005a, 0x98218279, + 0x4041b811, 0x8017100c, 0x0048b802, 0x001fa002, + 0x8017103c, 0x00000000, 0x001fa002, 0xb500001f, + 0xb00d0002, 0xb420001d, 0x80171054, 0x8033005a, + 0x98218279, 0x001fa001, 0x8017106c, 0x00000000, + 0x001fa001, 0xb5000015, 0xb00c0002, 0xb4200013, + 0xb00d0000, 0xb4200007, 0x8017100c, 0x00000000, + 0x001fa011, 0x80171040, 0x00000000, 0x001fa011, + 0xb500000a, 0xb00d0001, 0xb4200008, 0x80171054, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171058, + 0x00000000, 0x001fa001, 0xb5000000, 0x029f0388, + 0x02bf0321, 0xb0140000, 0xb4000006, 0xb0150000, + 0xb4000004, 0x8017108c, 0x8033007f, 0x9821ffff, + 0x001fa001, 0x8027b078, 0x5c22b801, 0x806f001f, + 0x80af001f, 0x80cf0400, 0x003fb0bc, 0x5822b801, + 0x01afb801, 0x003f90bc, 0xb520ffff, 0x90210020, + 0x806f0003, 0x80af0003, 0x80cf0420, 0x003fb0bc, + 0x5822b801, 0x01afb801, 0x003f90bc, 0xb520ffff, + 0x81270000, 0x8033007f, 0x9821ffff, 0x80171000, + 0xb600060a, 0x80470000, 0xb6000603, 0x015f8020, + 0x0156b80a, 0x1042b80a, 0x3002b801, 0xb4a00001, + 0x81270001, 0x00000000, 0x00000000, 0x015f0323, + 0x00000000, 0xb00a0000, 0xb4200002, 0x81670000, + 0xb5000001, 0x81670001, 0x017f23fb, 0x01ff41ee, + 0x59f0b80f, 0x61f0b80f, 0x021f41ef, 0x5a10b810, + 0x6210b810, 0xb00a0003, 0xb420003b, 0x017f039f, + 0x019f41c5, 0x5990b80c, 0x6190b80c, 0xb00b0000, + 0xb400000c, 0xb00c0000, 0xb4000005, 0xac4c0100, + 0x8033001d, 0x98215500, 0x12c1b802, 0xb500000f, + 0xac4f0100, 0x8033001d, 0x98215500, 0x12c1b802, + 0xb500000a, 0xb0090000, 0xb4000005, 0xac4f0100, + 0x8033ffe2, 0x9821ab00, 0x12c1b802, 0xb5000003, + 0xac4f0100, 0x00000000, 0x02c7b802, 0xb0030000, + 0xb420007e, 0x01bf03a0, 0x01df41c9, 0x59d0b80e, + 0x61d0b80e, 0xb00d0000, 0xb400000c, 0xb00e0000, + 0xb4000005, 0xac4e0100, 0x8033001d, 0x98215500, + 0x12e1b802, 0xb5000071, 0xac500100, 0x8033001d, + 0x98215500, 0x12e1b802, 0xb500006c, 0xb0090000, + 0xb4000005, 0xac500100, 0x8033ffe2, 0x9821ab00, + 0x12e1b802, 0xb5000065, 0xac500100, 0x00000000, + 0x02e7b802, 0xb5000061, 0xb00a0002, 0xb420002f, + 0x023f9002, 0x025f9001, 0xb00f0000, 0xb4a00007, + 0xac4f0100, 0x00000000, 0x4022b811, 0x00000000, + 0x0028b801, 0x02c7b801, 0xb500000c, 0xb0090000, + 0xb4000004, 0xac4f0100, 0x00000000, 0x02c7b802, + 0xb5000006, 0xac4f0100, 0x00000000, 0x4022b812, + 0x00000000, 0x0028b801, 0x02c7b801, 0xb0030000, + 0xb4200046, 0xb0100000, 0xb4a00007, 0xac500100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02e7b801, 0xb500003d, 0xb0090000, 0xb4000004, + 0xac500100, 0x00000000, 0x02e7b802, 0xb5000037, + 0xac500100, 0x00000000, 0x4022b812, 0x00000000, + 0x0028b801, 0x02e7b801, 0xb5000030, 0x023f9002, + 0x025f9001, 0xb00f0000, 0xb4a00007, 0xac4f0100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02c7b801, 0xb5000006, 0xac4f0100, 0x00000000, + 0x4022b812, 0x00000000, 0x0028b801, 0x02c7b801, + 0xb0090000, 0xb4000005, 0x0047b816, 0x8033ffe2, + 0x9821ab00, 0x1042b801, 0x02c7b802, 0xb0030000, + 0xb4200016, 0xb0100000, 0xb4a00007, 0xac500100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02e7b801, 0xb5000006, 0xac500100, 0x00000000, + 0x4022b812, 0x00000000, 0x0028b801, 0x02e7b801, + 0xb0090000, 0xb4000005, 0x0047b817, 0x8033ffe2, + 0x9821ab00, 0x1042b801, 0x02e7b802, 0x00000000, + 0x00000000, 0x02c8b816, 0x02dfb0cf, 0xb0030000, + 0xb4200002, 0x02e8b817, 0x02ffb0c6, 0x00ffb81b, + 0xb6001807, 0x5841b802, 0x3015b800, 0xb4800002, + 0x06b5b800, 0x98420001, 0x5aa1b815, 0x00000000, + 0x00ffb81c, 0x00000000, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815bb3f0, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717f4, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a0002d, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200001, + 0x8384020c, 0x80af001f, 0x808f0000, 0x806f0000, + 0x80670400, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x801bb3f8, 0x80270001, 0xb0000001, + 0xb4000002, 0x802600a0, 0x803eb3f8, 0x81270c00, + 0xb00a0000, 0xb4000001, 0x81270000, 0x813eb3f0, + 0x80270001, 0x003f2013, 0x00ffb81b, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009c, 0x96b48000, 0xb0158000, + 0xb4000195, 0x96b40100, 0xb0150100, 0xb40001ab, + 0x96b40400, 0xb0150400, 0xb40001ac, 0x96b40001, + 0xb0150001, 0xb400000c, 0x96b40008, 0xb0150008, + 0xb400019e, 0x96b44000, 0xb0154000, 0xb40001ab, + 0x96b40002, 0xb0150002, 0xb4000162, 0x00000000, + 0x00000000, 0xb50001bd, 0x02bf9017, 0x92b50001, + 0x02bfb017, 0x82850082, 0x5efdb814, 0x96f70001, + 0xb0170001, 0xb420000b, 0x83050069, 0x9718003f, + 0x82e50064, 0x12f7b818, 0x86f70109, 0x82feff74, + 0x02e7b86f, 0x9af74000, 0x01ffb817, 0x96f7bfff, + 0x01ffb817, 0x83050081, 0x82a5009a, 0x96b50001, + 0xb0150001, 0xb4200014, 0x82a70000, 0x02bfb017, + 0x96b41840, 0xb0150800, 0xb420000c, 0x96b40008, + 0x5aa9b815, 0x96d46000, 0x5ec3b816, 0x82f3000f, + 0x9af7c00f, 0x1718b817, 0x1ab5b818, 0x1ab5b816, + 0x9ab50340, 0x82a60081, 0xb5000132, 0x9b180180, + 0x83060081, 0xb500012f, 0x82a5009a, 0x96b50002, + 0xb0150002, 0xb420001b, 0x82a70000, 0x02bfb017, + 0x96b41800, 0xb0151800, 0xb4000013, 0x96b40040, + 0xb0150040, 0xb4200004, 0xa3180c00, 0x9b180340, + 0x83060081, 0xb500011f, 0x96b40008, 0x5aa9b815, + 0x96d46000, 0x5ec3b816, 0x82f3000f, 0x9af7c00f, + 0x1718b817, 0x1ab5b818, 0x1ab5b816, 0x9ab50340, + 0x82a60081, 0xb5000113, 0x9b180180, 0x83060081, + 0xb5000110, 0x82a500c1, 0x96b5000f, 0xb015000b, + 0xb420000e, 0x96b40020, 0xb0150020, 0xb400000b, + 0x96b40200, 0xb0150200, 0xb4000008, 0x82c50086, + 0x82e50094, 0x3016b817, 0xb4400004, 0x06f7b816, + 0xb017ff00, 0xb4400001, 0xb50000fe, 0x96b46000, + 0xb0156000, 0xb4000011, 0x96b41820, 0xb0150820, + 0xb4200004, 0x9b391000, 0x82a5009a, 0x96b5feff, + 0x82a6009a, 0x96b40040, 0xb0150040, 0xb4200001, + 0x9739efff, 0x96b91000, 0xb0151000, 0xb4200003, + 0x82a5009a, 0x9ab50100, 0x82a6009a, 0x96b40040, + 0xb0150040, 0xb4200019, 0x96b41800, 0xb0151800, + 0xb4200006, 0x96b98000, 0xb0158000, 0xb4200003, + 0x9b180180, 0x83060081, 0xb50000de, 0x96d80c00, + 0x82b300ff, 0x9ab5f3ff, 0x1718b815, 0xb0160c00, + 0xb4000007, 0x82e50098, 0x96f70400, 0xb0170400, + 0xb4200002, 0x82c70c00, 0xb5000001, 0xa2d60c00, + 0x1b18b816, 0x9b180340, 0xb50000c4, 0x96b40220, + 0xb0150000, 0xb4e00028, 0x82a5009d, 0x82f3ffff, + 0x16b5b817, 0x82f3000e, 0x3015b817, 0xb4200022, + 0x96f98000, 0xb0178000, 0xb400001f, 0x82a70000, + 0x02bfb017, 0x82c50081, 0x9ab60020, 0x82a60081, + 0x82a50086, 0x92b50bb8, 0x82a60094, 0x82c60081, + 0x82c5009d, 0x96d6ffff, 0x82b30032, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b30022, 0x9ab58001, 0x1ab5b816, 0x82c5009a, + 0x96d60020, 0xb0160020, 0xb4200002, 0x82b30032, + 0x9ab58001, 0x82a6009d, 0x02ff9017, 0x00000000, + 0xb0170040, 0xb4800000, 0x5eb5b814, 0x96b500f0, + 0x96f46000, 0x5eedb817, 0x1ab5b817, 0xb0170003, + 0xb4000004, 0x96b500ef, 0x96f70001, 0x5ae4b817, + 0x1ab5b817, 0x96d41800, 0xb0161800, 0xb400000a, + 0x96f900ff, 0x96b500ff, 0x9739ff00, 0x1b39b815, + 0x02a7b817, 0x96b500f3, 0x96d40008, 0x5ec1b816, + 0x1ab5b816, 0xb500000c, 0x96f98000, 0xb0178000, + 0xb4200007, 0x5efeb814, 0x96f70001, 0xb0170001, + 0xb4000003, 0x9b180180, 0x83060081, 0xb5000081, + 0x96b500f3, 0x9ab50008, 0x9739fff3, 0x96d40020, + 0xb0160020, 0xb4200017, 0x9b398000, 0x82c70000, + 0x02dfb017, 0x96d40010, 0x5ac8b816, 0x82f300ff, + 0x9af7cfff, 0x1718b817, 0x1b18b816, 0x9b180340, + 0x82c5009d, 0x96d6ffff, 0x82f3000e, 0x9af78001, + 0x1af7b816, 0x82c5009a, 0x96d60020, 0xb0160020, + 0xb4200002, 0x82f30032, 0x9af78001, 0x82e6009d, + 0xb500005a, 0x97397fff, 0x96b500ff, 0x5aaab815, + 0x82f300fc, 0x9af703ff, 0x1718b817, 0x1b18b815, + 0x9b180340, 0x82c5009a, 0x96d60010, 0xb0160010, + 0xb4200024, 0x82c70000, 0x02dfb017, 0x82c50086, + 0x92d60bb8, 0x82c60086, 0x82c50094, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4200002, 0x82e70bb8, + 0xb5000001, 0x82e70bb8, 0x12d6b817, 0x82e50081, + 0x9af70020, 0x82e60081, 0x82c60094, 0xa2f70020, + 0x82e60081, 0x82f30001, 0x16f7b818, 0x5ef0b817, + 0xb0170001, 0xb4000004, 0x96f84000, 0x5ee4b817, + 0x9718f3ff, 0x1b18b817, 0x82f3000a, 0x9af78000, + 0x82e6009d, 0x83060081, 0x83070001, 0x8306009f, + 0xb5000096, 0x82c5009d, 0x82f3000e, 0x9af78001, + 0x3016b817, 0xb420000f, 0x82b30032, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b30022, 0x9ab58001, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b30032, 0x9ab58001, + 0x82a6009d, 0x82c5009a, 0x96d60080, 0xb0160080, + 0xb4000011, 0x02df9017, 0x00000000, 0xb0160010, + 0xb480000d, 0x82c500c1, 0x96d6000f, 0xb016000b, + 0xb4000009, 0x82c50087, 0x96d60080, 0x5ac7b816, + 0x96f84000, 0x3017b816, 0xb4200003, 0x033f400f, + 0x9b394000, 0xb500000b, 0x9739bfff, 0x82e50061, + 0x96f70008, 0xb0170008, 0xb4000005, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4000001, 0x9718ffff, + 0x83060081, 0x83070001, 0x8306009f, 0x00000000, + 0xb500005e, 0x82850083, 0x96b400ff, 0xb015003c, + 0xb4200019, 0x96b92000, 0xb0152000, 0xb4000002, + 0x9b392000, 0xb5000014, 0x9739d3ff, 0x82870000, + 0x82860087, 0x82870008, 0x82860083, 0x829bff78, + 0x82a7001f, 0xb0140400, 0xb4000001, 0x82a70010, + 0x82a600c9, 0x829bff78, 0x00000000, 0x828600cb, + 0x8285009d, 0x82b3ffff, 0x9ab5fffd, 0x1694b815, + 0x8286009d, 0xb5000000, 0x83070002, 0x8306009f, + 0x00000000, 0xb500003d, 0x96b90800, 0xb0150800, + 0xb4200009, 0x9739f7ff, 0x82a703fd, 0x82a600cb, + 0x82a7003c, 0x82a60083, 0x8285009d, 0x9a940002, + 0x8286009d, 0xb5000004, 0x82850087, 0x5a82b814, + 0xa2940200, 0x82860087, 0xb5000000, 0x83078000, + 0x8306009f, 0x00000000, 0xb5000028, 0x83070008, + 0x8306009f, 0x00000000, 0xb5000024, 0x83070100, + 0x8306009f, 0x00000000, 0xb5000020, 0x83070000, + 0x83050081, 0x9b180180, 0x83060081, 0x83070400, + 0x8306009f, 0x00000000, 0xb5000018, 0x82870000, + 0x82850082, 0x5eb7b814, 0x96b500fc, 0x96d40006, + 0x5ec1b816, 0x1ab5b816, 0x5aacb815, 0x83050081, + 0x82d3001c, 0x9ad600ff, 0x1718b816, 0x1b18b815, + 0x9b180e00, 0x83060081, 0x83074000, 0x8306009f, + 0x8305009d, 0x82d300ff, 0x9ad6bfff, 0x1718b816, + 0x8306009d, 0x00000000, 0xb5000000, 0x029f9005, + 0x01ffb814, 0x033f600f, 0x029f900a, 0x02bf900b, + 0x02df900c, 0x02ff900d, 0x031f900e, 0x033f900f, + 0x00ffb81e, 0x02ff9010, 0x92f70b43, 0x02ffb010, + 0x02ff90cb, 0x82bbffdc, 0x829bffd8, 0x93150004, + 0x3014b815, 0xb400000f, 0x02dbb818, 0x029bb815, + 0x3017b816, 0xb480000b, 0x5a81b814, 0x029fb010, + 0x82860095, 0x8293001f, 0x9294fe00, 0x92b50008, + 0x3015b814, 0xb4800002, 0x82b3001f, 0x92b5fa00, + 0x82beffdc, 0x029f9010, 0x83250094, 0x06d4b819, + 0x02d6b816, 0xb016ffff, 0xb4a0000a, 0x8293000e, + 0x9a948001, 0x82c5009d, 0x96d6ffff, 0x1a94b816, + 0x82c5009a, 0x96d60010, 0xb0160010, 0xb4000001, + 0x8286009d, 0x00ffb81c, 0x82870001, 0x829ef500, + 0x82850086, 0x83250094, 0x06d4b819, 0x02d6b816, + 0xb016ffff, 0xb4a0000b, 0x82870001, 0x829ef504, + 0x82c50081, 0x9ab60020, 0x82a60081, 0x82a50086, + 0x92b50bbb, 0x82a60094, 0x82c60081, 0x86b505df, + 0x82a6009b, 0x00ffb81c, 0x82070028, 0x023f9006, + 0x83a4ef48, 0x80070000, 0x001fb011, 0x001f204f, + 0x003fb800, 0x001f9006, 0x5803b800, 0x80338000, + 0x1800b801, 0x003fb800, 0x005f4193, 0x5c41b802, + 0x80350000, 0x00000000, 0x0027b860, 0x80150010, + 0x5810b800, 0x80750010, 0x1863b800, 0x8087ffff, + 0x80a7770b, 0x80c70000, 0x1403b804, 0x3000b805, + 0xb4000008, 0x5888b804, 0x58a8b805, 0x90c60001, + 0xb0060003, 0xb4a0fff8, 0x84420001, 0xb4e0ffee, + 0xb5000027, 0xb0060003, 0xb4200007, 0x80150010, + 0x5810b800, 0x81150010, 0x950800ff, 0xb0080077, + 0xb4000001, 0xb500fff4, 0x001f400e, 0x98000010, + 0x98004000, 0x9400fffe, 0x001f600e, 0x80e71fc0, + 0x001f4000, 0x94000080, 0xb0000080, 0xb4200001, + 0x80e77560, 0x00ffb008, 0x80e70020, 0xb0060000, + 0xb400000e, 0x58e3b806, 0x90210020, 0x81070000, + 0x5938b803, 0x1908b809, 0x9523ff00, 0x5928b809, + 0x1908b809, 0x5d28b803, 0x9529ff00, 0x1908b809, + 0x5d38b803, 0x1908b809, 0x011fb011, 0x00ff204f, + 0x80137fff, 0x9800ffe7, 0x1421b800, 0x5c23b801, + 0x001f9006, 0x0441b800, 0x3001b800, 0xb4600002, + 0x0440b801, 0xa4422000, 0x007f90cb, 0x1063b802, + 0x007fb0cb, 0x003fb006, 0x803effec, 0x80470001, + 0x005f2013, 0xb500ebae, 0x001f400e, 0x9400000f, + 0xb0000000, 0xb4200001, 0x00ffb81f, 0xb0000001, + 0xb4000005, 0xb0000003, 0xb4000003, 0xb0000002, + 0xb4000001, 0x00ffb81f, 0x80070001, 0x001f2013, + 0xb500eb9f, 0x00000000, 0x00000000, 0x00000000, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x803bff68, 0x8078ff6c, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x803bff68, + 0x8078ff6c, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x83840126, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e7ef98, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x80270180, 0x81e7ee90, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801bef90, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x8018ef94, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x819eff68, 0x817cff6c, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801bef90, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x8018ef94, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801bef90, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x8018ef94, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e7ec70, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270240, + 0x81e7ed70, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e7ee90, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x806f0007, + 0x80af0007, 0x80270280, 0x81e7ee70, 0x5de2b80f, + 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, + 0x01ff90bc, 0xb520ffff, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x015f400e, 0x944a4000, 0xb0024000, 0xb420001e, + 0x954abfff, 0x015f600e, 0x820f001f, 0x802f001f, + 0x81470000, 0x015f23f9, 0x015fb0ba, 0x8057ffff, + 0x80770000, 0x82970400, 0x82d7ffff, 0x82f70000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6000702, + 0xb6000001, 0x029fa02a, 0x81df0004, 0x80275480, + 0x005fb801, 0x8033001f, 0x9821c000, 0x803effe0, + 0x90212000, 0x803effe4, 0x80d9ff80, 0x00df6001, + 0x814775e8, 0x015fb008, 0x003f0324, 0xb0010000, + 0xb420007e, 0x8344ebde, 0xb0180000, 0xb4000004, + 0x011f400e, 0x1908b818, 0x011f600e, 0x00ffb81f, + 0x8344f1df, 0xb00b0000, 0xb4000006, 0x023f400e, + 0x9a310002, 0x023f600e, 0x82270000, 0x023f2012, + 0x00ffb81f, 0x8364ed72, 0x82270000, 0x023f2011, + 0x80070000, 0x80170800, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002002, 0xb6003001, 0x001fa020, + 0x81df0004, 0x82270000, 0x003fb811, 0x02bf9006, + 0x5aa3b815, 0x82338000, 0x1a31b815, 0x003fb811, + 0x8067e950, 0x5c62b803, 0x81f50000, 0x019f4193, + 0x0267b80c, 0xadcc0010, 0x80170800, 0x80130000, + 0x9800f872, 0x001fa020, 0x80134e1f, 0x98000001, + 0x001fa020, 0x59d0b80e, 0x81150010, 0x1908b80e, + 0x001fa028, 0x858c0001, 0x5e01b80c, 0x5e25b810, + 0x81df0000, 0x00000000, 0x00000000, 0xb6310006, + 0xb6002005, 0x81150010, 0x5910b808, 0x00000000, + 0x81350010, 0x1808a029, 0x9630001f, 0xb0110000, + 0xb4000006, 0xb6310005, 0x81150010, 0x5910b808, + 0x00000000, 0x81350010, 0x1808a029, 0x81df0004, + 0x962c0001, 0xb0110000, 0xb4000003, 0x81150010, + 0x5910b808, 0x001fa028, 0x019f9006, 0x958cffff, + 0x00df4193, 0x58c1b806, 0x118cb806, 0xb00ce000, + 0xb4800002, 0x858ce000, 0x918cc000, 0x8153001f, + 0x118cb80a, 0x819effec, 0x019fb006, 0x015f4193, + 0x5941b80a, 0x019f90cb, 0x118cb80a, 0x019fb0cb, + 0x019f90ba, 0x918c0001, 0x019fb0ba, 0xb00c0002, + 0xb4200016, 0x019f400e, 0x940c8000, 0xb0008000, + 0xb4200012, 0x958c7fff, 0x019f600e, 0x80070000, + 0x800600a0, 0x80073da1, 0x800600a1, 0x801bff60, + 0x00000000, 0x801eff60, 0x00000000, 0x801bff60, + 0x00000000, 0x801eff60, 0x80130001, 0x98003da1, + 0x800600a1, 0x80070001, 0x800600a0, 0x003f0324, + 0x90210001, 0xb0010005, 0xb4a00001, 0x80270000, + 0x003f2324, 0x00ffb81f, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815bb3f0, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x81271800, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00032, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200001, + 0x8384fbf4, 0x80af001f, 0x808f0002, 0x806f0000, + 0x807bbf34, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600080a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290060, + 0x81df0004, 0x808f0000, 0x813bb3f8, 0x80270001, + 0xb0090001, 0xb4000002, 0x802600a0, 0x803eb3f8, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813eb3f0, 0xb0030800, 0xb4800001, 0x80670200, + 0x807ebf34, 0x80270001, 0x003f2013, 0x00ffb81b, + +}; + +static u32 AC3Ucode1f8000[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00020000, 0xffff0005, 0xffffffff, + 0x00050001, 0xffffffff, 0xffffffff, 0x00020000, + 0xffff0005, 0xffffffff, 0x00010000, 0x00050002, + 0xffffffff, 0x00020000, 0x00050003, 0xffffffff, + 0x00010000, 0x00030002, 0xffff0005, 0x00020000, + 0x00040003, 0xffff0005, 0x00010000, 0x00030002, + 0x00050004, 0x0019000d, 0x003d0025, 0x00250019, + 0x00fd003d, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x007fffff, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x007fffff, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00599999, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00599999, + 0x007fffff, 0x00599999, 0x00000000, 0x00599999, + 0x00000000, 0x00000000, 0x00000000, 0x00599999, + 0x00000000, 0x00599999, 0x007fffff, 0x00000000, + 0x00599999, 0x00599999, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00599999, 0x00599999, + 0x007fffff, 0x007fffff, 0x00000000, 0x00599999, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00599999, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x007fffff, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x007fffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00400000, + 0x00200000, 0x00100000, 0x00080000, 0x00040000, + 0x00020000, 0x00010000, 0x00008000, 0x00004000, + 0x00002000, 0x00001000, 0x00000800, 0x00000400, + 0x00000200, 0x00000100, 0x00000080, 0x00000040, + 0x00000020, 0x00000010, 0x00000008, 0x00000004, + 0x00000002, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010002, + 0x00030002, 0x00030002, 0x00030002, 0x00000000, + 0x00000000, 0x00010001, 0x00020002, 0x4000a000, + 0xe000a000, 0xf000b000, 0xf800b800, 0x005a8279, + 0x004c1bf8, 0x00400000, 0x004c1bf8, 0x005a8279, + 0x00400000, 0x00000000, 0x00400000, 0x03020100, + 0x00000000, 0x00000080, 0x00000020, 0x00000008, + 0x00000000, 0x00000001, 0x00010001, 0x10081000, + 0x10041000, 0x10081004, 0x10081008, 0x10081008, + 0x00000000, 0x00000000, 0x00000000, 0xff80000a, + 0xff80031f, 0xff800b24, 0xff801818, 0xff8029fa, + 0xff8040c9, 0xff805c86, 0xff807d2e, 0xff80a2c1, + 0xff80cd3c, 0xff80fc9f, 0xff8130e8, 0xff816a14, + 0xff81a821, 0xff81eb0e, 0xff8232d6, 0xff827f79, + 0xff82d0f2, 0xff83273e, 0xff83825b, 0xff83e244, + 0xff8446f7, 0xff84b06e, 0xff851ea6, 0xff85919b, + 0xff860949, 0xff8685aa, 0xff8706ba, 0xff878c74, + 0xff8816d3, 0xff88a5d1, 0xff89396a, 0xff89d196, + 0xff8a6e51, 0xff8b0f94, 0xff8bb55a, 0xff8c5f9b, + 0xff8d0e51, 0xff8dc176, 0xff8e7902, 0xff8f34ef, + 0xff8ff535, 0xff90b9cc, 0xff9182ae, 0xff924fd3, + 0xff932132, 0xff93f6c3, 0xff94d07f, 0xff95ae5d, + 0xff969054, 0xff97765b, 0xff98606a, 0xff994e78, + 0xff9a407c, 0xff9b366b, 0xff9c303e, 0xff9d2de9, + 0xff9e2f64, 0xff9f34a4, 0xffa03da0, 0xffa14a4c, + 0xffa25aa0, 0xffa36e8f, 0xffa48610, 0xffa5a118, + 0xffa6bf9c, 0xffa7e191, 0xffa906ec, 0xffaa2fa0, + 0xffab5ba4, 0xffac8aeb, 0xffadbd6a, 0xffaef315, + 0xffb02bdf, 0xffb167be, 0xffb2a6a4, 0xffb3e886, + 0xffb52d56, 0xffb67509, 0xffb7bf92, 0xffb90ce4, + 0xffba5cf2, 0xffbbafb0, 0xffbd050f, 0xffbe5d04, + 0xffbfb780, 0xffc11477, 0xffc273db, 0xffc3d59f, + 0xffc539b4, 0xffc6a00d, 0xffc8089d, 0xffc97355, + 0xffcae027, 0xffcc4f05, 0xffcdbfe2, 0xffcf32af, + 0xffd0a75d, 0xffd21ddf, 0xffd39625, 0xffd51022, + 0xffd68bc7, 0xffd80904, 0xffd987cd, 0xffdb0810, + 0xffdc89c1, 0xffde0cd0, 0xffdf912d, 0xffe116cb, + 0xffe29d9a, 0xffe4258b, 0xffe5ae8f, 0xffe73896, + 0xffe8c392, 0xffea4f74, 0xffebdc2b, 0xffed69aa, + 0xffeef7df, 0xfff086bd, 0xfff21634, 0xfff3a634, + 0xfff536ad, 0xfff6c792, 0xfff858d1, 0xfff9ea5b, + 0xfffb7c22, 0xfffd0e16, 0xfffea026, 0xffffcdbc, + 0xfffe3ba0, 0xfffca995, 0xfffb17ac, 0xfff985f3, + 0xfff7f479, 0xfff6634f, 0xfff4d284, 0xfff34228, + 0xfff1b249, 0xfff022f7, 0xffee9442, 0xffed0638, + 0xffeb78ea, 0xffe9ec67, 0xffe860bd, 0xffe6d5fd, + 0xffe54c35, 0xffe3c374, 0xffe23bcb, 0xffe0b547, + 0xffdf2ff7, 0xffddabec, 0xffdc2933, 0xffdaa7dd, + 0xffd927f6, 0xffd7a98f, 0xffd62cb7, 0xffd4b17b, + 0xffd337ea, 0xffd1c013, 0xffd04a05, 0xffced5ce, + 0xffcd637c, 0xffcbf31d, 0xffca84c1, 0xffc91874, + 0xffc7ae45, 0xffc64641, 0xffc4e078, 0xffc37cf6, + 0xffc21bc9, 0xffc0bcff, 0xffbf60a5, 0xffbe06c9, + 0xffbcaf79, 0xffbb5ac0, 0xffba08ae, 0xffb8b94d, + 0xffb76cac, 0xffb622d8, 0xffb4dbdc, 0xffb397c6, + 0xffb256a2, 0xffb1187d, 0xffafdd62, 0xffaea55f, + 0xffad707e, 0xffac3ecc, 0xffab1054, 0xffa9e523, + 0xffa8bd44, 0xffa798c2, 0xffa677a8, 0xffa55a02, + 0xffa43fdb, 0xffa3293d, 0xffa21634, 0xffa106c9, + 0xff9ffb08, 0xff9ef2fa, 0xff9deeab, 0xff9cee23, + 0xff9bf16c, 0xff9af892, 0xff9a039c, 0xff991295, + 0xff982586, 0xff973c78, 0xff965774, 0xff957683, + 0xff9499ad, 0xff93c0fb, 0xff92ec75, 0xff921c24, + 0xff91500f, 0xff90883f, 0xff8fc4bb, 0xff8f058b, + 0xff8e4ab6, 0xff8d9443, 0xff8ce239, 0xff8c349f, + 0xff8b8b7d, 0xff8ae6d7, 0xff8a46b5, 0xff89ab1e, + 0xff891416, 0xff8881a3, 0xff87f3cc, 0xff876a96, + 0xff86e606, 0xff866621, 0xff85eaed, 0xff85746d, + 0xff8502a6, 0xff84959e, 0xff842d57, 0xff83c9d7, + 0xff836b20, 0xff831138, 0xff82bc20, 0xff826bdc, + 0xff822070, 0xff81d9de, 0xff819829, 0xff815b54, + 0xff812360, 0xff80f051, 0xff80c228, 0xff8098e6, + 0xff80748e, 0xff805521, 0xff803a9f, 0xff80250b, + 0xff801464, 0xff8008ad, 0xff8001e4, 0xff800027, + 0xff800c7e, 0xff802c8f, 0xff806056, 0xff80a7cb, + 0xff8102e4, 0xff817191, 0xff81f3c3, 0xff828964, + 0xff83325f, 0xff83ee98, 0xff84bdf3, 0xff85a04f, + 0xff86958b, 0xff879d7f, 0xff88b804, 0xff89e4ee, + 0xff8b240e, 0xff8c7533, 0xff8dd82a, 0xff8f4cbb, + 0xff90d2ad, 0xff9269c4, 0xff9411c1, 0xff95ca62, + 0xff979365, 0xff996c81, 0xff9b5570, 0xff9d4de4, + 0xff9f5590, 0xffa16c24, 0xffa3914e, 0xffa5c4b8, + 0xffa8060d, 0xffaa54f3, 0xffacb10e, 0xffaf1a03, + 0xffb18f70, 0xffb410f7, 0xffb69e33, 0xffb936c0, + 0xffbbda37, 0xffbe8830, 0xffc14042, 0xffc40201, + 0xffc6cd00, 0xffc9a0d2, 0xffcc7d05, 0xffcf612b, + 0xffd24ccf, 0xffd53f80, 0xffd838c8, 0xffdb3833, + 0xffde3d49, 0xffe14795, 0xffe4569d, 0xffe769e9, + 0xffea80ff, 0xffed9b67, 0xfff0b8a4, 0xfff3d83c, + 0xfff6f9b5, 0xfffa1c91, 0xfffd4056, 0xffff9b78, + 0xfffc7756, 0xfff953c0, 0xfff63130, 0xfff31025, + 0xffeff117, 0xffecd484, 0xffe9bae5, 0xffe6a4b6, + 0xffe39270, 0xffe0848b, 0xffdd7b82, 0xffda77cb, + 0xffd779de, 0xffd48231, 0xffd19138, 0xffcea769, + 0xffcbc535, 0xffc8eb10, 0xffc61969, 0xffc350af, + 0xffc09151, 0xffbddbbb, 0xffbb3059, 0xffb88f92, + 0xffb5f9d0, 0xffb36f78, 0xffb0f0ef, 0xffae7e96, + 0xffac18cf, 0xffa9bff9, 0xffa7746f, 0xffa5368c, + 0xffa306aa, 0xffa0e51e, 0xff9ed23c, 0xff9cce56, + 0xff9ad9bc, 0xff98f4bc, 0xff971f9f, 0xff955aae, + 0xff93a62f, 0xff920266, 0xff906f92, 0xff8eedf3, + 0xff8d7dc4, 0xff8c1f3c, 0xff8ad294, 0xff8997fd, + 0xff886fa8, 0xff8759c3, 0xff865679, 0xff8565f2, + 0xff848852, 0xff83bdbd, 0xff830651, 0xff82622b, + 0xff81d163, 0xff815411, 0xff80ea47, 0xff809416, + 0xff80518b, 0xff8022b1, 0xff80078e, 0x00000475, + 0x000007fe, 0x00000c02, 0x000010a3, 0x000015f5, + 0x00001c08, 0x000022ed, 0x00002ab5, 0x00003371, + 0x00003d32, 0x0000480a, 0x0000540d, 0x0000614b, + 0x00006fda, 0x00007fcd, 0x00009138, 0x0000a431, + 0x0000b8cc, 0x0000cf1f, 0x0000e741, 0x00010148, + 0x00011d4b, 0x00013b61, 0x00015ba2, 0x00017e25, + 0x0001a302, 0x0001ca51, 0x0001f42c, 0x000220a9, + 0x00024fe2, 0x000281f0, 0x0002b6ea, 0x0002eee9, + 0x00032a07, 0x0003685a, 0x0003a9fc, 0x0003ef04, + 0x0004378a, 0x000483a5, 0x0004d36d, 0x000526f7, + 0x00057e5b, 0x0005d9ae, 0x00063904, 0x00069c74, + 0x00070410, 0x00076feb, 0x0007e01a, 0x000854ac, + 0x0008cdb3, 0x00094b40, 0x0009cd61, 0x000a5425, + 0x000adf98, 0x000b6fc8, 0x000c04bf, 0x000c9e87, + 0x000d3d2a, 0x000de0ae, 0x000e891a, 0x000f3674, + 0x000fe8c0, 0x00109fff, 0x00115c34, 0x00121d5d, + 0x0012e37b, 0x0013ae89, 0x00147e84, 0x00155366, + 0x00162d27, 0x00170bbf, 0x0017ef23, 0x0018d748, + 0x0019c421, 0x001ab59f, 0x001babb2, 0x001ca648, + 0x001da54f, 0x001ea8b0, 0x001fb058, 0x0020bc2d, + 0x0021cc18, 0x0022dffd, 0x0023f7c2, 0x00251348, + 0x00263272, 0x00275520, 0x00287b31, 0x0029a482, + 0x002ad0f1, 0x002c0059, 0x002d3294, 0x002e677c, + 0x002f9ee8, 0x0030d8b1, 0x003214ac, 0x003352b0, + 0x00349290, 0x0035d422, 0x00371738, 0x00385ba5, + 0x0039a13b, 0x003ae7cc, 0x003c2f2a, 0x003d7725, + 0x003ebf8d, 0x00400834, 0x004150e9, 0x0042997d, + 0x0043e1c0, 0x00452981, 0x00467092, 0x0047b6c3, + 0x0048fbe3, 0x004a3fc6, 0x004b823b, 0x004cc316, + 0x004e0228, 0x004f3f45, 0x00507a40, 0x0051b2ef, + 0x0052e925, 0x00541cba, 0x00554d85, 0x00567b5e, + 0x0057a61d, 0x0058cd9e, 0x0059f1bb, 0x005b1252, + 0x005c2f3f, 0x005d4863, 0x005e5d9d, 0x005f6ed0, + 0x00607bde, 0x006184ad, 0x00628923, 0x00638927, + 0x006484a3, 0x00657b81, 0x00666daf, 0x00675b19, + 0x006843b1, 0x00692767, 0x006a062d, 0x006adff9, + 0x006bb4c2, 0x006c847d, 0x006d4f27, 0x006e14b8, + 0x006ed52f, 0x006f9089, 0x007046c6, 0x0070f7e9, + 0x0071a3f3, 0x00724aea, 0x0072ecd3, 0x007389b6, + 0x0074219d, 0x0074b490, 0x0075429b, 0x0075cbcc, + 0x00765031, 0x0076cfd8, 0x00774ad3, 0x0077c132, + 0x00783308, 0x0078a068, 0x00790968, 0x00796e1c, + 0x0079ce9a, 0x007a2af9, 0x007a8350, 0x007ad7b8, + 0x007b2849, 0x007b751d, 0x007bbe4c, 0x007c03f1, + 0x007c4625, 0x007c8504, 0x007cc0a8, 0x007cf92c, + 0x007d2eaa, 0x007d613e, 0x007d9101, 0x007dbe10, + 0x007de883, 0x007e1076, 0x007e3603, 0x007e5943, + 0x007e7a4f, 0x007e9942, 0x007eb633, 0x007ed13a, + 0x007eea6f, 0x007f01ea, 0x007f17c0, 0x007f2c08, + 0x007f3ed7, 0x007f5043, 0x007f605e, 0x007f6f3c, + 0x007f7cf1, 0x007f898e, 0x007f9525, 0x007f9fc6, + 0x007fa982, 0x007fb268, 0x007fba86, 0x007fc1eb, + 0x007fc8a4, 0x007fcebe, 0x007fd443, 0x007fd941, + 0x007fddc2, 0x007fe1cf, 0x007fe572, 0x007fe8b4, + 0x007feb9e, 0x007fee36, 0x007ff086, 0x007ff293, + 0x007ff463, 0x007ff5fd, 0x007ff765, 0x007ff8a1, + 0x007ff9b6, 0x007ffaa7, 0x007ffb79, 0x007ffc2f, + 0x007ffccb, 0x007ffd52, 0x007ffdc6, 0x007ffe28, + 0x007ffe7b, 0x007ffec2, 0x007ffefd, 0x007fff2f, + 0x007fff58, 0x007fff7b, 0x007fff97, 0x007fffae, + 0x007fffc0, 0x007fffcf, 0x007fffdb, 0x007fffe4, + 0x007fffec, 0x007ffff1, 0x007ffff6, 0x007ffff9, + 0x007ffffb, 0x007ffffd, 0x007ffffe, 0x007fffff, + 0x007fffff, 0x007fffff, 0x007fffff, 0xff800000, + 0x00000000, 0xffa57d86, 0x005a827a, 0xff89be51, + 0x0030fbc5, 0xffcf043b, 0x007641af, 0xff8275a1, + 0x0018f8b8, 0xffb8e313, 0x006a6d99, 0xff959267, + 0x00471ced, 0xffe70748, 0x007d8a5f, 0xff809dc9, + 0x000c8bd3, 0xffaecc33, 0x0062f202, 0xff8f1d34, + 0x003c56ba, 0xffdad7f4, 0x007a7d05, 0xff8582fb, + 0x0025280c, 0xffc3a946, 0x0070e2cc, 0xff9d0dfe, + 0x005133cd, 0xfff3742d, 0x007f6237, 0xff802778, + 0x000647d9, 0xffaa0a5b, 0x005ed77d, 0xff8c4a14, + 0x0036ba20, 0xffd4e0cb, 0x00788484, 0xff83d604, + 0x001f19f9, 0xffbe31e2, 0x006dca0d, 0xff99307f, + 0x004c3fe0, 0xffed37f0, 0x007e9d56, 0xff8162aa, + 0x0012c810, 0xffb3c020, 0x0066cf81, 0xff9235f3, + 0x0041ce1e, 0xffe0e607, 0x007c29fc, 0xff877b7c, + 0x002b1f35, 0xffc945e0, 0x0073b5ec, 0xffa12883, + 0x0055f5a5, 0xfff9b827, 0x007fd888, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + +}; + +static u32 AC3Ucode1fe000[] = { + 0x00000000, 0x03020102, 0x05040403, 0x00400040, + 0x00500050, 0x00600060, 0x00700070, 0x00800080, + 0x00a000a0, 0x00c000c0, 0x00e000e0, 0x01000100, + 0x01400140, 0x01800180, 0x01c001c0, 0x02000200, + 0x02800280, 0x03000300, 0x03800380, 0x04000400, + 0x04800480, 0x05000500, 0x00460045, 0x00580057, + 0x00690068, 0x007a0079, 0x008c008b, 0x00af00ae, + 0x00d100d0, 0x00f400f3, 0x01170116, 0x015d015c, + 0x01a201a1, 0x01e801e7, 0x022e022d, 0x02b902b8, + 0x03440343, 0x03d003cf, 0x045b045a, 0x04e604e5, + 0x05720571, 0x00600060, 0x00780078, 0x00900090, + 0x00a800a8, 0x00c000c0, 0x00f000f0, 0x01200120, + 0x01500150, 0x01800180, 0x01e001e0, 0x02400240, + 0x02a002a0, 0x03000300, 0x03c003c0, 0x04800480, + 0x05400540, 0x06000600, 0x06c006c0, 0x07800780, + 0x7b67533f, 0x1513110f, 0x04d80540, 0x04100478, + 0x07000000, 0x0b000900, 0x02b002f0, 0x02300270, + 0x017001f0, 0xf80000f0, 0x01000080, 0x02000180, + 0x03000280, 0x04000380, 0x2725231f, 0x2c2b2a29, + 0x2e2e2d2d, 0x30302f2f, 0x04030201, 0x08070605, + 0x0c0b0a09, 0x100f0e0d, 0x14131211, 0x18171615, + 0x1c1b1a19, 0x2825221f, 0x37312e2b, 0x4f49433d, + 0x796d6155, 0xcdb59d85, 0x0000fde5, 0x3d3e3f40, + 0x393a3b3c, 0x35363738, 0x32333434, 0x2f2f3031, + 0x2c2c2d2e, 0x29292a2b, 0x26262728, 0x23242425, + 0x21212223, 0x1e1f2020, 0x1c1d1d1e, 0x1a1b1b1c, + 0x1819191a, 0x16171718, 0x15151516, 0x13131414, + 0x12121213, 0x10111111, 0x0f0f1010, 0x0e0e0e0f, + 0x0d0d0d0d, 0x0c0c0c0c, 0x0b0b0b0b, 0x0a0a0a0a, + 0x0909090a, 0x08080909, 0x08080808, 0x07070707, + 0x06060707, 0x06060606, 0x05050606, 0x05050505, + 0x04040505, 0x04040404, 0x04040404, 0x03030304, + 0x03030303, 0x03030303, 0x02030303, 0x02020202, + 0x02020202, 0x02020202, 0x02020202, 0x01010202, + 0x01010101, 0x01010101, 0x01010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010101, 0x00000101, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x04d004d0, + 0x04000440, 0x03c003e0, 0x03b003b0, 0x03a003a0, + 0x03a003a0, 0x039003a0, 0x03900390, 0x03800380, + 0x03700370, 0x03600360, 0x03500350, 0x03400340, + 0x03200330, 0x03000310, 0x02f002f0, 0x02f002f0, + 0x03100300, 0x03900340, 0x042003e0, 0x04900460, + 0x046004a0, 0x04400440, 0x08000520, 0x08400840, + 0x04f004f0, 0x04100460, 0x03d003e0, 0x03b003c0, + 0x03a003b0, 0x03a003a0, 0x03a003a0, 0x03900390, + 0x03800390, 0x03800380, 0x03700370, 0x03600360, + 0x03500350, 0x03400340, 0x03100320, 0x02f00300, + 0x02f002f0, 0x030002f0, 0x03500320, 0x03e00390, + 0x04500420, 0x049004a0, 0x04400460, 0x06300480, + 0x08400840, 0x05800580, 0x045004b0, 0x03f00420, + 0x03d003e0, 0x03b003c0, 0x03b003b0, 0x03a003a0, + 0x03a003a0, 0x03a003a0, 0x03a003a0, 0x03900390, + 0x03900390, 0x03800380, 0x03700380, 0x03500360, + 0x03300340, 0x03100320, 0x02f00300, 0x02f002f0, + 0x03100300, 0x03500330, 0x041003c0, 0x04a00470, + 0x04400460, 0x04e00450, 0xffaaaaab, 0x00000000, + 0x00555555, 0xff99999a, 0xffcccccd, 0x00000000, + 0x00333333, 0x00666666, 0xff924925, 0xffb6db6e, + 0xffdb6db7, 0x00000000, 0x00249249, 0x00492492, + 0x006db6db, 0xff8ba2e9, 0xffa2e8ba, 0xffba2e8c, + 0xffd1745d, 0xffe8ba2f, 0x00000000, 0x001745d1, + 0x002e8ba3, 0x0045d174, 0x005d1746, 0x00745d17, + 0xff888889, 0xff99999a, 0xffaaaaab, 0xffbbbbbc, + 0xffcccccd, 0xffddddde, 0xffeeeeef, 0x00000000, + 0x00111111, 0x00222222, 0x00333333, 0x00444444, + 0x00555555, 0x00666666, 0x00777777, 0x08070605, + 0x0c0b0a09, 0x10100e0e, 0x00000010, 0x00000000, + 0x00000010, 0x00000020, 0x00000100, 0x00000110, + 0x00000120, 0x00000200, 0x00000210, 0x00000220, + 0x00001000, 0x00001010, 0x00001020, 0x00001100, + 0x00001110, 0x00001120, 0x00001200, 0x00001210, + 0x00001220, 0x00002000, 0x00002010, 0x00002020, + 0x00002100, 0x00002110, 0x00002120, 0x00002200, + 0x00002210, 0x00002220, 0x00000000, 0x00000010, + 0x00000020, 0x00000030, 0x00000040, 0x00000100, + 0x00000110, 0x00000120, 0x00000130, 0x00000140, + 0x00000200, 0x00000210, 0x00000220, 0x00000230, + 0x00000240, 0x00000300, 0x00000310, 0x00000320, + 0x00000330, 0x00000340, 0x00000400, 0x00000410, + 0x00000420, 0x00000430, 0x00000440, 0x00001000, + 0x00001010, 0x00001020, 0x00001030, 0x00001040, + 0x00001100, 0x00001110, 0x00001120, 0x00001130, + 0x00001140, 0x00001200, 0x00001210, 0x00001220, + 0x00001230, 0x00001240, 0x00001300, 0x00001310, + 0x00001320, 0x00001330, 0x00001340, 0x00001400, + 0x00001410, 0x00001420, 0x00001430, 0x00001440, + 0x00002000, 0x00002010, 0x00002020, 0x00002030, + 0x00002040, 0x00002100, 0x00002110, 0x00002120, + 0x00002130, 0x00002140, 0x00002200, 0x00002210, + 0x00002220, 0x00002230, 0x00002240, 0x00002300, + 0x00002310, 0x00002320, 0x00002330, 0x00002340, + 0x00002400, 0x00002410, 0x00002420, 0x00002430, + 0x00002440, 0x00003000, 0x00003010, 0x00003020, + 0x00003030, 0x00003040, 0x00003100, 0x00003110, + 0x00003120, 0x00003130, 0x00003140, 0x00003200, + 0x00003210, 0x00003220, 0x00003230, 0x00003240, + 0x00003300, 0x00003310, 0x00003320, 0x00003330, + 0x00003340, 0x00003400, 0x00003410, 0x00003420, + 0x00003430, 0x00003440, 0x00004000, 0x00004010, + 0x00004020, 0x00004030, 0x00004040, 0x00004100, + 0x00004110, 0x00004120, 0x00004130, 0x00004140, + 0x00004200, 0x00004210, 0x00004220, 0x00004230, + 0x00004240, 0x00004300, 0x00004310, 0x00004320, + 0x00004330, 0x00004340, 0x00004400, 0x00004410, + 0x00004420, 0x00004430, 0x00004440, 0x00000000, + 0x00000100, 0x00000200, 0x00000300, 0x00000400, + 0x00000500, 0x00000600, 0x00000700, 0x00000800, + 0x00000900, 0x00000a00, 0x00001000, 0x00001100, + 0x00001200, 0x00001300, 0x00001400, 0x00001500, + 0x00001600, 0x00001700, 0x00001800, 0x00001900, + 0x00001a00, 0x00002000, 0x00002100, 0x00002200, + 0x00002300, 0x00002400, 0x00002500, 0x00002600, + 0x00002700, 0x00002800, 0x00002900, 0x00002a00, + 0x00003000, 0x00003100, 0x00003200, 0x00003300, + 0x00003400, 0x00003500, 0x00003600, 0x00003700, + 0x00003800, 0x00003900, 0x00003a00, 0x00004000, + 0x00004100, 0x00004200, 0x00004300, 0x00004400, + 0x00004500, 0x00004600, 0x00004700, 0x00004800, + 0x00004900, 0x00004a00, 0x00005000, 0x00005100, + 0x00005200, 0x00005300, 0x00005400, 0x00005500, + 0x00005600, 0x00005700, 0x00005800, 0x00005900, + 0x00005a00, 0x00006000, 0x00006100, 0x00006200, + 0x00006300, 0x00006400, 0x00006500, 0x00006600, + 0x00006700, 0x00006800, 0x00006900, 0x00006a00, + 0x00007000, 0x00007100, 0x00007200, 0x00007300, + 0x00007400, 0x00007500, 0x00007600, 0x00007700, + 0x00007800, 0x00007900, 0x00007a00, 0x00008000, + 0x00008100, 0x00008200, 0x00008300, 0x00008400, + 0x00008500, 0x00008600, 0x00008700, 0x00008800, + 0x00008900, 0x00008a00, 0x00009000, 0x00009100, + 0x00009200, 0x00009300, 0x00009400, 0x00009500, + 0x00009600, 0x00009700, 0x00009800, 0x00009900, + 0x00009a00, 0x0000a000, 0x0000a100, 0x0000a200, + 0x0000a300, 0x0000a400, 0x0000a500, 0x0000a600, + 0x0000a700, 0x0000a800, 0x0000a900, 0x0000aa00, + 0xff800000, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xffb82995, 0xffaf5d75, 0xffa57d87, 0xff9a6806, + 0xff8df708, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xffb82995, 0xffaf5d75, 0xffa57d87, 0xff9a6806, + 0xff8df708, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xfffb0000, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, + 0xfffdfffd, 0xfffdfffd, 0xfffdfffd, 0xfffefffe, + 0xfffefffe, 0xfffefffe, 0xffffffff, 0xffffffff, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x80050000, 0x000a800f, 0x001e801b, 0x80110014, + 0x00368033, 0x8039003c, 0x802d0028, 0x00228027, + 0x00668063, 0x8069006c, 0x807d0078, 0x00728077, + 0x80550050, 0x005a805f, 0x004e804b, 0x80410044, + 0x00c680c3, 0x80c900cc, 0x80dd00d8, 0x00d280d7, + 0x80f500f0, 0x00fa80ff, 0x00ee80eb, 0x80e100e4, + 0x80a500a0, 0x00aa80af, 0x00be80bb, 0x80b100b4, + 0x00968093, 0x8099009c, 0x808d0088, 0x00828087, + 0x01868183, 0x8189018c, 0x819d0198, 0x01928197, + 0x81b501b0, 0x01ba81bf, 0x01ae81ab, 0x81a101a4, + 0x81e501e0, 0x01ea81ef, 0x01fe81fb, 0x81f101f4, + 0x01d681d3, 0x81d901dc, 0x81cd01c8, 0x01c281c7, + 0x81450140, 0x014a814f, 0x015e815b, 0x81510154, + 0x01768173, 0x8179017c, 0x816d0168, 0x01628167, + 0x01268123, 0x8129012c, 0x813d0138, 0x01328137, + 0x81150110, 0x011a811f, 0x010e810b, 0x81010104, + 0x03068303, 0x8309030c, 0x831d0318, 0x03128317, + 0x83350330, 0x033a833f, 0x032e832b, 0x83210324, + 0x83650360, 0x036a836f, 0x037e837b, 0x83710374, + 0x03568353, 0x8359035c, 0x834d0348, 0x03428347, + 0x83c503c0, 0x03ca83cf, 0x03de83db, 0x83d103d4, + 0x03f683f3, 0x83f903fc, 0x83ed03e8, 0x03e283e7, + 0x03a683a3, 0x83a903ac, 0x83bd03b8, 0x03b283b7, + 0x83950390, 0x039a839f, 0x038e838b, 0x83810384, + 0x82850280, 0x028a828f, 0x029e829b, 0x82910294, + 0x02b682b3, 0x82b902bc, 0x82ad02a8, 0x02a282a7, + 0x02e682e3, 0x82e902ec, 0x82fd02f8, 0x02f282f7, + 0x82d502d0, 0x02da82df, 0x02ce82cb, 0x82c102c4, + 0x02468243, 0x8249024c, 0x825d0258, 0x02528257, + 0x82750270, 0x027a827f, 0x026e826b, 0x82610264, + 0x82250220, 0x022a822f, 0x023e823b, 0x82310234, + 0x02168213, 0x8219021c, 0x820d0208, 0x02028207, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000001, 0x00000002, 0x00000002, + 0x00000000, 0xff800000, 0xffa57d86, 0xffa57d86, + 0xffcf043b, 0xff89be51, 0xff89be51, 0xffcf043b, + 0xffe70748, 0xff8275a1, 0xff959267, 0xffb8e313, + 0xffb8e313, 0xff959267, 0xff8275a1, 0xffe70748, + 0xfff3742d, 0xff809dc9, 0xff9d0dfe, 0xffaecc33, + 0xffc3a946, 0xff8f1d34, 0xff8582fb, 0xffdad7f4, + 0xffdad7f4, 0xff8582fb, 0xff8f1d34, 0xffc3a946, + 0xffaecc33, 0xff9d0dfe, 0xff809dc9, 0xfff3742d, + 0xfff9b827, 0xff802778, 0xffa12883, 0xffaa0a5b, + 0xffc945e0, 0xff8c4a14, 0xff877b7c, 0xffd4e0cb, + 0xffe0e607, 0xff83d604, 0xff9235f3, 0xffbe31e2, + 0xffb3c020, 0xff99307f, 0xff8162aa, 0xffed37f0, + 0xffed37f0, 0xff8162aa, 0xff99307f, 0xffb3c020, + 0xffbe31e2, 0xff9235f3, 0xff83d604, 0xffe0e607, + 0xffd4e0cb, 0xff877b7c, 0xff8c4a14, 0xffc945e0, + 0xffaa0a5b, 0xffa12883, 0xff802778, 0xfff9b827, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; + +static u32 AC3Ucode1fff80[] = { + 0x0000240f, 0x007fffff, 0x007fffff, 0x00000003, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/ac3i2s_240.h linux.20pre2-ac1/drivers/media/video/ls220/ac3i2s_240.h --- linux.20pre2/drivers/media/video/ls220/ac3i2s_240.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/ac3i2s_240.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,2833 @@ +static u32 AC3I2S240Ucode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb5001197, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x80070800, 0x001f6193, + 0x800500d4, 0x8053ffff, 0x9842c7ff, 0x8039ff7c, + 0x1400b802, 0x003f6000, 0x94210007, 0xb0010001, + 0xb4200001, 0x98002800, 0xb0010000, 0xb4200001, + 0x98000800, 0x805300ff, 0x1800b802, 0x800600d4, + 0x8013001f, 0x9020c000, 0x003fb006, 0x803effe0, + 0x803effe8, 0x803effec, 0x9020e000, 0x9021ffe4, + 0x9020fa00, 0x803effd0, 0x803effdc, 0x803effd8, + 0x9020fe00, 0x803effd4, 0x90400000, 0x804600a2, + 0x90421800, 0x804600a3, 0x80134099, 0x98000040, + 0x800600a6, 0x80130000, 0x98003ca1, 0x800600a1, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x001f2324, 0x80070000, 0x001fb0ba, + 0x001f23f9, 0x801eb3f0, 0x80070800, 0x001f600f, + 0x80070000, 0x001f2012, 0x001fb0cb, 0x001fb010, + 0x801efff0, 0x98004000, 0x98008000, 0x001f600e, + 0x83e4012b, 0x80070000, 0x801eb3f8, 0x801eff70, + 0x800500a0, 0xb0000001, 0xb4000009, 0x80070001, + 0x800600a0, 0x80050080, 0x98000020, 0x80060080, + 0x9400ffdf, 0x80060080, 0x80070000, 0x800600a0, + 0x81df0004, 0x00000000, 0x00000000, 0x801bfff0, + 0x00000000, 0x940000ff, 0xb0000000, 0xb420004e, + 0x003f400e, 0x94010010, 0xb0000000, 0xb400fff4, + 0x838413ac, 0x003f0013, 0xb0010001, 0xb420003b, + 0x803bffe8, 0x801bffec, 0x00000000, 0x3001b800, + 0xb4600001, 0x90212000, 0x0421b800, 0x005f4193, + 0x5841b802, 0x3001b802, 0xb460000d, 0x80050086, + 0x005f9016, 0xb0020000, 0xb4200002, 0x001fb016, + 0xb500ffdf, 0x0420b802, 0xb0010b50, 0xb4a0ffdc, + 0x80070000, 0x001fb016, 0x83e400f5, 0xb500ffd8, + 0x80070000, 0x001fb016, 0x001f400e, 0x9400000f, + 0xb0000000, 0xb4000014, 0xb0000001, 0xb4000010, + 0x003f400e, 0x9421fff0, 0x003f600e, 0x003f9006, + 0x9421ffff, 0x90210004, 0xb001e000, 0xb4800002, + 0x8421e000, 0x9021c000, 0x8013001f, 0x1021b800, + 0x003fb006, 0x003f90cb, 0x90210004, 0x003fb0cb, + 0x83e400e7, 0x83e4138b, 0x8007001f, 0x94000003, + 0x5810b800, 0x83e71aa8, 0x1bffb800, 0x003f9008, + 0x1821b800, 0x00ffb801, 0x83e413de, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671ad4, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0xb500ffaa, 0x803bffc0, 0x805bffc4, + 0x807bffc8, 0x809bffcc, 0x5828b801, 0x5cb8b802, + 0x1821b805, 0x5848b802, 0x5cb8b803, 0x1842b805, + 0x5868b803, 0x5cb8b804, 0x1863b805, 0x5888b804, + 0x1884b800, 0x803effc0, 0x805effc4, 0x807effc8, + 0x809effcc, 0x003f400e, 0xb0000086, 0xb4400048, + 0xb0000084, 0xb4000032, 0xb0000085, 0xb4000038, + 0xb0000086, 0xb400003a, 0x001f4000, 0x94000080, + 0xb0000080, 0xb4000072, 0x800500d4, 0x8053ffff, + 0x9842c7ff, 0x1400b802, 0x805300ff, 0x98422800, + 0x1800b802, 0x800600d4, 0x80130000, 0x98000c7f, + 0x005f4000, 0x94420008, 0xb0020008, 0xb4200001, + 0xa0000080, 0x800600a1, 0x8013001f, 0x9040c000, + 0x005fb006, 0x805effe0, 0x805effe8, 0x805effec, + 0x9040e000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001fb0cb, + 0x001fb010, 0x001f2058, 0x80071f60, 0x001fb008, + 0x80075d70, 0x001fb009, 0x98214000, 0xb5000010, + 0x94011000, 0xb0001000, 0xb4200001, 0x9421efff, + 0x98210010, 0xb500000a, 0x80070000, 0x001fb0cb, + 0x83e4007f, 0x003f400e, 0x9421ffef, 0xb5000004, + 0x83e4007b, 0x003f400e, 0x98211000, 0x9421ffef, + 0x003f600e, 0x80070100, 0x801efff0, 0xb500ff4c, + 0xb000008b, 0xb400001c, 0xb000008e, 0xb4000022, + 0xb000008d, 0xb400001c, 0xb000008c, 0xb4000021, + 0xb0000087, 0xb400ffe8, 0xb0000088, 0xb4000014, + 0xb000008a, 0xb4000015, 0xb0000089, 0xb400001d, + 0xb00000a0, 0xb400001f, 0xb00000a1, 0xb4000041, + 0xb00000a2, 0xb400004a, 0xb00000a3, 0xb4000046, + 0xb00000a4, 0xb4000048, 0xb00000a5, 0xb4000048, + 0xb00000a6, 0xb4000048, 0x803efff8, 0xb500ffdd, + 0x9421ffdf, 0xb500ffda, 0xb500ffda, 0x80270100, + 0x803efff8, 0xb500ffd7, 0x80070000, 0x001fb017, + 0xb500ffd4, 0x801bffb0, 0x00000000, 0x001fb003, + 0xb500ffd0, 0x803bff80, 0x00000000, 0x003f6001, + 0xb500ffcc, 0x003f90ba, 0x803efff8, 0xb500ffc9, + 0x80130001, 0x98003da1, 0x800600a1, 0x80070200, + 0x801ebf34, 0x83e4002e, 0x8013001f, 0x9840c000, + 0x805effe0, 0x005fb006, 0x805effe8, 0x805effec, + 0x90422000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001f2324, + 0x001fb0cb, 0x001fb010, 0x001f2058, 0x800774b0, + 0x001fb008, 0x80077730, 0x001fb009, 0x98214000, + 0xb500ffa7, 0x80270000, 0x8047fef0, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x83641460, 0xb500ff9d, + 0x8364140e, 0xb500ff9b, 0x836413cd, 0xb500ff99, + 0x83441334, 0xb500ff97, 0x8344131d, 0xb500ff95, + 0x80070000, 0x80470000, 0xb6002003, 0xb6003002, + 0x001eb802, 0x90420004, 0x80171000, 0x8057ffff, + 0xb6002002, 0xb6001801, 0x001fa020, 0x00ffb81f, + 0x001f4000, 0x94000080, 0xb0000080, 0xb4200001, + 0xb500ffef, 0xb500000a, 0x80270000, 0x003f2013, + 0x8007001f, 0x94000003, 0x5810b800, 0x83671e60, + 0x1b7bb800, 0x003f9009, 0x1821b800, 0x00ffb801, + 0x003f0013, 0xb0010001, 0xb420fff3, 0x83a70000, + 0x803bff70, 0x00000000, 0xb0010000, 0xb4000011, + 0x80170300, 0x80070000, 0xb6000601, 0x001fa020, + 0x83640c66, 0x00ff0325, 0x82870000, 0xb6270002, + 0x83640217, 0x92940001, 0x001f033b, 0xb0000000, + 0xb4000002, 0x80270000, 0xb5000001, 0x80270001, + 0x003f233b, 0x80270000, 0x003f2013, 0x8007001f, + 0x94000003, 0x5810b800, 0x83671eec, 0x1b7bb800, + 0x003f9009, 0x1821b800, 0x00ffb801, 0x003f0013, + 0xb0010001, 0xb420fff3, 0x93bd0001, 0xb01d0004, + 0xb480ffdb, 0x803bff70, 0x00000000, 0xb0010000, + 0xb4000001, 0x83640c12, 0x00000000, 0x00000000, + 0x00ffb81f, 0x007f90cb, 0x90630400, 0x007fb0cb, + 0x003f9006, 0x9421ffff, 0x90210400, 0xb001e000, + 0xb4800002, 0x8421e000, 0x9021c000, 0x8013001f, + 0x1021b800, 0x003fb006, 0x803effec, 0x00ffb81f, + 0x015f400e, 0x944a4000, 0xb0024000, 0xb4200084, + 0x954abfff, 0x015f600e, 0x820f001f, 0x802f001f, + 0x81470000, 0x015f23f9, 0x829702ec, 0x82d7ffff, + 0x82f70000, 0xb6000501, 0x029fa02a, 0x82970400, + 0xb6000702, 0xb6000001, 0x029fa02a, 0x8053ff00, + 0x98420000, 0x805ebf14, 0x805ebf18, 0x805ebf1c, + 0x805ebf20, 0x805ebf24, 0x805ebf28, 0x80270000, + 0x003f2328, 0x80275480, 0x005fb801, 0x8033001f, + 0x9821c000, 0x803effe0, 0x90212000, 0x803effe4, + 0x80dbff8c, 0x80fbff90, 0x80debf14, 0x80febf18, + 0x80dbff94, 0x80fbff98, 0x80debf1c, 0x80febf20, + 0x80dbff9c, 0x80fbffa0, 0x80debf24, 0x80febf28, + 0x80dbff84, 0x80e70001, 0x00dfb001, 0x80dbff88, + 0x00ff6191, 0x00dfb002, 0x80dbffb0, 0x80470000, + 0x00dfb003, 0x80d9ff80, 0x005fb0cf, 0x005fb0c6, + 0x00df6001, 0x80470001, 0x005f618f, 0x804700ff, + 0x005f231c, 0x005f231d, 0x80470000, 0x005f204e, + 0x8047e138, 0x5c42b802, 0x814f6300, 0x80cf00a9, + 0x005fb0bc, 0x5842b802, 0x01cfb802, 0x005f90bc, + 0xb520ffff, 0x8067e16c, 0x5c62b803, 0x80270040, + 0xb6000209, 0x814fffc0, 0x00cfb801, 0x007fb0bc, + 0x5862b803, 0x01cfb803, 0x007f90bc, 0xb520ffff, + 0x90210020, 0x90630020, 0x8047e398, 0x5c42b802, + 0x814fce40, 0x80cf0080, 0x005fb0bc, 0x5842b802, + 0x01cfb802, 0x005f90bc, 0xb520ffff, 0x8047e400, + 0x5c42b802, 0x814f7380, 0x80cf009a, 0x005fb0bc, + 0x5842b802, 0x01cfb802, 0x005f90bc, 0xb520ffff, + 0x8047e43c, 0x5c42b802, 0x814f18c0, 0x80cf00b6, + 0x005fb0bc, 0x5842b802, 0x01cfb802, 0x005f90bc, + 0xb520ffff, 0x80e70000, 0x00ffb0ba, 0x808f0000, + 0x806f001f, 0x80af001f, 0x8027b9fc, 0x5c22b801, + 0x80670700, 0xb600080a, 0x00cfb803, 0x003fb0bc, + 0x5822b801, 0x01cfb801, 0x003f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90210020, 0x90630020, + 0x834400d3, 0xb0180000, 0xb4200025, 0x83440678, + 0x80c70000, 0x00df2324, 0x83640026, 0x83440220, + 0x00df0324, 0x90c60001, 0x00df2324, 0xb0060006, + 0xb4000003, 0x81472198, 0x015fb008, 0x00ffb81f, + 0x00ff90ba, 0x90e70001, 0x00ffb0ba, 0x019f9006, + 0x958cffff, 0x00df4193, 0x58c1b806, 0x118cb806, + 0xb00ce000, 0xb4800002, 0x858ce000, 0x918cc000, + 0x8153001f, 0x118cb80a, 0x819effec, 0x019fb006, + 0x015f4193, 0x5941b80a, 0x019f90cb, 0x118cb80a, + 0x019fb0cb, 0x81472180, 0x015fb008, 0x00ffb81f, + 0x015f400e, 0x194ab818, 0x015f600e, 0x802500a5, + 0x00ffb81f, 0x803bff8c, 0x805bff90, 0x803ebf14, + 0x805ebf18, 0x803bff94, 0x805bff98, 0x803ebf1c, + 0x805ebf20, 0x803bff9c, 0x805bffa0, 0x803ebf24, + 0x805ebf28, 0x80470003, 0x805ebefc, 0x003f0384, + 0x5822b801, 0x9021eb50, 0x005bb801, 0x00000000, + 0xb0020001, 0xb4200002, 0x80470001, 0x805ebefc, + 0x8073ff80, 0x98630000, 0x8027bf14, 0x8047befc, + 0xb6000609, 0x009bb801, 0x00000000, 0x00a7b804, + 0x6081b804, 0x3004b803, 0xb4000001, 0x00beb802, + 0x90210004, 0x90420004, 0x00ffb81b, 0x00000000, + 0x81150010, 0x00000000, 0x00000000, 0x81350010, + 0x00000000, 0x00000000, 0x81550002, 0x00000000, + 0x015f2380, 0x81550006, 0x00000000, 0x015f2381, + 0x81550005, 0x00000000, 0x015f2382, 0x81550003, + 0x00000000, 0x015f2383, 0x81550003, 0x015f2384, + 0xb00a0001, 0xb4000005, 0x956a0001, 0xb00b0000, + 0xb4000002, 0x81750002, 0x017f2385, 0x956a0004, + 0xb00b0000, 0xb4000002, 0x81750002, 0x017f2386, + 0xb00a0002, 0xb4200003, 0x81750002, 0x00000000, + 0x017f2387, 0x81750001, 0x00000000, 0x017f2388, + 0x81750005, 0x00000000, 0x017f2389, 0x81750001, + 0x017f239f, 0xb00b0001, 0xb4200003, 0x81750008, + 0x5968b80b, 0x017f61c5, 0x81750001, 0x017f238c, + 0xb00b0001, 0xb4200003, 0x81750008, 0x00000000, + 0x017f238d, 0x81750001, 0x017f238e, 0xb00b0001, + 0xb4200005, 0x81750005, 0x00000000, 0x017f238f, + 0x81750002, 0x017f2390, 0xb00a0000, 0xb420001b, + 0x81750005, 0x00000000, 0x017f2391, 0x81750001, + 0x017f23a0, 0xb00b0001, 0xb4200003, 0x81750008, + 0x5968b80b, 0x017f61c9, 0x81750001, 0x017f2394, + 0xb00b0001, 0xb4200003, 0x81750008, 0x00000000, + 0x017f2395, 0x81750001, 0x017f2396, 0xb00b0001, + 0xb4200006, 0x81750005, 0x00000000, 0x017f2397, + 0x81750002, 0x00000000, 0x017f2398, 0x81750001, + 0x00000000, 0x017f2399, 0x81750001, 0x00000000, + 0x017f239a, 0x81750001, 0x017f239b, 0xb00b0001, + 0xb4200003, 0x8175000e, 0x00000000, 0x017f61be, + 0x81750001, 0x017f239c, 0xb00b0001, 0xb4200003, + 0x8175000e, 0x00000000, 0x017f237e, 0x81750001, + 0x017f239d, 0xb00b0001, 0xb4200006, 0x81750006, + 0x017f239e, 0x916b0001, 0x81550008, 0x856b0001, + 0xb4e0fffd, 0x00ffb81c, 0x00000000, 0x00000000, + 0x81470000, 0x015f2385, 0x015f2386, 0x015f2387, + 0x015f238d, 0x015f238f, 0x015f2390, 0x015f2391, + 0x015f2395, 0x015f2396, 0x015f2397, 0x015f2398, + 0x015f61be, 0x015f61bf, 0x82070028, 0x023f9006, + 0x83a4003a, 0x83270000, 0x003fb819, 0x003f9006, + 0x5823b801, 0x83338000, 0x1b39b801, 0x003fb819, + 0x00000000, 0x00000000, 0x81550000, 0x8384ff64, + 0x017f0380, 0xad4b0026, 0x013f0381, 0x114ab809, + 0x5941b80a, 0x914ae00c, 0x0199b80a, 0x00000000, + 0x019f6193, 0xb0080b77, 0xb4200016, 0x015f0380, + 0xb00a0003, 0xb4600017, 0xb0090026, 0xb4600019, + 0x017f90ba, 0xb00b0000, 0xb4200004, 0x017f0384, + 0x017f204d, 0x017f0383, 0x017f2057, 0x015f0383, + 0x017f0057, 0x300ab80b, 0xb4200012, 0x015f0384, + 0x017f004d, 0x300ab80b, 0xb420000e, 0x83070000, + 0x00ffb81a, 0x83070800, 0x031f6193, 0x83070001, + 0x00ffb81a, 0x83070800, 0x031f6193, 0x83070002, + 0x00ffb81a, 0x83070800, 0x031f6193, 0x83070003, + 0x00ffb81a, 0x83070003, 0x00ffb81a, 0x5e02b810, + 0x5a02b810, 0x00bf9011, 0x00df004f, 0xa5260020, + 0x81e70000, 0x82471000, 0x95d1ffff, 0xa5cee000, + 0x300eb810, 0xb4600002, 0x05f0b80e, 0x0207b80e, + 0x8267001f, 0x82c70020, 0x82971000, 0xb0100080, + 0xb480001f, 0x5a8bb813, 0x5aa6b813, 0x1a94b815, + 0x01efb812, 0x014fb814, 0x01cfb811, 0xb520ffff, + 0xb636000f, 0x81470000, 0x039f8014, 0xb6000404, + 0x5948b80a, 0x957c00ff, 0x194ab80b, 0x5f88b81c, + 0xb0060020, 0xb4200001, 0x80a70000, 0x64a6b805, + 0x68e9b80a, 0x18a5b807, 0x029fa025, 0x00a7b80a, + 0x01efb812, 0x014fb814, 0x01afb811, 0xb520ffff, + 0x5ae2b816, 0x1231b817, 0x0610b817, 0xb500ffde, + 0xb0100000, 0xb4000003, 0x5ec2b810, 0x86760001, + 0xb500ffdc, 0xb00f0000, 0xb4000005, 0x0207b80f, + 0x81f3001f, 0x9a2fc000, 0x81e70000, 0xb500ffd0, + 0x015fb011, 0x00ffb81d, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x82d7ffff, 0x8357ffff, 0x83d7ffff, + 0x80770000, 0x80f70000, 0x81770000, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x83f70000, + 0xaeb40080, 0x808f0000, 0x806f001f, 0x80af001f, + 0xb0140000, 0xb4400014, 0x806f001f, 0x80af001f, + 0x8027b9fc, 0x5c22b801, 0x80670700, 0xb6000208, + 0x00cfb803, 0x003fb0bc, 0x5822b801, 0x01cfb801, + 0x003f90bc, 0xb520ffff, 0x90630020, 0x90210020, + 0x80270000, 0x80171000, 0xb6000303, 0xb6000001, + 0x001fa021, 0x00000000, 0x82670000, 0xb6000268, + 0x80170a00, 0x80970afc, 0x81170b00, 0x81970bfc, + 0x80271c00, 0x1021b813, 0x1021b813, 0x0217b801, + 0x80271ffc, 0x0421b813, 0x0421b813, 0x0297b801, + 0x80270c00, 0x1021b813, 0x1021b813, 0x0317b801, + 0x80270ffc, 0x0421b813, 0x0421b813, 0x0397b801, + 0x80478500, 0x1042b813, 0x5c42b802, 0x1022b815, + 0x80670280, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0x009f033b, + 0x80478480, 0x0442b813, 0x5c42b802, 0x1022b815, + 0x806702a0, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0xb0040000, + 0xb4000002, 0x80479000, 0xb5000001, 0x80479c00, + 0x1042b813, 0x5c42b802, 0x1022b815, 0x806702c0, + 0x00cfb803, 0x003fb0bc, 0x5822b801, 0x01cfb801, + 0x003f90bc, 0xb520ffff, 0xb0040000, 0xb4000002, + 0x80479180, 0xb5000001, 0x80479d80, 0x0442b813, + 0x5c42b802, 0x1022b815, 0x806702e0, 0x00cfb803, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x81270000, 0x80370000, 0x80b70000, + 0x81370000, 0x81b70000, 0x82370004, 0x82b7fffc, + 0xb6002016, 0x41498008, 0x51498814, 0x51498814, + 0x51418810, 0x51418810, 0x41818814, 0x0308a02a, + 0x49958820, 0x51898810, 0x51918828, 0x414d8814, + 0x0388a7ec, 0x494d8814, 0x49458810, 0x49458810, + 0x418d8810, 0x0308a02a, 0x49918fec, 0x51858814, + 0x51958fe4, 0x00000000, 0x0388a7ec, 0x92730080, + 0x009f033b, 0x5802b814, 0x90400300, 0x001f9802, + 0x00000000, 0xb0000000, 0xb4200016, 0x80170a00, + 0x80070000, 0xb6002001, 0x001fa020, 0xb0040000, + 0xb4200002, 0x80279000, 0xb5000001, 0x80279c00, + 0xac740080, 0x5c22b801, 0x11e1b803, 0x806f001f, + 0x80af001f, 0xb6000407, 0x80cf0280, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x91ef0020, 0x007f0320, 0x011f90cd, 0xaca30006, + 0x80c7b004, 0x10a5b814, 0x58a1b805, 0x10a5b806, + 0x0099b805, 0x8027b3dc, 0x5841b804, 0x1021b802, + 0x0159b801, 0x8027b3d0, 0x5841b804, 0x1021b802, + 0x0139b801, 0x80170c00, 0x0097b80a, 0xb6000002, + 0x59478020, 0x009fa04a, 0x00ffb81b, 0x00000000, + 0x009f0011, 0x015f0012, 0xb0060000, 0xb4200007, + 0x968a0001, 0xb0140000, 0xb400000d, 0x80870001, + 0x009f2011, 0x954a0002, 0x015f2012, 0xb0060002, + 0xb4200007, 0x968a0002, 0xb0140000, 0xb4000004, + 0x80870001, 0x009f2011, 0x81470000, 0x015f2012, + 0x8364002b, 0x00bf2010, 0xb0060000, 0xb4200003, + 0xb0050000, 0xb4200001, 0x8364008d, 0xb0050000, + 0xb4200001, 0x836400b2, 0x00bf0010, 0xb0050000, + 0xb4200006, 0x83640983, 0x8364029d, 0x00000000, + 0x8364092b, 0x00000000, 0xb5000005, 0x00bf0010, + 0xb0050001, 0xb4000002, 0x00000000, 0x83640924, + 0x00ff0325, 0x82870000, 0xb6270002, 0x8364ff08, + 0x92940001, 0x80070001, 0x801eff70, 0x001f0010, + 0xb0000001, 0xb4000007, 0x001f033b, 0xb0000000, + 0xb4000002, 0x80270000, 0xb5000001, 0x80270001, + 0x003f233b, 0x00ffb81a, 0x00000000, 0x00000000, + 0x027f4001, 0x5e2ab813, 0x96310003, 0x81c70000, + 0x820700ff, 0xb0110000, 0xb4000005, 0x5a21b811, + 0x81c70200, 0x8207000e, 0x69d1b80e, 0x1210b811, + 0x01dfb0cd, 0x5e2cb813, 0x96310003, 0x023f2323, + 0x5e28b813, 0x96310003, 0x023f2322, 0x5e27b813, + 0x96310001, 0x023f2328, 0x5e23b813, 0x96310001, + 0x023f2321, 0x95f30007, 0x01ff2320, 0x920fe004, + 0x0258b810, 0x00000000, 0x1252b811, 0x025f2325, + 0x8167befc, 0x017f6195, 0x021f031c, 0x01df031d, + 0x3010b80f, 0xb4200003, 0x3011b80e, 0xb4200001, + 0xb5000021, 0x80270000, 0x80471000, 0x0017b802, + 0x8057ffff, 0xb6002001, 0x001fa021, 0x80270400, + 0x80679000, 0x5c62b803, 0xb6001809, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01afb803, 0x007f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x80679c00, 0x5c62b803, 0xb6001809, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01afb803, 0x007f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x01ff231c, 0x023f231d, 0x83970300, 0x82070000, + 0xb6320001, 0x039fa030, 0x00bf0010, 0x021f0324, + 0xb0100000, 0xb4200001, 0x80a70000, 0xb0050000, + 0xb4200008, 0xb0040000, 0xb4a00002, 0x80a70001, + 0xb5000004, 0x82070000, 0x021f204e, 0xb4000001, + 0x80a70002, 0xb0050001, 0xb4200007, 0x021f004e, + 0xb0100002, 0xb4a00002, 0x80a70002, 0x00ffb81b, + 0x92100001, 0x021f204e, 0x00000000, 0x00ffb81b, + 0x81530000, 0x003fb80a, 0x00000000, 0x00000000, + 0x003fb819, 0x00000000, 0x00000000, 0x81550000, + 0x8384fd7b, 0x81470000, 0x015f61ee, 0x015f61ef, + 0x015f23a4, 0x8297050c, 0x82d7ffff, 0xb6000501, + 0x029fa02a, 0x8167e004, 0x116b0384, 0x0158b80b, + 0x019f0382, 0x015f237b, 0x017f0388, 0x116bb80a, + 0xb00c0008, 0xb4a00003, 0x80a70003, 0x00bf2010, + 0x00ffb81b, 0xb00a0005, 0xb4400003, 0xb00b0006, + 0xb4400001, 0x00ffb81b, 0x80a70004, 0x00bf2010, + 0x00ffb81b, 0x00000000, 0x00000000, 0x00000000, + 0x027f0388, 0x02bf037b, 0x02df0384, 0x02ff03a1, + 0x82970400, 0x8257ffff, 0x82d7ffff, 0xb6350003, + 0x81550001, 0x8357ffff, 0x029fa02a, 0x82970414, + 0xb6350003, 0x81550001, 0x83d7ffff, 0x029fa02a, + 0x81550001, 0xb00a0001, 0xb4200004, 0x814d0008, + 0x6149b80a, 0x954affff, 0x015f61ee, 0xb0160000, + 0xb4200007, 0x81550001, 0xb00a0001, 0xb4200004, + 0x814d0008, 0x6149b80a, 0x954affff, 0x015f61ef, + 0x81550001, 0xb00a0001, 0xb4200036, 0x82f50001, + 0x02ff23a1, 0xb0170001, 0xb420002c, 0x82970428, + 0xb6350003, 0x81550001, 0x00000000, 0x029fa02a, + 0x82970428, 0x81470000, 0x017f8034, 0xb00b0001, + 0xb4000004, 0x914a0001, 0x300ab815, 0xb480fffa, + 0xb5000001, 0x015f23a5, 0x81670000, 0xb0160002, + 0xb4200002, 0x81750001, 0x00000000, 0x017f233a, + 0x81550004, 0xadaa000c, 0x015f23a2, 0x81750004, + 0x916b0003, 0x017f23a3, 0x91ad0025, 0x01bf23a6, + 0xadab000c, 0x81e70000, 0x91ad0025, 0x01bf23a7, + 0x920a0001, 0x05abb810, 0xb00d0000, 0xb400000d, + 0xb62d0004, 0x81b50001, 0x65b0b80d, 0x19efb80d, + 0x92100001, 0x01ffb0be, 0xb5000006, 0x81a70000, + 0x82970428, 0xb6350001, 0x029fa02d, 0x01bf233a, + 0x01bf23a5, 0x82070000, 0x82270000, 0x82170428, + 0xb635003a, 0x01bf8030, 0xb00d0001, 0xb4200036, + 0x81d50001, 0x65b1b80e, 0x1a10b80d, 0xb00e0001, + 0xb4200031, 0x81b50002, 0xadad0003, 0xae510048, + 0x91cd000f, 0x91320868, 0x015f03a2, 0xad4a0004, + 0x92920700, 0x1189b80a, 0x0297b80c, 0x1194b80a, + 0x0317b80c, 0x01ff90be, 0x015f03a2, 0x017f03a3, + 0x064bb80a, 0x0107b80a, 0xb0120000, 0xb400001e, + 0xb632001d, 0x6928b80f, 0x95290001, 0xb0090000, + 0xb420000e, 0x81350004, 0x1129b80d, 0x029fa029, + 0x824d0004, 0x5a48b812, 0x5e48b812, 0x3009b80e, + 0xb4200002, 0x5e41b812, 0xb500000d, 0x5e42b812, + 0x81330040, 0x1a52b809, 0xb5000009, 0x0127b854, + 0x85290004, 0x0397b809, 0x0287b858, 0x86940004, + 0x013f803c, 0x0397b814, 0x029fa029, 0x025f803c, + 0x031fa032, 0x91080001, 0x92310001, 0x015f03a2, + 0x017f03a3, 0x013f033a, 0xb0090001, 0xb420001f, + 0x95300002, 0x95900001, 0x1929b80c, 0xb0090000, + 0xb400001a, 0x064bb80a, 0x0107b80a, 0xb6320017, + 0x6928b80f, 0x95290001, 0xb0090000, 0xb4200002, + 0x81350001, 0x013f23f8, 0x81a70700, 0x91ad0048, + 0x5982b808, 0x11adb80c, 0x0397b80d, 0x013f03f8, + 0xb0090001, 0xb4200005, 0x019f801c, 0x0196b80c, + 0x81b3ff80, 0x418cb80d, 0xb5000002, 0x019f801c, + 0x0196b80c, 0x039fa00c, 0x91080001, 0xb0160002, + 0xb420001a, 0xb0170001, 0xb4200008, 0xb00a0000, + 0xb4200002, 0x81270002, 0xb5000005, 0xb00a0002, + 0xb4400002, 0x81270003, 0xb5000001, 0x81270004, + 0x013f23a9, 0x81950001, 0xb00c0001, 0xb420000d, + 0x81a70000, 0x8397043c, 0xb6290006, 0x81150001, + 0x039fa028, 0xb0080001, 0xb4200001, 0x81a70001, + 0x00000000, 0x01bf23a8, 0xb5000002, 0x81a70000, + 0x01bf23a8, 0xb0170001, 0xb4200001, 0x81b50002, + 0x82970c20, 0xb6350003, 0x81550002, 0x00000000, + 0x029fa02a, 0xb0130001, 0xb4200001, 0x81150001, + 0x81c70000, 0xb6350014, 0x922e0c20, 0x015ff011, + 0xb00a0000, 0xb400000f, 0x922e0428, 0x015ff011, + 0xb00a0001, 0xb4200005, 0x922e044c, 0x0297b811, + 0x015f03a6, 0x029fa00a, 0xb5000006, 0x81550006, + 0xad4a0003, 0x922e044c, 0x0297b811, 0x914a0049, + 0x029fa00a, 0x91ce0004, 0xb0170001, 0xb420001e, + 0xb00d0000, 0xb400001c, 0x852d0001, 0x81470001, + 0x6549b80a, 0xad6a0003, 0x019f03a7, 0x058c03a6, + 0x81270000, 0xb00b0000, 0xb4000005, 0x300cb80b, + 0xb4800003, 0x058cb80b, 0x91290001, 0xb500fffb, + 0x81750004, 0x5961b80b, 0x839704ec, 0x0187b860, + 0x039fa02c, 0x039fa02a, 0x039fa029, 0x039fa02b, + 0xb0090000, 0xb4000004, 0xb6290003, 0x81550007, + 0x00000000, 0x00000000, 0x81c70000, 0xb635002e, + 0x922e0c20, 0x01fff011, 0xb00f0000, 0xb4000029, + 0x852f0001, 0x81470001, 0x6549b80a, 0xad6a0003, + 0x922e044c, 0x025fd811, 0x86520001, 0x0227b812, + 0x81270000, 0xb00b0000, 0xb4000005, 0x3012b80b, + 0xb4800003, 0x0652b80b, 0x91290001, 0xb500fffb, + 0x2e09b80b, 0x00000000, 0x3010b811, 0xb4600001, + 0x91290001, 0xae4e0004, 0x82150004, 0x9232049c, + 0x0297b811, 0x0187b860, 0x029fa02c, 0x029fa02a, + 0x029fa029, 0x029fa030, 0xb0090000, 0xb4000004, + 0xb6290003, 0x81550007, 0x00000000, 0x00000000, + 0x82270460, 0x1231b80e, 0x0217b811, 0x81550002, + 0x021fa00a, 0x91ce0004, 0xb0130001, 0xb420000c, + 0xb0080000, 0xb400000a, 0x81550004, 0x839704fc, + 0x0167b860, 0x039fa02b, 0x81670001, 0x039fa02b, + 0x8175000e, 0x81670002, 0x039fa02b, 0x039fa02a, + 0x81150001, 0xb0080001, 0xb420000a, 0x8135000b, + 0x5d2923aa, 0x95490180, 0x5d4723ab, 0x95490060, + 0x5d4523ac, 0x95490018, 0x5d4323ad, 0x95490007, + 0x015f23ae, 0x81350001, 0xb0090001, 0xb4200017, + 0x81350006, 0x013f23af, 0xb0170001, 0xb4200005, + 0x81550004, 0x00000000, 0x015f23b0, 0x81550003, + 0x015f23b1, 0x82970474, 0x83170488, 0xb6350004, + 0x81550007, 0x5e83a02a, 0x954a0007, 0x031fa02a, + 0xb0130001, 0xb4200005, 0x81750004, 0x00000000, + 0x017f23b2, 0x81750003, 0x017f23b3, 0xb0170001, + 0xb420000b, 0x81b50001, 0xb00d0001, 0xb4200008, + 0x81d50003, 0x59c8b80e, 0x91ce0300, 0x01df61da, + 0x81d50003, 0x59c8b80e, 0x91ce0300, 0x01df61db, + 0x81550001, 0xb00a0001, 0xb420004b, 0xb0170001, + 0xb4200001, 0x81550002, 0x82470000, 0x82270000, + 0xb6350004, 0x81750002, 0x6571b80b, 0x92310002, + 0x1a52b80b, 0xb0170001, 0xb4200017, 0xb00a0001, + 0xb4200011, 0x81150003, 0x91080001, 0x011f23a4, + 0x829709d0, 0x831709f0, 0x83970060, 0xb6280009, + 0x81750005, 0x00000000, 0x029fa02b, 0x81750004, + 0x00000000, 0x031fa02b, 0x81750003, 0x00000000, + 0x039fa02b, 0xb5000004, 0xb00a0002, 0xb4800002, + 0x81070000, 0x011f23a4, 0x82270000, 0x81270000, + 0xb6350025, 0x6a11b812, 0x92310002, 0x96100003, + 0xb0100001, 0xb4200018, 0xada90020, 0x81750003, + 0x920d0520, 0x0217b810, 0x920d05c0, 0x0297b810, + 0x920d0660, 0x0317b810, 0x5942b809, 0x920a050c, + 0x0397b810, 0x916b0001, 0x039fa02b, 0xb62b0009, + 0x81750005, 0x00000000, 0x021fa02b, 0x81750004, + 0x00000000, 0x029fa02b, 0x81750003, 0x00000000, + 0x031fa02b, 0xb5000007, 0xb0100002, 0xb4800005, + 0x59a2b809, 0x91ad050c, 0x0397b80d, 0x82070000, + 0x039fa010, 0x91290001, 0x81550001, 0xb00a0001, + 0xb4200007, 0x81550009, 0xb00a0000, 0xb4000004, + 0xb62a0003, 0x82150008, 0x00000000, 0x00000000, + 0xb00a0100, 0xb4a00007, 0x954aff00, 0xb6008003, + 0x82150010, 0x00000000, 0x00000000, 0x854a0100, + 0xb4e0fffa, 0x00ffb81b, 0x00000000, 0x00000000, + 0x81070000, 0x011f61dc, 0x011f61de, 0x011f61e0, + 0x011f03aa, 0x9108e0f4, 0x0138b808, 0x011f03ab, + 0x013f61ac, 0x9108e0f0, 0x0138b808, 0x011f03ac, + 0x013f61ad, 0x5901b808, 0x9108e0f8, 0x0139b808, + 0x011f03ad, 0x013f61ae, 0x5901b808, 0x9108e100, + 0x0139b808, 0x011f03ae, 0x013f61b0, 0x5901b808, + 0x9108e108, 0x0179b808, 0x013f03af, 0x017f61b1, + 0x02bf037b, 0x82970474, 0xb6350002, 0x015f8034, + 0x1929b80a, 0x011f03a1, 0xb0080001, 0xb4200002, + 0x015f03b0, 0x1929b80a, 0x019f0388, 0xb00c0001, + 0xb4200002, 0x015f03b2, 0x1929b80a, 0x013f61b3, + 0x015f03a8, 0xb00a0001, 0xb420003a, 0x81a70000, + 0x01bf237a, 0x83840056, 0x806f001f, 0x80af001f, + 0x80270300, 0x8067a800, 0x5c62b803, 0xb600080a, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01afb803, + 0x007f90bc, 0x0047b86f, 0xb0020001, 0xb4c0fffd, + 0x90210020, 0x90630020, 0x81a70001, 0x01bf237a, + 0x83840043, 0x838403c6, 0x81a70000, 0x01bf237a, + 0x82470400, 0x01bff012, 0x01bf23fa, 0x83840418, + 0x8384048f, 0x8384053e, 0x83840595, 0x806f001f, + 0x80af001f, 0x80270300, 0x8067ac00, 0x5c62b803, + 0xb600080a, 0x00cfb801, 0x007fb0bc, 0x5862b803, + 0x01cfb803, 0x007f90bc, 0x0047b86f, 0xb0020001, + 0xb4c0fffd, 0x90210020, 0x90630020, 0x81a70001, + 0x01bf237a, 0x82470404, 0x015ff012, 0x015f23fa, + 0x838403ff, 0x83840476, 0x83840525, 0x8384057c, + 0xb5000011, 0x81a70000, 0x01bf237a, 0xb635000e, + 0x8384001b, 0x01bf037a, 0xad4d0004, 0x00000000, + 0x914a0400, 0x01bff00a, 0x01bf23fa, 0x838403f0, + 0x83840467, 0x83840516, 0x8384056d, 0x01df037a, + 0x91ce0001, 0x01df237a, 0x019f0388, 0xb00c0001, + 0xb4200009, 0x02bf037b, 0x02bf237a, 0x838400e8, + 0x82470000, 0x025f23fa, 0x838403e1, 0x83840458, + 0x83840507, 0x8384055e, 0x00ffb81b, 0x00000000, + 0x80770000, 0x80f70000, 0x81770000, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x83f70000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x82d7ffff, 0x8357ffff, 0x83d7ffff, + 0x017f037a, 0x5a42b80b, 0x01bf03a8, 0xb00d0001, + 0xb4200004, 0x011f9118, 0x013f9119, 0x7929b808, + 0xb5000002, 0x91b20460, 0x013ff00d, 0x91b20340, + 0x0297b80d, 0x00000000, 0x029fa009, 0x01df0384, + 0xb00e0000, 0xb4200005, 0xb00b0001, 0xb4200003, + 0x009f90c6, 0x00bf0391, 0xb5000002, 0x009f90cf, + 0x00bf0389, 0x83a4013a, 0x81870000, 0x019f61b5, + 0x019f61b4, 0x5a02b80b, 0x9190044c, 0x01dfd80c, + 0x01df61b6, 0x91900488, 0x01dff00c, 0x59c1b80e, + 0x918ee118, 0x01d9b80c, 0x019f03af, 0x01df61af, + 0x858c000f, 0x5986b80c, 0x91d00474, 0x01bff00e, + 0x59c2b80d, 0x11cc61b2, 0x81870000, 0x019f61b8, + 0x91900414, 0x01dfd80c, 0x01df61b7, 0xadab0010, + 0x00000000, 0x908d049c, 0x83a40189, 0xadcb0020, + 0x5982b80b, 0x908e0520, 0x90ae05c0, 0x90ce0660, + 0x928c050c, 0x00ff9814, 0x83a40161, 0x83a401b0, + 0x017f037a, 0x59c2b80b, 0x918e0428, 0x01fff00c, + 0xb00f0001, 0xb4200081, 0x023f03a5, 0x3011b80b, + 0xb420000f, 0x01c7b860, 0x01dfb0fa, 0x01df41dc, + 0x01df61e8, 0x01df41de, 0x01df61ea, 0x01df41e0, + 0x01df61ec, 0x01df41dd, 0x01df61e9, 0x01df41df, + 0x01df61eb, 0x01df41e1, 0x01df61ed, 0xb5000024, + 0x01c7b860, 0x01dfb0f9, 0x01df41dc, 0x01df61e2, + 0x01df41de, 0x01df61e4, 0x01df41e0, 0x01df61e6, + 0x01df41dd, 0x01df61e3, 0x01df41df, 0x01df61e5, + 0x01df41e1, 0x01df61e7, 0x803f0000, 0x00000000, + 0x00000000, 0x01df90fa, 0x003fb80e, 0x00000000, + 0x00000000, 0x81d50000, 0x00000000, 0x00000000, + 0x01df41e8, 0x01df61dc, 0x01df41ea, 0x01df61de, + 0x01df41ec, 0x01df61e0, 0x01df41e9, 0x01df61dd, + 0x01df41eb, 0x01df61df, 0x01df41ed, 0x01df61e1, + 0x029f03a6, 0x029f236a, 0x029f03a7, 0x029f236c, + 0x027f03a2, 0x92b3e128, 0x0298b815, 0x019f03b0, + 0x029f2368, 0x5982b80c, 0x01df03af, 0x85ce000f, + 0x59c6b80e, 0x11cc61b2, 0x82a70001, 0x02bf61b8, + 0x82a70000, 0x02bf61b9, 0x029f41da, 0x029f61ba, + 0x029f41db, 0x029f61bb, 0x019f03b1, 0x5981b80c, + 0x918ce118, 0x0299b80c, 0xad8b0048, 0x029f61af, + 0x59a2b813, 0x118cb80d, 0x928c0868, 0x029fb0fb, + 0x928c0700, 0x029fb0fc, 0x019f41bc, 0x918c0003, + 0x019f61bc, 0x5a02b80b, 0x91900414, 0x029fd80c, + 0x029f236e, 0x808704ec, 0x83a40119, 0x808709d0, + 0x80a709f0, 0x80c70060, 0x00ff03a4, 0x83a400f4, + 0x83a40143, 0x021f037a, 0x019f03a5, 0x300cb810, + 0xb4000016, 0x803f0000, 0x00000000, 0x00000000, + 0x01df90f9, 0x003fb80e, 0x00000000, 0x00000000, + 0x81d50000, 0x00000000, 0x00000000, 0x01df41e2, + 0x01df61dc, 0x01df41e4, 0x01df61de, 0x01df41e6, + 0x01df61e0, 0x01df41e3, 0x01df61dd, 0x01df41e5, + 0x01df61df, 0x01df41e7, 0x01df61e1, 0x029f41b6, + 0xa6d40100, 0xaeb40004, 0x81870000, 0x92b50c00, + 0x0397b815, 0xb6360001, 0x039fa02c, 0x00ffb81c, + 0x009f90cf, 0x00bf0389, 0x019f037a, 0x5982b80c, + 0x918c0340, 0x0397b80c, 0x81870000, 0x039fa00c, + 0x83a4007b, 0x81870000, 0x019f61b5, 0x019f61b4, + 0x81870007, 0x019f61b6, 0x019f03b3, 0x5981b80c, + 0x918ce118, 0x01b9b80c, 0x019f03af, 0x01bf61af, + 0x858c000f, 0x5986b80c, 0x01bf03b2, 0x59a2b80d, + 0x118cb80d, 0x019f61b2, 0x81870000, 0x019f61b7, + 0x019f61b8, 0x808704fc, 0x83a400d1, 0x80870000, + 0x80a70000, 0x80c70000, 0x80e70000, 0x83a400ac, + 0x83a400fb, 0x81470000, 0x81e70c1c, 0x0397b80f, + 0xb600f901, 0x039fa02a, 0x00ffb81c, 0x00000000, + 0x82270000, 0x023f2011, 0x0227b860, 0x023fb0ff, + 0x02bf9006, 0x92350028, 0x8213001f, 0x9210e000, + 0x3011b810, 0xb4800001, 0x86312000, 0x021f4193, + 0x5a01b810, 0x86100028, 0x83a4fa94, 0x82270000, + 0x003fb811, 0x02bf9006, 0x5aa3b815, 0x82338000, + 0x1a31b815, 0x003fb811, 0x8067e950, 0x5c62b803, + 0x81f50000, 0x80270400, 0xb6000409, 0x814fffc0, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01cfb803, + 0x007f90bc, 0xb520ffff, 0x90210020, 0x90630020, + 0x82870000, 0x81f50010, 0x019f4193, 0x5d61b80c, + 0x5d43b80c, 0x114ab80b, 0x0187b80a, 0x960cff00, + 0x92100100, 0x858c0001, 0xb62c000c, 0x81f50010, + 0x5e28b80f, 0xb6000209, 0x5a48b814, 0x9652ff00, + 0x5e68b814, 0x5981b813, 0x918c1000, 0x01dfd80c, + 0x2252b811, 0x2292b80e, 0x962f00ff, 0x81870000, + 0x86100100, 0xb4e0fff0, 0xb00a0000, 0xb4000009, + 0x81670000, 0xb0140000, 0xb4000001, 0x81670001, + 0x017f2012, 0x258a4193, 0x918c0001, 0x81470000, + 0xb500ffe2, 0x81670000, 0xb0140000, 0xb4000001, + 0x81670002, 0x116b0012, 0x803f0000, 0x00000000, + 0x00000000, 0x003fb811, 0x00000000, 0x00000000, + 0x81f50000, 0x017f2012, 0x00ffb81a, 0x00000000, + 0x61f4b804, 0x91ef0001, 0x8233003f, 0x9a31ffff, + 0x5a02b804, 0x1610b811, 0x92510001, 0x1a10b812, + 0x029f03fb, 0xb0140001, 0xb4200012, 0x5a21b805, + 0x92b1e910, 0x0299b815, 0x5a22b805, 0x5a90b814, + 0x6290b814, 0x92b1e890, 0x11efb814, 0x029bb815, + 0x8233ff80, 0x3011b814, 0xb4000006, 0x4294b811, + 0x00000000, 0x0288b814, 0x4210b814, 0x00000000, + 0x0208b810, 0x029f9003, 0x82f3007f, 0x9af7ffff, + 0x3017b814, 0xb4000003, 0x4210b814, 0x00000000, + 0x0208b810, 0x82270000, 0x02c7b810, 0xb0160000, + 0xb400000a, 0x1676b812, 0x3013b812, 0xb4000003, + 0x5ac1b816, 0x92310001, 0xb500fffa, 0x81d3ff80, + 0x3010b80e, 0xb4200001, 0x1ad6b80e, 0x05efb811, + 0x027f037a, 0x5a62b813, 0x92730340, 0x0397b813, + 0x023fd813, 0x02dfb0fd, 0x5a30b811, 0x6230b811, + 0x0631b80f, 0x3010b812, 0xb4200001, 0x92310001, + 0x82470000, 0xb0110000, 0xb4800004, 0x82470003, + 0xb0110003, 0xb4400001, 0x0247b811, 0x039fa012, + 0x124f61bc, 0x00ffb81d, 0x00000000, 0x00000000, + 0x83970a10, 0x82070000, 0xb6003201, 0x039fa030, + 0xb0070000, 0xb4000019, 0x029f41b4, 0x0297b804, + 0x0317b805, 0x0397b806, 0xb6270014, 0x12948034, + 0x01df8038, 0xb00e0000, 0xb4a0000e, 0x02bf803c, + 0x5a02b814, 0x91b00a10, 0x0217b80d, 0xb62e0008, + 0x96150003, 0x91f00001, 0xadef0080, 0xb0150004, + 0xb4600001, 0x85ef0280, 0x021fa02f, 0x92940001, + 0xb5000001, 0x021f803c, 0x00000000, 0x00ffb81d, + 0x0397b804, 0x021f036a, 0x027f803c, 0x029f803c, + 0x02bf803c, 0x02df803c, 0x5a22b810, 0x92311000, + 0x0397b811, 0xb0100000, 0xb4200001, 0x039fa036, + 0xb0150000, 0xb4000021, 0x0227b860, 0x023fb0ff, + 0xb520ffff, 0x803f0000, 0x82138000, 0x1a10b813, + 0x003fb810, 0x00000000, 0x00000000, 0x82150000, + 0x00000000, 0xb635000d, 0x82550007, 0x5a42b812, + 0x9212e4b8, 0x025bb810, 0x8227000c, 0xb6000307, + 0x68d1b812, 0x94c6000f, 0x84c60002, 0x12d6b806, + 0xb6340001, 0x039fa036, 0x86310004, 0x803f0000, + 0x82138000, 0x023f90ff, 0x1a31b810, 0x003fb811, + 0x00000000, 0x00000000, 0x82150000, 0x00ffb81d, + 0x00ff41b5, 0x011f41b4, 0x019f41af, 0x01bf41ae, + 0x01df41ba, 0x01ff41bb, 0x82070000, 0x023f0380, + 0x82470000, 0xae310032, 0x029f41b3, 0x5862b807, + 0x90431000, 0x81970ad8, 0x0217b802, 0x90430c00, + 0x0297b802, 0x0317b802, 0x912802a4, 0x007ff009, + 0x58478030, 0x792341b6, 0x0529b807, 0x019fa029, + 0xb0080014, 0xb4800011, 0xa5420c00, 0x031fa02a, + 0x84690001, 0xb4a00011, 0xb623000b, 0x58678030, + 0xa4030c00, 0x031fa020, 0x044ab800, 0x0056b802, + 0x5c41b802, 0xf84200ff, 0x90620100, 0x005ff003, + 0x7d40b80a, 0x114ab802, 0xb5000004, 0xa5420c00, + 0x58478010, 0xa5620c00, 0x031fa02a, 0xb0080016, + 0xb4400043, 0xb0080013, 0xb440002c, 0xb0080006, + 0xb4400024, 0xb0080005, 0xb4400014, 0xb0080002, + 0xb4400006, 0x80440030, 0x015f619c, 0x05cab80c, + 0x05eab80d, 0x066eb810, 0xb500003c, 0x8044002a, + 0x300a419c, 0xb4800001, 0x82470001, 0x015f619c, + 0xb0120001, 0xb4200001, 0xb500001a, 0x05cab80c, + 0x05eab80d, 0x066eb810, 0xb5000030, 0x001f41b6, + 0xb0000007, 0xb4000001, 0x8044001b, 0x300a419c, + 0xb4800001, 0x82470001, 0xb0120001, 0xb4200001, + 0xb500000c, 0x05cab80c, 0x05eab80d, 0x066eb810, + 0xb5000022, 0x80440010, 0x840b0100, 0x300ab800, + 0xb4200001, 0x86100040, 0xb5000002, 0x86100080, + 0xfe100000, 0x046e41ad, 0x042ab80c, 0x7dc1b803, + 0x044f41ac, 0x042ab80d, 0x7de1b802, 0x046eb810, + 0x7e6fb803, 0xb5000011, 0x840b0100, 0x3000b80a, + 0xb4200002, 0x82070180, 0x00ffb802, 0x300ab80b, + 0xb4a00002, 0x86100040, 0xfe100000, 0x00ffb802, + 0x046e41ad, 0x042ab80c, 0x7dc1b803, 0x044f41ac, + 0x042ab80d, 0x7de1b802, 0x7e6eb80f, 0x380a41b0, + 0xb4600003, 0x242a41b0, 0x5c22b801, 0x1273b801, + 0xb0140000, 0xb4200002, 0x80071fe0, 0xb5000016, + 0x1011b808, 0x5801b800, 0x9020e26c, 0x0079b801, + 0x5842b808, 0x90420a10, 0x7c03b813, 0x003f9802, + 0x1000b801, 0x003f41b2, 0x5830b801, 0x6030b801, + 0x0400b801, 0x003f41b1, 0x5830b801, 0x6030b801, + 0x0400b801, 0xfc000000, 0xf8001fe0, 0x94001fe0, + 0x100041b1, 0x9400ffff, 0x8067003f, 0xb6290008, + 0x005f8014, 0x0442b800, 0x9442ffff, 0x5850b802, + 0x6050b802, 0xfc420000, 0x5c45b802, 0x7a82a023, + 0x10e7b809, 0x91080001, 0x300741b6, 0xb420ff6a, + 0x019f61af, 0x01bf61ae, 0x01df61ba, 0x01ff61bb, + 0x00ff41b5, 0x011f41b4, 0x019f41b8, 0x01bf41b7, + 0x01df41dd, 0x01ff41df, 0x021f41e1, 0x027f90fd, + 0x029f41bc, 0x02ff41dc, 0x031f41de, 0x033f41e0, + 0x5822b807, 0x91210c00, 0x0117b809, 0x81970ad8, + 0x91211000, 0x0217b809, 0x91210c00, 0x0317b809, + 0x80170ba0, 0x013f802c, 0xb629005f, 0x003f8038, + 0xb001000e, 0xb440001e, 0xb001000c, 0xb4400054, + 0xb001000a, 0xb4400043, 0xb0010007, 0xb440003c, + 0xb0010005, 0xb440002b, 0xb0010000, 0xb440001a, + 0xb00d0001, 0xb4200010, 0x005f418f, 0xac42bb75, + 0x8073005a, 0x9442ffff, 0x005f618f, 0x95628000, + 0x5848b802, 0xb00b8000, 0xb4200002, 0x8173ff00, + 0x1842b80b, 0x9863827a, 0x4043b802, 0x00000000, + 0x0048b802, 0xb500003f, 0x80470000, 0xb500003d, + 0x8401000f, 0x5c22b800, 0x902102d8, 0x001ff001, + 0x004db800, 0xb5000037, 0x86f70001, 0xb4600005, + 0x80750005, 0x5862b803, 0x9043e44c, 0x01d9b802, + 0x82e70002, 0x5c4cb80e, 0x9462000f, 0x5862b803, + 0x90630200, 0x005f9803, 0x59c4b80e, 0x95ceffff, + 0xb5000028, 0x87180001, 0xb4600005, 0x80750007, + 0x5862b803, 0x9043e4b8, 0x01f9b802, 0x83070002, + 0x5c4cb80f, 0x9462000f, 0x5862b803, 0x9063020c, + 0x005f9803, 0x59e4b80f, 0x95efffff, 0xb5000019, + 0x80750003, 0x5862b803, 0x90630220, 0x005f9803, + 0xb5000014, 0x87390001, 0xb4600005, 0x80750007, + 0x5862b803, 0x9043e6ac, 0x0219b802, 0x83270001, + 0x5c4cb810, 0x9462000f, 0x5862b803, 0x9063023c, + 0x005f9803, 0x5a04b810, 0x9610ffff, 0xb5000005, + 0x80750004, 0x5862b803, 0x90630268, 0x005f9803, + 0x00000000, 0x001fa022, 0x80170ba0, 0xb00c0001, + 0xb4200035, 0x023f90fb, 0x007f9811, 0x025f90fc, + 0x06d4b803, 0x007f9812, 0x4083b813, 0x00000000, + 0x0088b804, 0xb629002b, 0x24368030, 0x9421ffff, + 0x5830b801, 0x6030b801, 0x40448020, 0xb0010020, + 0xb4800003, 0x80470000, 0x80670000, 0xb500000e, + 0xb0010000, 0xb4a00004, 0x82b30080, 0x6aa1b815, + 0x4042b815, 0xb5000008, 0x6c41b802, 0x82a70017, + 0x12b5b801, 0x6875b803, 0x1842b803, 0x00000000, + 0x00000000, 0x00000000, 0x0108a022, 0x007f41b9, + 0x90630001, 0x007f61b9, 0xb003000c, 0xb420000c, + 0x92310004, 0x023fb0fb, 0x007f9811, 0x92520004, + 0x06d4b803, 0x025fb0fc, 0x007f9812, 0x80470000, + 0x4083b813, 0x00000000, 0x0088b804, 0x005f61b9, + 0x00000000, 0xb500001a, 0xb6290019, 0x24348030, + 0x9421ffff, 0x5830b801, 0x6030b801, 0x40538020, + 0xb0010020, 0xb4800003, 0x80470000, 0x80670000, + 0xb500000e, 0xb0010000, 0xb4a00004, 0x82b30080, + 0x6aa1b815, 0x4042b815, 0xb5000008, 0x6c41b802, + 0x82a70017, 0x12b5b801, 0x6875b803, 0x1842b803, + 0x00000000, 0x00000000, 0x00000000, 0x0108a022, + 0x10e7b809, 0x91080001, 0x300741b6, 0xb420ff48, + 0x00ff61b5, 0x011f61b4, 0x01df61dd, 0x01ff61df, + 0x021f61e1, 0x02ff61dc, 0x031f61de, 0x033f61e0, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x808f0000, 0x003f9113, 0x005f9114, + 0x7141b802, 0x80cf0700, 0x8027b064, 0x5c22b801, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x80cf0704, 0x8027b06c, 0x5c22b801, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x81e7043c, 0x82071c00, 0x82271c10, + 0x019f03a9, 0x806f001f, 0x80af001f, 0x80270400, + 0x8067a800, 0x5c62b803, 0xb6000808, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01cfb803, 0x007f90bc, + 0xb520ffff, 0x90210020, 0x90630020, 0x81971000, + 0x82170c00, 0xb6000004, 0x003f800c, 0x005f8010, + 0x021fa021, 0x019fa022, 0x00bfd810, 0x003fd811, + 0x70c1b80a, 0x001f980f, 0x91ef0004, 0x92100002, + 0x92310002, 0x5822b805, 0x90411000, 0x0197b802, + 0x90410c00, 0x0217b802, 0x0466b805, 0xb0000000, + 0xb4000005, 0xb6230004, 0x003f8010, 0x005f800c, + 0x1201a022, 0x0581a022, 0x858c0001, 0xb4e0ffea, + 0x80270400, 0x8067ac00, 0x5c62b803, 0xb6000808, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01afb803, + 0x007f90bc, 0xb520ffff, 0x90210020, 0x90630020, + 0x00ffb81c, 0x00000000, 0x00000000, 0x00000000, + 0x808f0000, 0x806f001f, 0x80af001f, 0x003f037a, + 0xb0010000, 0xb4400030, 0x81a7b7fc, 0x5da2b80d, + 0x80670500, 0xb6000208, 0x00cfb803, 0x01bfb0bc, + 0x59a2b80d, 0x01cfb80d, 0x01bf90bc, 0xb520ffff, + 0x90630020, 0x91ad0020, 0x81c7b8fc, 0x5dc2b80e, + 0x80670540, 0xb6000208, 0x00cfb803, 0x01dfb0bc, + 0x59c2b80e, 0x01cfb80e, 0x01df90bc, 0xb520ffff, + 0x90630020, 0x91ce0020, 0x81a7b3fc, 0x5da2b80d, + 0x80670600, 0xb6000408, 0x00cfb803, 0x01bfb0bc, + 0x59a2b80d, 0x01cfb80d, 0x01bf90bc, 0xb520ffff, + 0x90630020, 0x91ad0020, 0x81c7b5fc, 0x5dc2b80e, + 0x80670680, 0xb6000408, 0x00cfb803, 0x01dfb0bc, + 0x59c2b80e, 0x01cfb80e, 0x01df90bc, 0xb520ffff, + 0x90630020, 0x91ce0020, 0x005f03fa, 0xb0020000, + 0xb4000024, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x8257ffff, 0x82d7ffff, 0x8357ffff, + 0x83d7ffff, 0x83971300, 0x83171200, 0x82971100, + 0x82171000, 0x81170c00, 0x81970ff8, 0x80171400, + 0x80971500, 0x005f802c, 0x001f8028, 0xb6004010, + 0x41028000, 0x51008004, 0x007f876c, 0x0208a028, + 0x41008000, 0x49028004, 0x003f8068, 0x0388a028, + 0x41038000, 0x51018004, 0x005f802c, 0x0288a028, + 0x41018020, 0x49038024, 0x001f8028, 0x0308a028, + 0x00ffb81c, 0x83d7ffff, 0x8357ffff, 0x82d7ffff, + 0x8257ffff, 0x8157ffff, 0x81d7ffff, 0x8057ffff, + 0x80d7ffff, 0x82971200, 0x82171000, 0x81170c00, + 0x81970ffc, 0x83171800, 0x83971a00, 0x83370000, + 0x83b70000, 0x81370008, 0x81b7fff8, 0x4119880c, + 0xb6008006, 0x511d8808, 0x41498838, 0x0208a028, + 0x494d883c, 0x4119880c, 0x0288a02a, 0x00ffb81c, + 0x82670000, 0x82a70000, 0x003f037a, 0xb0010000, + 0xb4400018, 0x81a7bdfc, 0x5da2b80d, 0x80670580, + 0xb6000208, 0x00cfb803, 0x01bfb0bc, 0x59a2b80d, + 0x01cfb80d, 0x01bf90bc, 0xb520ffff, 0x90630020, + 0x91ad0020, 0x81a7eb70, 0x5da2b80d, 0x806705c0, + 0xb6000208, 0x00cfb803, 0x01bfb0bc, 0x59a2b80d, + 0x01cfb80d, 0x01bf90bc, 0xb520ffff, 0x90630020, + 0x91ad0020, 0x02bf03fa, 0x808f0000, 0xb0150000, + 0xb4000006, 0x81470040, 0x81670003, 0x81870002, + 0x81a71000, 0x81c71300, 0xb5000005, 0x81470080, + 0x81670004, 0x81870001, 0x81a71000, 0x81c71200, + 0x0017b80d, 0x0097b80e, 0x108db80a, 0x0117b804, + 0x108eb80a, 0x0197b804, 0x5841b80a, 0x108db802, + 0x0217b804, 0x108eb802, 0x0297b804, 0x106ab802, + 0x108db803, 0x0317b804, 0x108eb803, 0x0397b804, + 0x5ea2b80a, 0xb6350020, 0x001f8000, 0x003f8008, + 0x005f8004, 0x007f800c, 0x10c08010, 0x10a18018, + 0x10828014, 0x10e3801c, 0x1246b805, 0x0686b805, + 0x10c4b807, 0x0484b807, 0x80e70000, 0x80a70000, + 0x0008a032, 0x0108a034, 0x0088a026, 0x0188a024, + 0x04c08010, 0x04a18018, 0x04828014, 0x04e3801c, + 0x0646b807, 0x1286b807, 0x10c4b805, 0x0484b805, + 0x80e70000, 0x80a70000, 0x0208a032, 0x0308a034, + 0x0288a026, 0x0388a024, 0x5de1b80a, 0x82070004, + 0xb62b002a, 0x0017b80d, 0x0097b80e, 0x102db80f, + 0x0117b801, 0x104eb80f, 0x0197b802, 0x82171600, + 0x82971700, 0x0037b80f, 0x00b7b80f, 0x0137b80f, + 0x01b7b80f, 0xb630001b, 0x003f8030, 0x005f8034, + 0x5ee2b80f, 0x8013007f, 0x9800ffff, 0xb6370011, + 0x41008000, 0x51018008, 0x4902800c, 0x40c08000, + 0x0008a028, 0x48c18008, 0x50c2800c, 0x42808004, + 0x00c8b806, 0x52828008, 0x5281800c, 0x41008004, + 0x0088a034, 0x49028008, 0x4901800c, 0x011fa026, + 0x0188a028, 0x001f8001, 0x001f8005, 0x001f8009, + 0x001f800d, 0x5de1b80f, 0x5a01b810, 0x0017b80d, + 0x0097b80e, 0x902d0004, 0x0117b801, 0x904e0004, + 0x0197b802, 0x82171600, 0x82971700, 0x5ea1b80a, + 0x8013007f, 0x9800ffff, 0xb6350013, 0x003f8030, + 0x005f8034, 0x42408000, 0x52418008, 0x4a42800c, + 0x41008000, 0x0008a052, 0x49018008, 0x5102800c, + 0x42808004, 0x0108b808, 0x52828008, 0x5281800c, + 0x40c08004, 0x0088a054, 0x48c28008, 0x48c1800c, + 0x011fa048, 0x0188a046, 0x81a71100, 0x81c71200, + 0x858c0001, 0xb4e0ff7e, 0x00ffb81c, 0x00000000, + 0x005f03fa, 0x00000000, 0xb0020000, 0xb4000034, + 0x81b70080, 0x81d7ffff, 0x81f70001, 0x82370080, + 0x8257ffff, 0x82770001, 0x82b70080, 0x82d7ffff, + 0x82f70001, 0x83370080, 0x8357ffff, 0x83770001, + 0x81971000, 0x82171100, 0x82971200, 0x83171300, + 0x815703fc, 0x81370200, 0x81170c00, 0x83d703fc, + 0x83b70200, 0x83970f00, 0x8057ffff, 0x80d7ffff, + 0x80171400, 0x80971500, 0x001f800d, 0x003f8019, + 0xb6004012, 0x41008000, 0x51018004, 0x007f8011, + 0x0128a008, 0x41018000, 0x49008004, 0x009f8015, + 0x03a8a008, 0x41038000, 0x51048004, 0x001f800d, + 0x03a8a008, 0x41048020, 0x49038024, 0x003f8019, + 0x0128a008, 0x005f8028, 0x005f803c, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x00ffb81c, + 0x82370040, 0x8257ffff, 0x82770001, 0x82b70040, + 0x82d7ffff, 0x82f70001, 0x82171000, 0x82971200, + 0x8157ffff, 0x81170c00, 0x81d7ffff, 0x81970e00, + 0x8057ffff, 0x80d7ffff, 0x80171800, 0x80971a00, + 0xb600800a, 0x001f8011, 0x003f8015, 0x41008000, + 0x51018004, 0x00000000, 0x0108a028, 0x41018020, + 0x49008024, 0x00000000, 0x0188a028, 0x82770000, + 0x82f70000, 0x00ffb81c, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x808f0000, + 0x015f0384, 0x017f037a, 0xac4a0006, 0x8027b004, + 0x1042b80b, 0x5841b802, 0x1021b802, 0x0159b801, + 0x013f0325, 0x01bf0320, 0x5822b80b, 0x90210340, + 0x00ff9801, 0x8027b2e8, 0x5842b807, 0x1021b802, + 0x025bb801, 0x80070000, 0xac4d0006, 0x8027b004, + 0x1042b800, 0x5841b802, 0x1021b802, 0x0199b801, + 0x00000000, 0xac4c0006, 0x8027b078, 0x1042b80a, + 0x5842b802, 0x1021b802, 0x011bb801, 0x00000000, + 0x40d2b808, 0x00000000, 0xb0060000, 0xb4000080, + 0x005f033b, 0x80278400, 0xac600080, 0x5c22b801, + 0x10a1b803, 0xb0020000, 0xb4200002, 0x80279000, + 0xb5000001, 0x80279c00, 0x5c22b801, 0x11e1b803, + 0x80470300, 0x5822b800, 0x1042b801, 0x003f9802, + 0x806f001f, 0x80af001f, 0xb0010000, 0xb4200024, + 0x80170c00, 0x80971000, 0x003f8020, 0xb6000003, + 0x4201b806, 0x003f8020, 0x0088a030, 0x80270400, + 0xb6000208, 0x00cfb801, 0x00bfb0bc, 0x58a2b805, + 0x01afb805, 0x00bf90bc, 0xb520ffff, 0x90210020, + 0x90a50020, 0xb6000408, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x90210020, 0x91ef0020, 0xb6000208, 0x00cfb801, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x90210020, 0x90a50020, 0xb5000043, + 0x80270400, 0x0087b805, 0x01c7b80f, 0xb6000208, + 0x00cfb801, 0x009fb0bc, 0x5882b804, 0x01cfb804, + 0x009f90bc, 0xb520ffff, 0x90210020, 0x90840020, + 0xb6000408, 0x00cfb801, 0x01dfb0bc, 0x59c2b80e, + 0x01cfb80e, 0x01df90bc, 0xb520ffff, 0x90210020, + 0x91ce0020, 0xb6000208, 0x00cfb801, 0x009fb0bc, + 0x5882b804, 0x01cfb804, 0x009f90bc, 0xb520ffff, + 0x90210020, 0x90840020, 0x80170c00, 0x80971000, + 0x8053007f, 0x9842ffff, 0xb6000004, 0x42028004, + 0x4a068020, 0x00000000, 0x0088a030, 0x80270400, + 0xb6000208, 0x00cfb801, 0x00bfb0bc, 0x58a2b805, + 0x01afb805, 0x00bf90bc, 0xb520ffff, 0x90210020, + 0x90a50020, 0xb6000408, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x90210020, 0x91ef0020, 0xb6000208, 0x00cfb801, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x90210020, 0x90a50020, 0x5822b800, + 0x90210300, 0x0117b801, 0x80470001, 0x011fa002, + 0x90000001, 0x3000b809, 0xb480ff6b, 0x00ffb81c, + 0x8057ffff, 0x013f0325, 0x015f033b, 0x80171000, + 0x80070000, 0xb6002001, 0x001fa020, 0xb00a0001, + 0xb4c00002, 0x81679000, 0xb5000001, 0x81679c00, + 0x5d62b80b, 0x81878400, 0x5d82b80c, 0x80070000, + 0x5822b800, 0x90410300, 0x003f9802, 0x00000000, + 0xb0010000, 0xb4200019, 0xac400080, 0x00000000, + 0x10ccb802, 0x10abb802, 0x806f001f, 0x80af001f, + 0x80cf0400, 0xb6000408, 0xb520ffff, 0x00dfb0bc, + 0x58c2b806, 0x01afb806, 0x00df90bc, 0xb520ffff, + 0x80cf0400, 0x90c60020, 0x80cf0400, 0xb6000407, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x80cf0400, 0x90a50020, 0x90000001, + 0x3000b809, 0xb480ffde, 0x00ffb81b, 0x8057ffff, + 0x013f0325, 0x80171000, 0x80070000, 0xb6002001, + 0x001fa020, 0x81878400, 0x5d82b80c, 0x80070000, + 0x5822b800, 0x90410300, 0x003f9802, 0x00000000, + 0xb0010000, 0xb420000f, 0xac400080, 0x00000000, + 0x10ccb802, 0x806f001f, 0x80af001f, 0x80cf0400, + 0xb6000408, 0xb520ffff, 0x00dfb0bc, 0x58c2b806, + 0x01afb806, 0x00df90bc, 0xb520ffff, 0x80cf0400, + 0x90c60020, 0x90000001, 0x3000b809, 0xb480ffe8, + 0x00ffb81b, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x8139b000, 0x00000000, 0xb0090000, 0xb4000012, + 0x806f001f, 0x80af001f, 0x80cf0400, 0x013fb0bc, + 0x5922b809, 0x01cfb809, 0x013f90bc, 0xb520ffff, + 0x806f0003, 0x80af0003, 0x80cf0420, 0x91290020, + 0x013fb0bc, 0x5922b809, 0x01cfb809, 0x013f90bc, + 0xb520ffff, 0xb5000233, 0x80270000, 0x80171000, + 0xb6002401, 0x001fa021, 0x007f0384, 0x009f0320, + 0x00bf0385, 0x00df0386, 0x80e7b36c, 0x5821b803, + 0x1021b807, 0x0159b801, 0x5821b804, 0x1021b807, + 0x0179b801, 0x80e7b37c, 0x5821b803, 0x1021b807, + 0x0199b801, 0x5821b804, 0x1021b807, 0x01b9b801, + 0x80e7b38c, 0x5821b803, 0x1021b807, 0x01d9b801, + 0x5821b804, 0x1021b807, 0x01f9b801, 0x005f0385, + 0x8027b39c, 0x5842b802, 0x1021b802, 0x021bb801, + 0x005f0386, 0x8027b3ac, 0x5842b802, 0x1021b802, + 0x023bb801, 0x027f0383, 0x003f0328, 0x005f4195, + 0xb0130007, 0xb42000df, 0xb0010000, 0xb42000dd, + 0xb0020000, 0xb40000db, 0xb0030002, 0xb48000d9, + 0x029bb802, 0x82a7b108, 0xb00b0001, 0xb4200001, + 0xb5000005, 0xb00b0002, 0xb4200002, 0x92b500a0, + 0xb5000001, 0x92b50140, 0xb0030004, 0xb4600002, + 0x82870000, 0xb5000006, 0xb0030006, 0xb4600004, + 0xb0140001, 0xb4a00002, 0x82870001, 0xb5000000, + 0xac54000a, 0x806f0009, 0x80af0009, 0x5c22b815, + 0x80cf0440, 0x1021b802, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0xb0030003, + 0xb400000f, 0xb0030004, 0xb400001d, 0xb0030005, + 0xb400002b, 0xb0030006, 0xb4000042, 0xb0030007, + 0xb4000059, 0x80171000, 0x005f9440, 0x001fa002, + 0x80171038, 0x005f9440, 0x001fa002, 0xb5000073, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171004, + 0x005f9443, 0x001fa002, 0x8017101c, 0x005f9446, + 0x001fa002, 0x80171034, 0x005f9449, 0x001fa002, + 0x80171038, 0x005f9440, 0x001fa002, 0xb5000063, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171008, + 0x005f9441, 0x001fa002, 0x80171020, 0x005f9444, + 0x001fa002, 0x80171034, 0x005f9440, 0x001fa002, + 0x80171038, 0x005f9447, 0x001fa002, 0xb5000053, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171004, + 0x005f9443, 0x001fa002, 0x8017100c, 0x005f9441, + 0x001fa002, 0x8017101c, 0x005f9446, 0x001fa002, + 0x80171024, 0x005f9444, 0x001fa002, 0x80171034, + 0x005f9449, 0x001fa002, 0x80171038, 0x005f9440, + 0x001fa002, 0x8017103c, 0x005f9447, 0x001fa002, + 0xb500003a, 0x80171000, 0x005f9440, 0x001fa002, + 0x80171008, 0x005f9441, 0x001fa002, 0x8017100c, + 0x005f9442, 0x001fa002, 0x80171020, 0x005f9444, + 0x001fa002, 0x80171024, 0x005f9445, 0x001fa002, + 0x80171034, 0x005f9440, 0x001fa002, 0x80171038, + 0x005f9447, 0x001fa002, 0x8017103c, 0x005f9448, + 0x001fa002, 0xb5000021, 0x80171000, 0x005f9440, + 0x001fa002, 0x80171004, 0x005f9443, 0x001fa002, + 0x8017100c, 0x005f9441, 0x001fa002, 0x80171010, + 0x005f9442, 0x001fa002, 0x8017101c, 0x005f9446, + 0x001fa002, 0x80171024, 0x005f9444, 0x001fa002, + 0x80171028, 0x005f9445, 0x001fa002, 0x80171034, + 0x005f9449, 0x001fa002, 0x80171038, 0x005f9440, + 0x001fa002, 0x8017103c, 0x005f9447, 0x001fa002, + 0x80171040, 0x005f9448, 0x001fa002, 0x80270001, + 0x803eff90, 0x80171000, 0x82b30020, 0x9ab50000, + 0x40158020, 0xb6000501, 0x48158020, 0x82b30020, + 0x9ab50000, 0x80470000, 0x3015b800, 0xb4600006, + 0x80171000, 0x83840226, 0xb6000603, 0x40028000, + 0x00000000, 0x0008a020, 0x80171018, 0x82b30020, + 0x9ab50000, 0x40158020, 0xb6000501, 0x48158020, + 0x82b30020, 0x9ab50000, 0x80470000, 0x3015b800, + 0xb4600006, 0x80171018, 0x83840215, 0xb6000603, + 0x40028000, 0x00000000, 0x0008a020, 0x80171030, + 0x82b30020, 0x9ab50000, 0x40158020, 0xb6000501, + 0x48158020, 0x82b30020, 0x9ab50000, 0x80470000, + 0x3015b800, 0xb4600006, 0x80171030, 0x83840204, + 0xb6000603, 0x40028000, 0x00000000, 0x0008a020, + 0xb500011e, 0x80270000, 0x803eff90, 0xb0030000, + 0xb4200067, 0x025f0322, 0xb00b0001, 0xb4200016, + 0xb0120001, 0xb4200005, 0x80171018, 0x8033007f, + 0x9821ffff, 0x001fa001, 0xb5000110, 0xb0120002, + 0xb4200005, 0x80171020, 0x8033007f, 0x9821ffff, + 0x001fa001, 0xb5000109, 0x80171018, 0x80330040, + 0x98210000, 0x001fa001, 0x80171020, 0x00000000, + 0x001fa001, 0xb5000101, 0xb00b0002, 0xb420002c, + 0xb0120000, 0xb4200008, 0x80171000, 0x8033007f, + 0x9821ffff, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000f5, 0xb0120001, 0xb4200008, + 0x80171000, 0x8033005a, 0x98218279, 0x001fa001, + 0x80171030, 0x00000000, 0x001fa001, 0xb50000eb, + 0xb0120002, 0xb4200008, 0x80171008, 0x8033005a, + 0x98218279, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000e1, 0x80171000, 0x80330040, + 0x98210000, 0x001fa001, 0x80171008, 0x00000000, + 0x001fa001, 0x8017100c, 0x00000000, 0x001fa001, + 0x80171038, 0x00000000, 0x001fa001, 0xb50000d3, + 0xb0120000, 0xb4200008, 0x80171000, 0x8033007f, + 0x9821ffff, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000c9, 0xb0120001, 0xb4200005, + 0x80171018, 0x8033007f, 0x9821ffff, 0x001fa001, + 0xb50000c2, 0xb0120002, 0xb4200005, 0x80171020, + 0x8033007f, 0x9821ffff, 0x001fa001, 0xb50000bb, + 0x80171018, 0x80330040, 0x98210000, 0x001fa001, + 0x80171020, 0x00000000, 0x001fa001, 0xb50000b3, + 0x80070000, 0x8033007f, 0x9821ffff, 0xb600050e, + 0x144eb80f, 0xb0028000, 0xb4c00008, 0xac400006, + 0x00000000, 0x1042b800, 0x5842b802, 0x90421000, + 0x0017b802, 0x00000000, 0x001fa001, 0x90000001, + 0x59c1b80e, 0x59e1b80f, 0xb0040000, 0xb4200023, + 0xb00a0002, 0xb4000007, 0x80171004, 0x8033005a, + 0x98218279, 0x001fa001, 0x80171034, 0x00000000, + 0x001fa001, 0xb00c0002, 0xb4000009, 0x8017100c, + 0x8033ffa5, 0x98217d87, 0x001fa001, 0x8017103c, + 0x8033005a, 0x98218279, 0x001fa001, 0xb500008b, + 0x8017100c, 0x8033ffa5, 0x98217d87, 0x001fa001, + 0x80171010, 0x00000000, 0x001fa001, 0x8017103c, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171040, + 0x00000000, 0x001fa001, 0xb500007c, 0xb0040001, + 0xb420002a, 0xb00a0001, 0xb4000007, 0x80171018, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171020, + 0x00000000, 0x001fa001, 0xb00a0003, 0xb420000a, + 0x8053005a, 0x98428279, 0x4030b802, 0x8017101c, + 0x5821b801, 0x00000000, 0x00000000, 0x00000000, + 0x0028b801, 0x001fa001, 0xb00c0001, 0xb4200007, + 0x8053005a, 0x98428279, 0x4031b802, 0x80171024, + 0x0028b801, 0x001fa001, 0xb500005c, 0xb00c0002, + 0xb420005a, 0x8053005a, 0x98428279, 0x4031b802, + 0x80171024, 0x0028b801, 0x001fa001, 0x80171028, + 0x00000000, 0x001fa001, 0xb5000050, 0xb00b0002, + 0xb4200012, 0xb00a0001, 0xb4200008, 0x80171004, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171034, + 0x00000000, 0x001fa001, 0xb5000008, 0xb00a0003, + 0xb4200006, 0x80171004, 0x00000000, 0x001fa010, + 0x80171034, 0x00000000, 0x001fa010, 0xb00c0001, + 0xb4200025, 0x027f0383, 0x003f0328, 0xb0130007, + 0xb420000b, 0xb00b0003, 0xb4200009, 0xb0010000, + 0xb4200007, 0x80171024, 0x00000000, 0x001fa011, + 0x80171054, 0x80270000, 0x001fa001, 0xb500002b, + 0xb00d0000, 0xb420000a, 0x8033005a, 0x98218279, + 0x4041b811, 0x8017100c, 0x0048b802, 0x001fa002, + 0x8017103c, 0x00000000, 0x001fa002, 0xb500001f, + 0xb00d0002, 0xb420001d, 0x80171054, 0x8033005a, + 0x98218279, 0x001fa001, 0x8017106c, 0x00000000, + 0x001fa001, 0xb5000015, 0xb00c0002, 0xb4200013, + 0xb00d0000, 0xb4200007, 0x8017100c, 0x00000000, + 0x001fa011, 0x80171040, 0x00000000, 0x001fa011, + 0xb500000a, 0xb00d0001, 0xb4200008, 0x80171054, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171058, + 0x00000000, 0x001fa001, 0xb5000000, 0x029f0388, + 0x02bf0321, 0xb0140000, 0xb4000006, 0xb0150000, + 0xb4000004, 0x8017108c, 0x8033007f, 0x9821ffff, + 0x001fa001, 0x8027b078, 0x5c22b801, 0x806f001f, + 0x80af001f, 0x80cf0400, 0x003fb0bc, 0x5822b801, + 0x01afb801, 0x003f90bc, 0xb520ffff, 0x90210020, + 0x806f0003, 0x80af0003, 0x80cf0420, 0x003fb0bc, + 0x5822b801, 0x01afb801, 0x003f90bc, 0xb520ffff, + 0x81270000, 0x8033007f, 0x9821ffff, 0x80171000, + 0xb600060a, 0x80470000, 0xb6000603, 0x015f8020, + 0x0156b80a, 0x1042b80a, 0x3002b801, 0xb4a00001, + 0x81270001, 0x00000000, 0x00000000, 0x015f0323, + 0x00000000, 0xb00a0000, 0xb4200002, 0x81670000, + 0xb5000001, 0x81670001, 0x017f23fb, 0x01ff41ee, + 0x59f0b80f, 0x61f0b80f, 0x021f41ef, 0x5a10b810, + 0x6210b810, 0xb00a0003, 0xb420003b, 0x017f039f, + 0x019f41c5, 0x5990b80c, 0x6190b80c, 0xb00b0000, + 0xb400000c, 0xb00c0000, 0xb4000005, 0xac4c0100, + 0x8033001d, 0x98215500, 0x12c1b802, 0xb500000f, + 0xac4f0100, 0x8033001d, 0x98215500, 0x12c1b802, + 0xb500000a, 0xb0090000, 0xb4000005, 0xac4f0100, + 0x8033ffe2, 0x9821ab00, 0x12c1b802, 0xb5000003, + 0xac4f0100, 0x00000000, 0x02c7b802, 0xb0030000, + 0xb420007e, 0x01bf03a0, 0x01df41c9, 0x59d0b80e, + 0x61d0b80e, 0xb00d0000, 0xb400000c, 0xb00e0000, + 0xb4000005, 0xac4e0100, 0x8033001d, 0x98215500, + 0x12e1b802, 0xb5000071, 0xac500100, 0x8033001d, + 0x98215500, 0x12e1b802, 0xb500006c, 0xb0090000, + 0xb4000005, 0xac500100, 0x8033ffe2, 0x9821ab00, + 0x12e1b802, 0xb5000065, 0xac500100, 0x00000000, + 0x02e7b802, 0xb5000061, 0xb00a0002, 0xb420002f, + 0x023f9002, 0x025f9001, 0xb00f0000, 0xb4a00007, + 0xac4f0100, 0x00000000, 0x4022b811, 0x00000000, + 0x0028b801, 0x02c7b801, 0xb500000c, 0xb0090000, + 0xb4000004, 0xac4f0100, 0x00000000, 0x02c7b802, + 0xb5000006, 0xac4f0100, 0x00000000, 0x4022b812, + 0x00000000, 0x0028b801, 0x02c7b801, 0xb0030000, + 0xb4200046, 0xb0100000, 0xb4a00007, 0xac500100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02e7b801, 0xb500003d, 0xb0090000, 0xb4000004, + 0xac500100, 0x00000000, 0x02e7b802, 0xb5000037, + 0xac500100, 0x00000000, 0x4022b812, 0x00000000, + 0x0028b801, 0x02e7b801, 0xb5000030, 0x023f9002, + 0x025f9001, 0xb00f0000, 0xb4a00007, 0xac4f0100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02c7b801, 0xb5000006, 0xac4f0100, 0x00000000, + 0x4022b812, 0x00000000, 0x0028b801, 0x02c7b801, + 0xb0090000, 0xb4000005, 0x0047b816, 0x8033ffe2, + 0x9821ab00, 0x1042b801, 0x02c7b802, 0xb0030000, + 0xb4200016, 0xb0100000, 0xb4a00007, 0xac500100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02e7b801, 0xb5000006, 0xac500100, 0x00000000, + 0x4022b812, 0x00000000, 0x0028b801, 0x02e7b801, + 0xb0090000, 0xb4000005, 0x0047b817, 0x8033ffe2, + 0x9821ab00, 0x1042b801, 0x02e7b802, 0x00000000, + 0x00000000, 0x02c8b816, 0x02dfb0cf, 0xb0030000, + 0xb4200002, 0x02e8b817, 0x02ffb0c6, 0x00ffb81b, + 0xb6001807, 0x5841b802, 0x3015b800, 0xb4800002, + 0x06b5b800, 0x98420001, 0x5aa1b815, 0x00000000, + 0x00ffb81c, 0x00000000, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000015, 0x815bb3f0, 0x81070000, 0x812707f8, + 0xb00a0000, 0xb4000006, 0x81070800, 0x81270ff8, + 0xb00a0001, 0xb4000002, 0x81071000, 0x812717f8, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000f, 0x3001b809, + 0xb4a0002d, 0xb500000c, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81070000, 0xb5000007, 0xb0040001, + 0xb4200002, 0x81070800, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81071000, 0xb0040000, 0xb4200001, + 0x8384026c, 0x80af001f, 0x808f0000, 0x806f0000, + 0x80670400, 0x5d22b808, 0xb600100a, 0x00cfb803, + 0x013fb0bc, 0x5922b809, 0x01afb809, 0x013f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x91290020, 0x801bb3f8, 0x80270001, 0xb0000001, + 0xb4000002, 0x802600a0, 0x803eb3f8, 0x914a0001, + 0xb00a0002, 0xb4a00001, 0x81470000, 0x815eb3f0, + 0x80270001, 0x003f2013, 0x00ffb81b, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009d, 0x9a940008, 0x8286009d, + 0x8285009c, 0x96b48000, 0xb0158000, 0xb40001b5, + 0x96b40100, 0xb0150100, 0xb400020c, 0x96b40400, + 0xb0150400, 0xb400020d, 0x96b40001, 0xb0150001, + 0xb400000c, 0x96b40008, 0xb0150008, 0xb40001ad, + 0x96b44000, 0xb0154000, 0xb400020c, 0x96b40002, + 0xb0150002, 0xb4000182, 0x00000000, 0x00000000, + 0xb500021e, 0x02bf9017, 0x92b50001, 0x02bfb017, + 0x82850082, 0x96f40001, 0xb0170000, 0xb4000171, + 0x5efdb814, 0x96f70001, 0xb0170001, 0xb420000b, + 0x83050069, 0x9718003f, 0x82e50064, 0x12f7b818, + 0x86f70109, 0x82feff74, 0x02e7b86f, 0x9af74000, + 0x01ffb817, 0x96f7bfff, 0x01ffb817, 0x83050081, + 0x82a5009a, 0x96b50001, 0xb0150001, 0xb4200014, + 0x82a70000, 0x02bfb017, 0x96b41840, 0xb0150800, + 0xb420000c, 0x96b40008, 0x5aa9b815, 0x96d46000, + 0x5ec3b816, 0x82f3000f, 0x9af7c00f, 0x1718b817, + 0x1ab5b818, 0x1ab5b816, 0x9ab50340, 0x82a60081, + 0xb500014c, 0x9b180180, 0x83060081, 0xb5000149, + 0x82a5009a, 0x96b50002, 0xb0150002, 0xb420001b, + 0x82a70000, 0x02bfb017, 0x96b41800, 0xb0151800, + 0xb4000013, 0x96b40040, 0xb0150040, 0xb4200004, + 0xa3180c00, 0x9b180340, 0x83060081, 0xb5000139, + 0x96b40008, 0x5aa9b815, 0x96d46000, 0x5ec3b816, + 0x82f3000f, 0x9af7c00f, 0x1718b817, 0x1ab5b818, + 0x1ab5b816, 0x9ab50340, 0x82a60081, 0xb500012d, + 0x9b180180, 0x83060081, 0xb500012a, 0x82a500c1, + 0x96b5000f, 0xb015000b, 0xb420000e, 0x96b40020, + 0xb0150020, 0xb400000b, 0x96b40200, 0xb0150200, + 0xb4000008, 0x82c50086, 0x82e50094, 0x3016b817, + 0xb4400004, 0x06f7b816, 0xb017ff00, 0xb4400001, + 0xb5000118, 0x96b46000, 0xb0156000, 0xb4000011, + 0x96b41820, 0xb0150820, 0xb4200004, 0x9b391000, + 0x82a5009a, 0x96b5feff, 0x82a6009a, 0x96b40040, + 0xb0150040, 0xb4200001, 0x9739efff, 0x96b91000, + 0xb0151000, 0xb4200003, 0x82a5009a, 0x9ab50100, + 0x82a6009a, 0x96b40040, 0xb0150040, 0xb4200019, + 0x96b41800, 0xb0151800, 0xb4200006, 0x96b98000, + 0xb0158000, 0xb4200003, 0x9b180180, 0x83060081, + 0xb50000f8, 0x96d80c00, 0x82b300ff, 0x9ab5f3ff, + 0x1718b815, 0xb0160c00, 0xb4000007, 0x82e50098, + 0x96f70400, 0xb0170400, 0xb4200002, 0x82c70c00, + 0xb5000001, 0xa2d60c00, 0x1b18b816, 0x9b180340, + 0xb50000c4, 0x96b40220, 0xb0150000, 0xb4e00021, + 0x82a5009d, 0x82f3ffff, 0x16b5b817, 0x82f33800, + 0x3015b817, 0xb420001b, 0x96f98000, 0xb0178000, + 0xb4000018, 0x82a70000, 0x02bfb017, 0x82c5009d, + 0x96d6ffff, 0x82b3c800, 0x9ab58001, 0x82e500c1, + 0x96f7000f, 0xb017000b, 0xb4000002, 0x82b38800, + 0x9ab58001, 0x1ab5b816, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b3c800, 0x9ab58001, + 0x82a6009d, 0x02ff9017, 0x00000000, 0xb0170040, + 0xb4800000, 0x5eb5b814, 0x96b500f0, 0x96f46000, + 0x5eedb817, 0x1ab5b817, 0xb0170003, 0xb4000004, + 0x96b500ef, 0x96f70001, 0x5ae4b817, 0x1ab5b817, + 0x96d41800, 0xb0161800, 0xb400000a, 0x96f900ff, + 0x96b500ff, 0x9739ff00, 0x1b39b815, 0x02a7b817, + 0x96b500f3, 0x96d40008, 0x5ec1b816, 0x1ab5b816, + 0xb500000c, 0x96f98000, 0xb0178000, 0xb4200007, + 0x5efeb814, 0x96f70001, 0xb0170001, 0xb4000003, + 0x9b180180, 0x83060081, 0xb50000a2, 0x96b500f3, + 0x9ab50008, 0x9739fff3, 0x96d40020, 0xb0160020, + 0xb4200019, 0x82c7001f, 0x82c600c9, 0x9b398000, + 0x82c70000, 0x02dfb017, 0x96d40010, 0x5ac8b816, + 0x82f300ff, 0x9af7cfff, 0x1718b817, 0x1b18b816, + 0x9b180340, 0x82c5009d, 0x96d6ffff, 0x82f33800, + 0x9af78001, 0x1af7b816, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82f3c800, 0x9af78001, + 0x82e6009d, 0xb500005f, 0x97397fff, 0x96b500ff, + 0x5aaab815, 0x82f300fc, 0x9af703ff, 0x1718b817, + 0x1b18b815, 0x9b180340, 0x82c5009a, 0x96d60010, + 0xb0160010, 0xb4200027, 0x82c70000, 0x02dfb017, + 0x82c50086, 0x92d60bb8, 0x82c60086, 0x82c50094, + 0x5eefb818, 0x96f70003, 0xb0170003, 0xb4200002, + 0x82e70bb8, 0xb5000001, 0x82e70bb8, 0x12d6b817, + 0x82e50081, 0x9af70020, 0x82e60081, 0x82c60094, + 0xa2f70020, 0x82e60081, 0x82f30001, 0x16f7b818, + 0x5ef0b817, 0xb0170001, 0xb4000004, 0x96f84000, + 0x5ee4b817, 0x9718f3ff, 0x1b18b817, 0x82f32800, + 0x9af78000, 0x82e6009d, 0x83060081, 0x83070001, + 0x8306009f, 0x8305009c, 0xb0180001, 0xb4e0fffb, + 0xb50000f6, 0x82c5009d, 0x82f33800, 0x9af78001, + 0x3016b817, 0xb420000f, 0x82b3c800, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b38800, 0x9ab58001, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b3c800, 0x9ab58001, + 0x82a6009d, 0x82c5009a, 0x96d60080, 0xb0160080, + 0xb4000013, 0x02df9017, 0x00000000, 0xb0160010, + 0xb480000f, 0x82c500c1, 0x96d6000f, 0xb016000b, + 0xb400000b, 0x82c50087, 0x96d60080, 0x5ac7b816, + 0x82c50098, 0x96d60800, 0x5ac3b816, 0x96f84000, + 0x3017b816, 0xb4200002, 0x033f400f, 0x9b394000, + 0x9739bfff, 0x82e50061, 0x96f70008, 0xb0170008, + 0xb4000005, 0x5eefb818, 0x96f70003, 0xb0170003, + 0xb4000001, 0x9718ffff, 0x96b41800, 0xb0151800, + 0xb4000008, 0x5eb9b814, 0x96b5000f, 0x82c50099, + 0x5ed0b816, 0x96f6000f, 0x5ab0b815, 0x82a60099, + 0xb5000002, 0x5ef9b814, 0x96f7000f, 0x5aecb817, + 0x82c5009a, 0x96d60fff, 0x1ad6b817, 0x82c6009a, + 0x96b46000, 0xb0156000, 0xb4200005, 0x5ae2b817, + 0x82d30ffc, 0x9ad63fff, 0x1718b816, 0x1b18b817, + 0x83060081, 0x83070001, 0x8306009f, 0x8305009c, + 0xb0180001, 0xb4e0fffb, 0x00000000, 0xb500009f, + 0x82850083, 0x96b400ff, 0xb015003c, 0xb4200019, + 0x96b92000, 0xb0152000, 0xb4000002, 0x9b392000, + 0xb5000014, 0x9739d3ff, 0x82870000, 0x82860087, + 0x82870008, 0x82860083, 0x829bff78, 0x82a7001f, + 0xb0140400, 0xb4000001, 0x82a70010, 0x82a600c9, + 0x829bff78, 0x00000000, 0x828600cb, 0x8285009d, + 0x82b3ffff, 0x9ab5fffd, 0x1694b815, 0x8286009d, + 0xb5000000, 0x83070002, 0x8306009f, 0x00000000, + 0xb500007e, 0x83078000, 0x8306009f, 0x00000000, + 0xb500007a, 0x82850094, 0x82a50086, 0x06b5b814, + 0x02b6b815, 0xb0151700, 0xb440004c, 0x8285006c, + 0x969400ff, 0xb0140024, 0xb4000019, 0xb0140012, + 0xb4000017, 0x8285009a, 0x5eedb814, 0x96f70003, + 0xb0170003, 0xb4000009, 0x82a50083, 0x5ea8b815, + 0x96b500ff, 0xb0150020, 0xb4400002, 0x82c70bbc, + 0xb5000001, 0x82c70bb8, 0xb5000008, 0x82a50083, + 0x5ea8b815, 0x96b500ff, 0xb0150020, 0xb4400002, + 0x82c71199, 0xb5000001, 0x82c71197, 0xb5000017, + 0xb500002e, 0x8285009a, 0x5eedb814, 0x96f70003, + 0xb0170003, 0xb4000009, 0x82a50083, 0x5ea8b815, + 0x96b500ff, 0xb0150020, 0xb4400002, 0x82c70e12, + 0xb5000001, 0x82c70e0e, 0xb5000008, 0x82a50083, + 0x5ea8b815, 0x96b500ff, 0xb0150020, 0xb4400002, + 0x82c70e12, 0xb5000001, 0x82c70e0e, 0x82e50086, + 0x12f7b816, 0x02bf9017, 0xb0150020, 0xb480000b, + 0x82a5009a, 0x96b56000, 0xb0156000, 0xb4000007, + 0x82a50098, 0x96d50a00, 0xb0160a00, 0xb4000002, + 0xb0160000, 0xb4200001, 0x92f705dc, 0x82850081, + 0x9ab40020, 0x82a60081, 0x82c50094, 0x82e60094, + 0x82860081, 0x86b705dc, 0x82a6009b, 0x83070008, + 0x8306009f, 0x00000000, 0xb5000024, 0x83070100, + 0x8306009f, 0x00000000, 0xb5000020, 0x83070000, + 0x83050081, 0x9b180180, 0x83060081, 0x83070400, + 0x8306009f, 0x00000000, 0xb5000018, 0x82870000, + 0x82850082, 0x5eb7b814, 0x96b500fc, 0x96d40006, + 0x5ec1b816, 0x1ab5b816, 0x5aacb815, 0x83050081, + 0x82d3001c, 0x9ad600ff, 0x1718b816, 0x1b18b815, + 0x9b180e00, 0x83060081, 0x83074000, 0x8306009f, + 0x8305009d, 0x82d3ffff, 0x9ad6bfff, 0x1718b816, + 0x8306009d, 0x00000000, 0xb5000000, 0x029f9005, + 0x01ffb814, 0x033f600f, 0x029f900a, 0x02bf900b, + 0x02df900c, 0x02ff900d, 0x031f900e, 0x033f900f, + 0x00ffb81e, 0x02ff9010, 0x92f70b43, 0x02ffb010, + 0x02ff90cb, 0x82bbffdc, 0x829bffd8, 0x93150004, + 0x3014b815, 0xb400000f, 0x02dbb818, 0x029bb815, + 0x3017b816, 0xb480000b, 0x5a81b814, 0x029fb010, + 0x82860095, 0x8293001f, 0x9294fe00, 0x92b50008, + 0x3015b814, 0xb4800002, 0x82b3001f, 0x92b5fa00, + 0x82beffdc, 0x82850086, 0x83250094, 0x06d4b819, + 0x02d6b816, 0xb016ffff, 0xb4a00009, 0x82c50081, + 0x9ab60020, 0x82a60081, 0x82a50086, 0x92b50bbb, + 0x82a60094, 0x82c60081, 0x86b505df, 0x82a6009b, + 0x00ffb81c, 0x82870001, 0x829ef500, 0x82850086, + 0x83250094, 0x06d4b819, 0x02d6b816, 0xb016ffff, + 0xb4a0000b, 0x82870001, 0x829ef504, 0x82c50081, + 0x9ab60020, 0x82a60081, 0x82a50086, 0x92b50bbb, + 0x82a60094, 0x82c60081, 0x86b505df, 0x82a6009b, + 0x00ffb81c, 0x82070028, 0x023f9006, 0x83a4ef4f, + 0x80070000, 0x001fb011, 0x001f204f, 0x003fb800, + 0x001f9006, 0x5803b800, 0x80338000, 0x1800b801, + 0x003fb800, 0x005f4193, 0x5c41b802, 0x80350000, + 0x00000000, 0x0027b860, 0x80150010, 0x5810b800, + 0x80750010, 0x1863b800, 0x8087ffff, 0x80a7770b, + 0x80c70000, 0x1403b804, 0x3000b805, 0xb4000008, + 0x5888b804, 0x58a8b805, 0x90c60001, 0xb0060003, + 0xb4a0fff8, 0x84420001, 0xb4e0ffee, 0xb5000027, + 0xb0060003, 0xb4200007, 0x80150010, 0x5810b800, + 0x81150010, 0x950800ff, 0xb0080077, 0xb4000001, + 0xb500fff4, 0x001f400e, 0x98000010, 0x98004000, + 0x9400fffe, 0x001f600e, 0x80e71f60, 0x001f4000, + 0x94000080, 0xb0000080, 0xb4200001, 0x80e774b0, + 0x00ffb008, 0x80e70020, 0xb0060000, 0xb400000e, + 0x58e3b806, 0x90210020, 0x81070000, 0x5938b803, + 0x1908b809, 0x9523ff00, 0x5928b809, 0x1908b809, + 0x5d28b803, 0x9529ff00, 0x1908b809, 0x5d38b803, + 0x1908b809, 0x011fb011, 0x00ff204f, 0x80137fff, + 0x9800ffe7, 0x1421b800, 0x5c23b801, 0x001f9006, + 0x0441b800, 0x3001b800, 0xb4600002, 0x0440b801, + 0xa4422000, 0x007f90cb, 0x1063b802, 0x007fb0cb, + 0x003fb006, 0x803effec, 0x80470001, 0x005f2013, + 0xb500ebd7, 0x001f400e, 0x9400000f, 0xb0000000, + 0xb4200001, 0x00ffb81f, 0xb0000001, 0xb4000005, + 0xb0000003, 0xb4000003, 0xb0000002, 0xb4000001, + 0x00ffb81f, 0x80070001, 0x001f2013, 0xb500ebc8, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x803bff68, 0x8078ff6c, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x803bff68, + 0x8078ff6c, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x83840126, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e7ef98, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x80270180, 0x81e7ee90, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801bef90, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x8018ef94, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x819eff68, 0x817cff6c, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801bef90, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x8018ef94, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801bef90, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x8018ef94, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e7ec70, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270240, + 0x81e7ed70, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e7ee90, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x806f0007, + 0x80af0007, 0x80270280, 0x81e7ee70, 0x5de2b80f, + 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, + 0x01ff90bc, 0xb520ffff, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x015f400e, 0x944a4000, 0xb0024000, 0xb420001a, + 0x954abfff, 0x015f600e, 0x820f001f, 0x802f001f, + 0x81470000, 0x015f23f9, 0x015fb0ba, 0x8057ffff, + 0x80770000, 0x82970400, 0x82d7ffff, 0x82f70000, + 0xb6000702, 0xb6000001, 0x029fa02a, 0x80275480, + 0x005fb801, 0x8033001f, 0x9821c000, 0x803effe0, + 0x90212000, 0x803effe4, 0x80d9ff80, 0x00df6001, + 0x81477528, 0x015fb008, 0x003f0324, 0xb0010000, + 0xb4200076, 0x8344ebe6, 0xb0180000, 0xb4000004, + 0x011f400e, 0x1908b818, 0x011f600e, 0x00ffb81f, + 0x8344f187, 0xb00b0000, 0xb4000006, 0x023f400e, + 0x9a310002, 0x023f600e, 0x82270000, 0x023f2012, + 0x00ffb81f, 0x8364ed6a, 0x82270000, 0x023f2011, + 0x80070000, 0x80170800, 0xb6002002, 0xb6003001, + 0x001fa020, 0x82270000, 0x003fb811, 0x02bf9006, + 0x5aa3b815, 0x82338000, 0x1a31b815, 0x003fb811, + 0x8067e950, 0x5c62b803, 0x81f50000, 0x019f4193, + 0x0267b80c, 0xadcc0010, 0x80170800, 0x80130000, + 0x9800f872, 0x001fa020, 0x80134e1f, 0x98000001, + 0x001fa020, 0x59d0b80e, 0x81150010, 0x1908b80e, + 0x001fa028, 0x858c0001, 0x5e01b80c, 0x5e25b810, + 0xb6310006, 0xb6002005, 0x81150010, 0x5910b808, + 0x00000000, 0x81350010, 0x1808a029, 0x9630001f, + 0xb0110000, 0xb4000006, 0xb6310005, 0x81150010, + 0x5910b808, 0x00000000, 0x81350010, 0x1808a029, + 0x962c0001, 0xb0110000, 0xb4000003, 0x81150010, + 0x5910b808, 0x001fa028, 0x019f9006, 0x958cffff, + 0x00df4193, 0x58c1b806, 0x118cb806, 0xb00ce000, + 0xb4800002, 0x858ce000, 0x918cc000, 0x8153001f, + 0x118cb80a, 0x819effec, 0x019fb006, 0x015f4193, + 0x5941b80a, 0x019f90cb, 0x118cb80a, 0x019fb0cb, + 0x019f90ba, 0x918c0001, 0x019fb0ba, 0xb00c0002, + 0xb4200016, 0x019f400e, 0x940c8000, 0xb0008000, + 0xb4200012, 0x958c7fff, 0x019f600e, 0x80070000, + 0x800600a0, 0x80073da1, 0x800600a1, 0x801bff60, + 0x00000000, 0x801eff60, 0x00000000, 0x801bff60, + 0x00000000, 0x801eff60, 0x80130001, 0x98003da1, + 0x800600a1, 0x80070001, 0x800600a0, 0x003f0324, + 0x90210001, 0xb0010005, 0xb4a00001, 0x80270000, + 0x003f2324, 0x00ffb81f, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815bb3f0, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x81271800, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a0002e, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200001, + 0x8384fc04, 0x80af001f, 0x808f0002, 0x806f0000, + 0x807bbf34, 0x5d22b80a, 0xb600080a, 0x00cfb803, + 0x013fb0bc, 0x5922b809, 0x01afb809, 0x013f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x91290060, 0x808f0000, 0x813bb3f8, 0x80270001, + 0xb0090001, 0xb4000002, 0x802600a0, 0x803eb3f8, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813eb3f0, 0xb0030800, 0xb4800001, 0x80670200, + 0x807ebf34, 0x80270001, 0x003f2013, 0x00ffb81b, +}; + +static u32 AC3I2S240Ucode1f8000[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00020000, 0xffff0005, 0xffffffff, + 0x00050001, 0xffffffff, 0xffffffff, 0x00020000, + 0xffff0005, 0xffffffff, 0x00010000, 0x00050002, + 0xffffffff, 0x00020000, 0x00050003, 0xffffffff, + 0x00010000, 0x00030002, 0xffff0005, 0x00020000, + 0x00040003, 0xffff0005, 0x00010000, 0x00030002, + 0x00050004, 0x0019000d, 0x003d0025, 0x00250019, + 0x00fd003d, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x007fffff, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x007fffff, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00599999, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00599999, + 0x007fffff, 0x00599999, 0x00000000, 0x00599999, + 0x00000000, 0x00000000, 0x00000000, 0x00599999, + 0x00000000, 0x00599999, 0x007fffff, 0x00000000, + 0x00599999, 0x00599999, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00599999, 0x00599999, + 0x007fffff, 0x007fffff, 0x00000000, 0x00599999, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00599999, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x007fffff, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x007fffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00400000, + 0x00200000, 0x00100000, 0x00080000, 0x00040000, + 0x00020000, 0x00010000, 0x00008000, 0x00004000, + 0x00002000, 0x00001000, 0x00000800, 0x00000400, + 0x00000200, 0x00000100, 0x00000080, 0x00000040, + 0x00000020, 0x00000010, 0x00000008, 0x00000004, + 0x00000002, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010002, + 0x00030002, 0x00030002, 0x00030002, 0x00000000, + 0x00000000, 0x00010001, 0x00020002, 0x4000a000, + 0xe000a000, 0xf000b000, 0xf800b800, 0x005a8279, + 0x004c1bf8, 0x00400000, 0x004c1bf8, 0x005a8279, + 0x00400000, 0x00000000, 0x00400000, 0x03020100, + 0x00000000, 0x00000080, 0x00000020, 0x00000008, + 0x00000000, 0x00000001, 0x00010001, 0x10001000, + 0x10001004, 0x10041004, 0x10041004, 0x10041004, + 0x00000000, 0x00000000, 0x00000000, 0xff80000a, + 0xff80031f, 0xff800b24, 0xff801818, 0xff8029fa, + 0xff8040c9, 0xff805c86, 0xff807d2e, 0xff80a2c1, + 0xff80cd3c, 0xff80fc9f, 0xff8130e8, 0xff816a14, + 0xff81a821, 0xff81eb0e, 0xff8232d6, 0xff827f79, + 0xff82d0f2, 0xff83273e, 0xff83825b, 0xff83e244, + 0xff8446f7, 0xff84b06e, 0xff851ea6, 0xff85919b, + 0xff860949, 0xff8685aa, 0xff8706ba, 0xff878c74, + 0xff8816d3, 0xff88a5d1, 0xff89396a, 0xff89d196, + 0xff8a6e51, 0xff8b0f94, 0xff8bb55a, 0xff8c5f9b, + 0xff8d0e51, 0xff8dc176, 0xff8e7902, 0xff8f34ef, + 0xff8ff535, 0xff90b9cc, 0xff9182ae, 0xff924fd3, + 0xff932132, 0xff93f6c3, 0xff94d07f, 0xff95ae5d, + 0xff969054, 0xff97765b, 0xff98606a, 0xff994e78, + 0xff9a407c, 0xff9b366b, 0xff9c303e, 0xff9d2de9, + 0xff9e2f64, 0xff9f34a4, 0xffa03da0, 0xffa14a4c, + 0xffa25aa0, 0xffa36e8f, 0xffa48610, 0xffa5a118, + 0xffa6bf9c, 0xffa7e191, 0xffa906ec, 0xffaa2fa0, + 0xffab5ba4, 0xffac8aeb, 0xffadbd6a, 0xffaef315, + 0xffb02bdf, 0xffb167be, 0xffb2a6a4, 0xffb3e886, + 0xffb52d56, 0xffb67509, 0xffb7bf92, 0xffb90ce4, + 0xffba5cf2, 0xffbbafb0, 0xffbd050f, 0xffbe5d04, + 0xffbfb780, 0xffc11477, 0xffc273db, 0xffc3d59f, + 0xffc539b4, 0xffc6a00d, 0xffc8089d, 0xffc97355, + 0xffcae027, 0xffcc4f05, 0xffcdbfe2, 0xffcf32af, + 0xffd0a75d, 0xffd21ddf, 0xffd39625, 0xffd51022, + 0xffd68bc7, 0xffd80904, 0xffd987cd, 0xffdb0810, + 0xffdc89c1, 0xffde0cd0, 0xffdf912d, 0xffe116cb, + 0xffe29d9a, 0xffe4258b, 0xffe5ae8f, 0xffe73896, + 0xffe8c392, 0xffea4f74, 0xffebdc2b, 0xffed69aa, + 0xffeef7df, 0xfff086bd, 0xfff21634, 0xfff3a634, + 0xfff536ad, 0xfff6c792, 0xfff858d1, 0xfff9ea5b, + 0xfffb7c22, 0xfffd0e16, 0xfffea026, 0xffffcdbc, + 0xfffe3ba0, 0xfffca995, 0xfffb17ac, 0xfff985f3, + 0xfff7f479, 0xfff6634f, 0xfff4d284, 0xfff34228, + 0xfff1b249, 0xfff022f7, 0xffee9442, 0xffed0638, + 0xffeb78ea, 0xffe9ec67, 0xffe860bd, 0xffe6d5fd, + 0xffe54c35, 0xffe3c374, 0xffe23bcb, 0xffe0b547, + 0xffdf2ff7, 0xffddabec, 0xffdc2933, 0xffdaa7dd, + 0xffd927f6, 0xffd7a98f, 0xffd62cb7, 0xffd4b17b, + 0xffd337ea, 0xffd1c013, 0xffd04a05, 0xffced5ce, + 0xffcd637c, 0xffcbf31d, 0xffca84c1, 0xffc91874, + 0xffc7ae45, 0xffc64641, 0xffc4e078, 0xffc37cf6, + 0xffc21bc9, 0xffc0bcff, 0xffbf60a5, 0xffbe06c9, + 0xffbcaf79, 0xffbb5ac0, 0xffba08ae, 0xffb8b94d, + 0xffb76cac, 0xffb622d8, 0xffb4dbdc, 0xffb397c6, + 0xffb256a2, 0xffb1187d, 0xffafdd62, 0xffaea55f, + 0xffad707e, 0xffac3ecc, 0xffab1054, 0xffa9e523, + 0xffa8bd44, 0xffa798c2, 0xffa677a8, 0xffa55a02, + 0xffa43fdb, 0xffa3293d, 0xffa21634, 0xffa106c9, + 0xff9ffb08, 0xff9ef2fa, 0xff9deeab, 0xff9cee23, + 0xff9bf16c, 0xff9af892, 0xff9a039c, 0xff991295, + 0xff982586, 0xff973c78, 0xff965774, 0xff957683, + 0xff9499ad, 0xff93c0fb, 0xff92ec75, 0xff921c24, + 0xff91500f, 0xff90883f, 0xff8fc4bb, 0xff8f058b, + 0xff8e4ab6, 0xff8d9443, 0xff8ce239, 0xff8c349f, + 0xff8b8b7d, 0xff8ae6d7, 0xff8a46b5, 0xff89ab1e, + 0xff891416, 0xff8881a3, 0xff87f3cc, 0xff876a96, + 0xff86e606, 0xff866621, 0xff85eaed, 0xff85746d, + 0xff8502a6, 0xff84959e, 0xff842d57, 0xff83c9d7, + 0xff836b20, 0xff831138, 0xff82bc20, 0xff826bdc, + 0xff822070, 0xff81d9de, 0xff819829, 0xff815b54, + 0xff812360, 0xff80f051, 0xff80c228, 0xff8098e6, + 0xff80748e, 0xff805521, 0xff803a9f, 0xff80250b, + 0xff801464, 0xff8008ad, 0xff8001e4, 0xff800027, + 0xff800c7e, 0xff802c8f, 0xff806056, 0xff80a7cb, + 0xff8102e4, 0xff817191, 0xff81f3c3, 0xff828964, + 0xff83325f, 0xff83ee98, 0xff84bdf3, 0xff85a04f, + 0xff86958b, 0xff879d7f, 0xff88b804, 0xff89e4ee, + 0xff8b240e, 0xff8c7533, 0xff8dd82a, 0xff8f4cbb, + 0xff90d2ad, 0xff9269c4, 0xff9411c1, 0xff95ca62, + 0xff979365, 0xff996c81, 0xff9b5570, 0xff9d4de4, + 0xff9f5590, 0xffa16c24, 0xffa3914e, 0xffa5c4b8, + 0xffa8060d, 0xffaa54f3, 0xffacb10e, 0xffaf1a03, + 0xffb18f70, 0xffb410f7, 0xffb69e33, 0xffb936c0, + 0xffbbda37, 0xffbe8830, 0xffc14042, 0xffc40201, + 0xffc6cd00, 0xffc9a0d2, 0xffcc7d05, 0xffcf612b, + 0xffd24ccf, 0xffd53f80, 0xffd838c8, 0xffdb3833, + 0xffde3d49, 0xffe14795, 0xffe4569d, 0xffe769e9, + 0xffea80ff, 0xffed9b67, 0xfff0b8a4, 0xfff3d83c, + 0xfff6f9b5, 0xfffa1c91, 0xfffd4056, 0xffff9b78, + 0xfffc7756, 0xfff953c0, 0xfff63130, 0xfff31025, + 0xffeff117, 0xffecd484, 0xffe9bae5, 0xffe6a4b6, + 0xffe39270, 0xffe0848b, 0xffdd7b82, 0xffda77cb, + 0xffd779de, 0xffd48231, 0xffd19138, 0xffcea769, + 0xffcbc535, 0xffc8eb10, 0xffc61969, 0xffc350af, + 0xffc09151, 0xffbddbbb, 0xffbb3059, 0xffb88f92, + 0xffb5f9d0, 0xffb36f78, 0xffb0f0ef, 0xffae7e96, + 0xffac18cf, 0xffa9bff9, 0xffa7746f, 0xffa5368c, + 0xffa306aa, 0xffa0e51e, 0xff9ed23c, 0xff9cce56, + 0xff9ad9bc, 0xff98f4bc, 0xff971f9f, 0xff955aae, + 0xff93a62f, 0xff920266, 0xff906f92, 0xff8eedf3, + 0xff8d7dc4, 0xff8c1f3c, 0xff8ad294, 0xff8997fd, + 0xff886fa8, 0xff8759c3, 0xff865679, 0xff8565f2, + 0xff848852, 0xff83bdbd, 0xff830651, 0xff82622b, + 0xff81d163, 0xff815411, 0xff80ea47, 0xff809416, + 0xff80518b, 0xff8022b1, 0xff80078e, 0x00000475, + 0x000007fe, 0x00000c02, 0x000010a3, 0x000015f5, + 0x00001c08, 0x000022ed, 0x00002ab5, 0x00003371, + 0x00003d32, 0x0000480a, 0x0000540d, 0x0000614b, + 0x00006fda, 0x00007fcd, 0x00009138, 0x0000a431, + 0x0000b8cc, 0x0000cf1f, 0x0000e741, 0x00010148, + 0x00011d4b, 0x00013b61, 0x00015ba2, 0x00017e25, + 0x0001a302, 0x0001ca51, 0x0001f42c, 0x000220a9, + 0x00024fe2, 0x000281f0, 0x0002b6ea, 0x0002eee9, + 0x00032a07, 0x0003685a, 0x0003a9fc, 0x0003ef04, + 0x0004378a, 0x000483a5, 0x0004d36d, 0x000526f7, + 0x00057e5b, 0x0005d9ae, 0x00063904, 0x00069c74, + 0x00070410, 0x00076feb, 0x0007e01a, 0x000854ac, + 0x0008cdb3, 0x00094b40, 0x0009cd61, 0x000a5425, + 0x000adf98, 0x000b6fc8, 0x000c04bf, 0x000c9e87, + 0x000d3d2a, 0x000de0ae, 0x000e891a, 0x000f3674, + 0x000fe8c0, 0x00109fff, 0x00115c34, 0x00121d5d, + 0x0012e37b, 0x0013ae89, 0x00147e84, 0x00155366, + 0x00162d27, 0x00170bbf, 0x0017ef23, 0x0018d748, + 0x0019c421, 0x001ab59f, 0x001babb2, 0x001ca648, + 0x001da54f, 0x001ea8b0, 0x001fb058, 0x0020bc2d, + 0x0021cc18, 0x0022dffd, 0x0023f7c2, 0x00251348, + 0x00263272, 0x00275520, 0x00287b31, 0x0029a482, + 0x002ad0f1, 0x002c0059, 0x002d3294, 0x002e677c, + 0x002f9ee8, 0x0030d8b1, 0x003214ac, 0x003352b0, + 0x00349290, 0x0035d422, 0x00371738, 0x00385ba5, + 0x0039a13b, 0x003ae7cc, 0x003c2f2a, 0x003d7725, + 0x003ebf8d, 0x00400834, 0x004150e9, 0x0042997d, + 0x0043e1c0, 0x00452981, 0x00467092, 0x0047b6c3, + 0x0048fbe3, 0x004a3fc6, 0x004b823b, 0x004cc316, + 0x004e0228, 0x004f3f45, 0x00507a40, 0x0051b2ef, + 0x0052e925, 0x00541cba, 0x00554d85, 0x00567b5e, + 0x0057a61d, 0x0058cd9e, 0x0059f1bb, 0x005b1252, + 0x005c2f3f, 0x005d4863, 0x005e5d9d, 0x005f6ed0, + 0x00607bde, 0x006184ad, 0x00628923, 0x00638927, + 0x006484a3, 0x00657b81, 0x00666daf, 0x00675b19, + 0x006843b1, 0x00692767, 0x006a062d, 0x006adff9, + 0x006bb4c2, 0x006c847d, 0x006d4f27, 0x006e14b8, + 0x006ed52f, 0x006f9089, 0x007046c6, 0x0070f7e9, + 0x0071a3f3, 0x00724aea, 0x0072ecd3, 0x007389b6, + 0x0074219d, 0x0074b490, 0x0075429b, 0x0075cbcc, + 0x00765031, 0x0076cfd8, 0x00774ad3, 0x0077c132, + 0x00783308, 0x0078a068, 0x00790968, 0x00796e1c, + 0x0079ce9a, 0x007a2af9, 0x007a8350, 0x007ad7b8, + 0x007b2849, 0x007b751d, 0x007bbe4c, 0x007c03f1, + 0x007c4625, 0x007c8504, 0x007cc0a8, 0x007cf92c, + 0x007d2eaa, 0x007d613e, 0x007d9101, 0x007dbe10, + 0x007de883, 0x007e1076, 0x007e3603, 0x007e5943, + 0x007e7a4f, 0x007e9942, 0x007eb633, 0x007ed13a, + 0x007eea6f, 0x007f01ea, 0x007f17c0, 0x007f2c08, + 0x007f3ed7, 0x007f5043, 0x007f605e, 0x007f6f3c, + 0x007f7cf1, 0x007f898e, 0x007f9525, 0x007f9fc6, + 0x007fa982, 0x007fb268, 0x007fba86, 0x007fc1eb, + 0x007fc8a4, 0x007fcebe, 0x007fd443, 0x007fd941, + 0x007fddc2, 0x007fe1cf, 0x007fe572, 0x007fe8b4, + 0x007feb9e, 0x007fee36, 0x007ff086, 0x007ff293, + 0x007ff463, 0x007ff5fd, 0x007ff765, 0x007ff8a1, + 0x007ff9b6, 0x007ffaa7, 0x007ffb79, 0x007ffc2f, + 0x007ffccb, 0x007ffd52, 0x007ffdc6, 0x007ffe28, + 0x007ffe7b, 0x007ffec2, 0x007ffefd, 0x007fff2f, + 0x007fff58, 0x007fff7b, 0x007fff97, 0x007fffae, + 0x007fffc0, 0x007fffcf, 0x007fffdb, 0x007fffe4, + 0x007fffec, 0x007ffff1, 0x007ffff6, 0x007ffff9, + 0x007ffffb, 0x007ffffd, 0x007ffffe, 0x007fffff, + 0x007fffff, 0x007fffff, 0x007fffff, 0xff800000, + 0x00000000, 0xffa57d86, 0x005a827a, 0xff89be51, + 0x0030fbc5, 0xffcf043b, 0x007641af, 0xff8275a1, + 0x0018f8b8, 0xffb8e313, 0x006a6d99, 0xff959267, + 0x00471ced, 0xffe70748, 0x007d8a5f, 0xff809dc9, + 0x000c8bd3, 0xffaecc33, 0x0062f202, 0xff8f1d34, + 0x003c56ba, 0xffdad7f4, 0x007a7d05, 0xff8582fb, + 0x0025280c, 0xffc3a946, 0x0070e2cc, 0xff9d0dfe, + 0x005133cd, 0xfff3742d, 0x007f6237, 0xff802778, + 0x000647d9, 0xffaa0a5b, 0x005ed77d, 0xff8c4a14, + 0x0036ba20, 0xffd4e0cb, 0x00788484, 0xff83d604, + 0x001f19f9, 0xffbe31e2, 0x006dca0d, 0xff99307f, + 0x004c3fe0, 0xffed37f0, 0x007e9d56, 0xff8162aa, + 0x0012c810, 0xffb3c020, 0x0066cf81, 0xff9235f3, + 0x0041ce1e, 0xffe0e607, 0x007c29fc, 0xff877b7c, + 0x002b1f35, 0xffc945e0, 0x0073b5ec, 0xffa12883, + 0x0055f5a5, 0xfff9b827, 0x007fd888, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static u32 AC3I2S240Ucode1fe000[] = { + 0x00000000, 0x03020102, 0x05040403, 0x00400040, + 0x00500050, 0x00600060, 0x00700070, 0x00800080, + 0x00a000a0, 0x00c000c0, 0x00e000e0, 0x01000100, + 0x01400140, 0x01800180, 0x01c001c0, 0x02000200, + 0x02800280, 0x03000300, 0x03800380, 0x04000400, + 0x04800480, 0x05000500, 0x00460045, 0x00580057, + 0x00690068, 0x007a0079, 0x008c008b, 0x00af00ae, + 0x00d100d0, 0x00f400f3, 0x01170116, 0x015d015c, + 0x01a201a1, 0x01e801e7, 0x022e022d, 0x02b902b8, + 0x03440343, 0x03d003cf, 0x045b045a, 0x04e604e5, + 0x05720571, 0x00600060, 0x00780078, 0x00900090, + 0x00a800a8, 0x00c000c0, 0x00f000f0, 0x01200120, + 0x01500150, 0x01800180, 0x01e001e0, 0x02400240, + 0x02a002a0, 0x03000300, 0x03c003c0, 0x04800480, + 0x05400540, 0x06000600, 0x06c006c0, 0x07800780, + 0x7b67533f, 0x1513110f, 0x04d80540, 0x04100478, + 0x07000000, 0x0b000900, 0x02b002f0, 0x02300270, + 0x017001f0, 0xf80000f0, 0x01000080, 0x02000180, + 0x03000280, 0x04000380, 0x2725231f, 0x2c2b2a29, + 0x2e2e2d2d, 0x30302f2f, 0x04030201, 0x08070605, + 0x0c0b0a09, 0x100f0e0d, 0x14131211, 0x18171615, + 0x1c1b1a19, 0x2825221f, 0x37312e2b, 0x4f49433d, + 0x796d6155, 0xcdb59d85, 0x0000fde5, 0x3d3e3f40, + 0x393a3b3c, 0x35363738, 0x32333434, 0x2f2f3031, + 0x2c2c2d2e, 0x29292a2b, 0x26262728, 0x23242425, + 0x21212223, 0x1e1f2020, 0x1c1d1d1e, 0x1a1b1b1c, + 0x1819191a, 0x16171718, 0x15151516, 0x13131414, + 0x12121213, 0x10111111, 0x0f0f1010, 0x0e0e0e0f, + 0x0d0d0d0d, 0x0c0c0c0c, 0x0b0b0b0b, 0x0a0a0a0a, + 0x0909090a, 0x08080909, 0x08080808, 0x07070707, + 0x06060707, 0x06060606, 0x05050606, 0x05050505, + 0x04040505, 0x04040404, 0x04040404, 0x03030304, + 0x03030303, 0x03030303, 0x02030303, 0x02020202, + 0x02020202, 0x02020202, 0x02020202, 0x01010202, + 0x01010101, 0x01010101, 0x01010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010101, 0x00000101, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x04d004d0, + 0x04000440, 0x03c003e0, 0x03b003b0, 0x03a003a0, + 0x03a003a0, 0x039003a0, 0x03900390, 0x03800380, + 0x03700370, 0x03600360, 0x03500350, 0x03400340, + 0x03200330, 0x03000310, 0x02f002f0, 0x02f002f0, + 0x03100300, 0x03900340, 0x042003e0, 0x04900460, + 0x046004a0, 0x04400440, 0x08000520, 0x08400840, + 0x04f004f0, 0x04100460, 0x03d003e0, 0x03b003c0, + 0x03a003b0, 0x03a003a0, 0x03a003a0, 0x03900390, + 0x03800390, 0x03800380, 0x03700370, 0x03600360, + 0x03500350, 0x03400340, 0x03100320, 0x02f00300, + 0x02f002f0, 0x030002f0, 0x03500320, 0x03e00390, + 0x04500420, 0x049004a0, 0x04400460, 0x06300480, + 0x08400840, 0x05800580, 0x045004b0, 0x03f00420, + 0x03d003e0, 0x03b003c0, 0x03b003b0, 0x03a003a0, + 0x03a003a0, 0x03a003a0, 0x03a003a0, 0x03900390, + 0x03900390, 0x03800380, 0x03700380, 0x03500360, + 0x03300340, 0x03100320, 0x02f00300, 0x02f002f0, + 0x03100300, 0x03500330, 0x041003c0, 0x04a00470, + 0x04400460, 0x04e00450, 0xffaaaaab, 0x00000000, + 0x00555555, 0xff99999a, 0xffcccccd, 0x00000000, + 0x00333333, 0x00666666, 0xff924925, 0xffb6db6e, + 0xffdb6db7, 0x00000000, 0x00249249, 0x00492492, + 0x006db6db, 0xff8ba2e9, 0xffa2e8ba, 0xffba2e8c, + 0xffd1745d, 0xffe8ba2f, 0x00000000, 0x001745d1, + 0x002e8ba3, 0x0045d174, 0x005d1746, 0x00745d17, + 0xff888889, 0xff99999a, 0xffaaaaab, 0xffbbbbbc, + 0xffcccccd, 0xffddddde, 0xffeeeeef, 0x00000000, + 0x00111111, 0x00222222, 0x00333333, 0x00444444, + 0x00555555, 0x00666666, 0x00777777, 0x08070605, + 0x0c0b0a09, 0x10100e0e, 0x00000010, 0x00000000, + 0x00000010, 0x00000020, 0x00000100, 0x00000110, + 0x00000120, 0x00000200, 0x00000210, 0x00000220, + 0x00001000, 0x00001010, 0x00001020, 0x00001100, + 0x00001110, 0x00001120, 0x00001200, 0x00001210, + 0x00001220, 0x00002000, 0x00002010, 0x00002020, + 0x00002100, 0x00002110, 0x00002120, 0x00002200, + 0x00002210, 0x00002220, 0x00000000, 0x00000010, + 0x00000020, 0x00000030, 0x00000040, 0x00000100, + 0x00000110, 0x00000120, 0x00000130, 0x00000140, + 0x00000200, 0x00000210, 0x00000220, 0x00000230, + 0x00000240, 0x00000300, 0x00000310, 0x00000320, + 0x00000330, 0x00000340, 0x00000400, 0x00000410, + 0x00000420, 0x00000430, 0x00000440, 0x00001000, + 0x00001010, 0x00001020, 0x00001030, 0x00001040, + 0x00001100, 0x00001110, 0x00001120, 0x00001130, + 0x00001140, 0x00001200, 0x00001210, 0x00001220, + 0x00001230, 0x00001240, 0x00001300, 0x00001310, + 0x00001320, 0x00001330, 0x00001340, 0x00001400, + 0x00001410, 0x00001420, 0x00001430, 0x00001440, + 0x00002000, 0x00002010, 0x00002020, 0x00002030, + 0x00002040, 0x00002100, 0x00002110, 0x00002120, + 0x00002130, 0x00002140, 0x00002200, 0x00002210, + 0x00002220, 0x00002230, 0x00002240, 0x00002300, + 0x00002310, 0x00002320, 0x00002330, 0x00002340, + 0x00002400, 0x00002410, 0x00002420, 0x00002430, + 0x00002440, 0x00003000, 0x00003010, 0x00003020, + 0x00003030, 0x00003040, 0x00003100, 0x00003110, + 0x00003120, 0x00003130, 0x00003140, 0x00003200, + 0x00003210, 0x00003220, 0x00003230, 0x00003240, + 0x00003300, 0x00003310, 0x00003320, 0x00003330, + 0x00003340, 0x00003400, 0x00003410, 0x00003420, + 0x00003430, 0x00003440, 0x00004000, 0x00004010, + 0x00004020, 0x00004030, 0x00004040, 0x00004100, + 0x00004110, 0x00004120, 0x00004130, 0x00004140, + 0x00004200, 0x00004210, 0x00004220, 0x00004230, + 0x00004240, 0x00004300, 0x00004310, 0x00004320, + 0x00004330, 0x00004340, 0x00004400, 0x00004410, + 0x00004420, 0x00004430, 0x00004440, 0x00000000, + 0x00000100, 0x00000200, 0x00000300, 0x00000400, + 0x00000500, 0x00000600, 0x00000700, 0x00000800, + 0x00000900, 0x00000a00, 0x00001000, 0x00001100, + 0x00001200, 0x00001300, 0x00001400, 0x00001500, + 0x00001600, 0x00001700, 0x00001800, 0x00001900, + 0x00001a00, 0x00002000, 0x00002100, 0x00002200, + 0x00002300, 0x00002400, 0x00002500, 0x00002600, + 0x00002700, 0x00002800, 0x00002900, 0x00002a00, + 0x00003000, 0x00003100, 0x00003200, 0x00003300, + 0x00003400, 0x00003500, 0x00003600, 0x00003700, + 0x00003800, 0x00003900, 0x00003a00, 0x00004000, + 0x00004100, 0x00004200, 0x00004300, 0x00004400, + 0x00004500, 0x00004600, 0x00004700, 0x00004800, + 0x00004900, 0x00004a00, 0x00005000, 0x00005100, + 0x00005200, 0x00005300, 0x00005400, 0x00005500, + 0x00005600, 0x00005700, 0x00005800, 0x00005900, + 0x00005a00, 0x00006000, 0x00006100, 0x00006200, + 0x00006300, 0x00006400, 0x00006500, 0x00006600, + 0x00006700, 0x00006800, 0x00006900, 0x00006a00, + 0x00007000, 0x00007100, 0x00007200, 0x00007300, + 0x00007400, 0x00007500, 0x00007600, 0x00007700, + 0x00007800, 0x00007900, 0x00007a00, 0x00008000, + 0x00008100, 0x00008200, 0x00008300, 0x00008400, + 0x00008500, 0x00008600, 0x00008700, 0x00008800, + 0x00008900, 0x00008a00, 0x00009000, 0x00009100, + 0x00009200, 0x00009300, 0x00009400, 0x00009500, + 0x00009600, 0x00009700, 0x00009800, 0x00009900, + 0x00009a00, 0x0000a000, 0x0000a100, 0x0000a200, + 0x0000a300, 0x0000a400, 0x0000a500, 0x0000a600, + 0x0000a700, 0x0000a800, 0x0000a900, 0x0000aa00, + 0xff800000, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xffb82995, 0xffaf5d75, 0xffa57d87, 0xff9a6806, + 0xff8df708, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xffb82995, 0xffaf5d75, 0xffa57d87, 0xff9a6806, + 0xff8df708, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xfffb0000, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, + 0xfffdfffd, 0xfffdfffd, 0xfffdfffd, 0xfffefffe, + 0xfffefffe, 0xfffefffe, 0xffffffff, 0xffffffff, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x80050000, 0x000a800f, 0x001e801b, 0x80110014, + 0x00368033, 0x8039003c, 0x802d0028, 0x00228027, + 0x00668063, 0x8069006c, 0x807d0078, 0x00728077, + 0x80550050, 0x005a805f, 0x004e804b, 0x80410044, + 0x00c680c3, 0x80c900cc, 0x80dd00d8, 0x00d280d7, + 0x80f500f0, 0x00fa80ff, 0x00ee80eb, 0x80e100e4, + 0x80a500a0, 0x00aa80af, 0x00be80bb, 0x80b100b4, + 0x00968093, 0x8099009c, 0x808d0088, 0x00828087, + 0x01868183, 0x8189018c, 0x819d0198, 0x01928197, + 0x81b501b0, 0x01ba81bf, 0x01ae81ab, 0x81a101a4, + 0x81e501e0, 0x01ea81ef, 0x01fe81fb, 0x81f101f4, + 0x01d681d3, 0x81d901dc, 0x81cd01c8, 0x01c281c7, + 0x81450140, 0x014a814f, 0x015e815b, 0x81510154, + 0x01768173, 0x8179017c, 0x816d0168, 0x01628167, + 0x01268123, 0x8129012c, 0x813d0138, 0x01328137, + 0x81150110, 0x011a811f, 0x010e810b, 0x81010104, + 0x03068303, 0x8309030c, 0x831d0318, 0x03128317, + 0x83350330, 0x033a833f, 0x032e832b, 0x83210324, + 0x83650360, 0x036a836f, 0x037e837b, 0x83710374, + 0x03568353, 0x8359035c, 0x834d0348, 0x03428347, + 0x83c503c0, 0x03ca83cf, 0x03de83db, 0x83d103d4, + 0x03f683f3, 0x83f903fc, 0x83ed03e8, 0x03e283e7, + 0x03a683a3, 0x83a903ac, 0x83bd03b8, 0x03b283b7, + 0x83950390, 0x039a839f, 0x038e838b, 0x83810384, + 0x82850280, 0x028a828f, 0x029e829b, 0x82910294, + 0x02b682b3, 0x82b902bc, 0x82ad02a8, 0x02a282a7, + 0x02e682e3, 0x82e902ec, 0x82fd02f8, 0x02f282f7, + 0x82d502d0, 0x02da82df, 0x02ce82cb, 0x82c102c4, + 0x02468243, 0x8249024c, 0x825d0258, 0x02528257, + 0x82750270, 0x027a827f, 0x026e826b, 0x82610264, + 0x82250220, 0x022a822f, 0x023e823b, 0x82310234, + 0x02168213, 0x8219021c, 0x820d0208, 0x02028207, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000001, 0x00000002, 0x00000002, + 0x00000000, 0xff800000, 0xffa57d86, 0xffa57d86, + 0xffcf043b, 0xff89be51, 0xff89be51, 0xffcf043b, + 0xffe70748, 0xff8275a1, 0xff959267, 0xffb8e313, + 0xffb8e313, 0xff959267, 0xff8275a1, 0xffe70748, + 0xfff3742d, 0xff809dc9, 0xff9d0dfe, 0xffaecc33, + 0xffc3a946, 0xff8f1d34, 0xff8582fb, 0xffdad7f4, + 0xffdad7f4, 0xff8582fb, 0xff8f1d34, 0xffc3a946, + 0xffaecc33, 0xff9d0dfe, 0xff809dc9, 0xfff3742d, + 0xfff9b827, 0xff802778, 0xffa12883, 0xffaa0a5b, + 0xffc945e0, 0xff8c4a14, 0xff877b7c, 0xffd4e0cb, + 0xffe0e607, 0xff83d604, 0xff9235f3, 0xffbe31e2, + 0xffb3c020, 0xff99307f, 0xff8162aa, 0xffed37f0, + 0xffed37f0, 0xff8162aa, 0xff99307f, 0xffb3c020, + 0xffbe31e2, 0xff9235f3, 0xff83d604, 0xffe0e607, + 0xffd4e0cb, 0xff877b7c, 0xff8c4a14, 0xffc945e0, + 0xffaa0a5b, 0xffa12883, 0xff802778, 0xfff9b827, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; + +static u32 AC3I2S240Ucode1fff80[] = { + 0x0000240f, 0x007fffff, 0x007fffff, 0x00000003, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/ac3i2s.h linux.20pre2-ac1/drivers/media/video/ls220/ac3i2s.h --- linux.20pre2/drivers/media/video/ls220/ac3i2s.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/ac3i2s.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,2850 @@ +static u32 AC3I2SUcode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb500122b, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x80070800, 0x001f6193, + 0x800500d4, 0x8053ffff, 0x9842c7ff, 0x8039ff7c, + 0x1400b802, 0x003f6000, 0x94210007, 0xb0010001, + 0xb4200001, 0x98002800, 0xb0010000, 0xb4200001, + 0x98000800, 0x805300ff, 0x1800b802, 0x800600d4, + 0x8013001f, 0x9020c000, 0x003fb006, 0x803effe0, + 0x803effe8, 0x803effec, 0x9020e000, 0x9021ffe4, + 0x9020fa00, 0x803effd0, 0x803effdc, 0x803effd8, + 0x9020fe00, 0x803effd4, 0x90400000, 0x804600a2, + 0x90421800, 0x804600a3, 0x80134099, 0x98000040, + 0x800600a6, 0x80130000, 0x98003ca1, 0x800600a1, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x001f2324, 0x80070000, 0x001fb0ba, + 0x001f23f9, 0x801eb3f0, 0x80070800, 0x001f600f, + 0x80070000, 0x001f2012, 0x001fb0cb, 0x001fb010, + 0x801efff0, 0x98004000, 0x98008000, 0x001f600e, + 0x83e4013f, 0x80070000, 0x801eb3f8, 0x801eff70, + 0x800500a0, 0xb0000001, 0xb4000009, 0x80070001, + 0x800600a0, 0x80050080, 0x98000020, 0x80060080, + 0x9400ffdf, 0x80060080, 0x80070000, 0x800600a0, + 0x81df0004, 0x00000000, 0x00000000, 0x801bfff0, + 0x00000000, 0x940000ff, 0xb0000000, 0xb420004e, + 0x003f400e, 0x94010010, 0xb0000000, 0xb400fff4, + 0x838413dd, 0x003f0013, 0xb0010001, 0xb420003b, + 0x803bffe8, 0x801bffec, 0x00000000, 0x3001b800, + 0xb4600001, 0x90212000, 0x0421b800, 0x005f4193, + 0x5841b802, 0x3001b802, 0xb460000d, 0x80050086, + 0x005f9016, 0xb0020000, 0xb4200002, 0x001fb016, + 0xb500ffdf, 0x0420b802, 0xb0010b50, 0xb4a0ffdc, + 0x80070000, 0x001fb016, 0x83e40109, 0xb500ffd8, + 0x80070000, 0x001fb016, 0x001f400e, 0x9400000f, + 0xb0000000, 0xb4000014, 0xb0000001, 0xb4000010, + 0x003f400e, 0x9421fff0, 0x003f600e, 0x003f9006, + 0x9421ffff, 0x90210004, 0xb001e000, 0xb4800002, + 0x8421e000, 0x9021c000, 0x8013001f, 0x1021b800, + 0x003fb006, 0x003f90cb, 0x90210004, 0x003fb0cb, + 0x83e400ff, 0x83e413bc, 0x8007001f, 0x94000003, + 0x5810b800, 0x83e71aa8, 0x1bffb800, 0x003f9008, + 0x1821b800, 0x00ffb801, 0x83e4140f, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671ad4, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0xb500ffaa, 0x803bffc0, 0x805bffc4, + 0x807bffc8, 0x809bffcc, 0x5828b801, 0x5cb8b802, + 0x1821b805, 0x5848b802, 0x5cb8b803, 0x1842b805, + 0x5868b803, 0x5cb8b804, 0x1863b805, 0x5888b804, + 0x1884b800, 0x803effc0, 0x805effc4, 0x807effc8, + 0x809effcc, 0x003f400e, 0xb0000086, 0xb4400048, + 0xb0000084, 0xb4000032, 0xb0000085, 0xb4000038, + 0xb0000086, 0xb400003a, 0x001f4000, 0x94000080, + 0xb0000080, 0xb4000072, 0x800500d4, 0x8053ffff, + 0x9842c7ff, 0x1400b802, 0x805300ff, 0x98422800, + 0x1800b802, 0x800600d4, 0x80130000, 0x98000c7f, + 0x005f4000, 0x94420008, 0xb0020008, 0xb4200001, + 0xa0000080, 0x800600a1, 0x8013001f, 0x9040c000, + 0x005fb006, 0x805effe0, 0x805effe8, 0x805effec, + 0x9040e000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001fb0cb, + 0x001fb010, 0x001f2058, 0x80071fe0, 0x001fb008, + 0x80075fb0, 0x001fb009, 0x98214000, 0xb5000010, + 0x94011000, 0xb0001000, 0xb4200001, 0x9421efff, + 0x98210010, 0xb500000a, 0x80070000, 0x001fb0cb, + 0x83e40097, 0x003f400e, 0x9421ffef, 0xb5000004, + 0x83e40093, 0x003f400e, 0x98211000, 0x9421ffef, + 0x003f600e, 0x80070100, 0x801efff0, 0xb500ff4c, + 0xb000008b, 0xb400001c, 0xb000008e, 0xb4000022, + 0xb000008d, 0xb400001c, 0xb000008c, 0xb4000021, + 0xb0000087, 0xb400ffe8, 0xb0000088, 0xb4000014, + 0xb000008a, 0xb4000015, 0xb0000089, 0xb400001d, + 0xb00000a0, 0xb400001f, 0xb00000a1, 0xb4000041, + 0xb00000a2, 0xb400004e, 0xb00000a3, 0xb4000046, + 0xb00000a4, 0xb4000050, 0xb00000a5, 0xb4000054, + 0xb00000a6, 0xb4000058, 0x803efff8, 0xb500ffdd, + 0x9421ffdf, 0xb500ffda, 0xb500ffda, 0x80270100, + 0x803efff8, 0xb500ffd7, 0x80070000, 0x001fb017, + 0xb500ffd4, 0x801bffb0, 0x00000000, 0x001fb003, + 0xb500ffd0, 0x803bff80, 0x00000000, 0x003f6001, + 0xb500ffcc, 0x003f90ba, 0x803efff8, 0xb500ffc9, + 0x80130001, 0x98003da1, 0x800600a1, 0x80070200, + 0x801ebf34, 0x83e40042, 0x8013001f, 0x9840c000, + 0x805effe0, 0x005fb006, 0x805effe8, 0x805effec, + 0x90422000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001f2324, + 0x001fb0cb, 0x001fb010, 0x001f2058, 0x80077580, + 0x001fb008, 0x80077830, 0x001fb009, 0x98214000, + 0xb500ffa7, 0x80270000, 0x8047fef0, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x81df0000, 0x00000000, + 0x00000000, 0x83641491, 0x81df0004, 0xb500ff99, + 0x81df0000, 0x00000000, 0x00000000, 0x8364143b, + 0x81df0004, 0xb500ff93, 0x81df0000, 0x00000000, + 0x00000000, 0x836413f6, 0x81df0004, 0xb500ff8d, + 0x81df0000, 0x00000000, 0x00000000, 0x83441359, + 0x81df0004, 0xb500ff87, 0x81df0000, 0x00000000, + 0x00000000, 0x8344133e, 0x81df0004, 0xb500ff81, + 0x80070000, 0x80470000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002003, 0xb6003002, 0x001eb802, + 0x90420004, 0x80171000, 0x8057ffff, 0xb6002002, + 0xb6001801, 0x001fa020, 0x81df0004, 0x00ffb81f, + 0x001f4000, 0x94000080, 0xb0000080, 0xb4200001, + 0xb500ffeb, 0xb500000a, 0x80270000, 0x003f2013, + 0x8007001f, 0x94000003, 0x5810b800, 0x83671ec0, + 0x1b7bb800, 0x003f9009, 0x1821b800, 0x00ffb801, + 0x003f0013, 0xb0010001, 0xb420fff3, 0x83a70000, + 0x803bff70, 0x00000000, 0xb0010000, 0xb4000015, + 0x80170300, 0x80070000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6000601, 0x001fa020, 0x83640cdb, + 0x00ff0325, 0x82870000, 0xb6270002, 0x83640228, + 0x92940001, 0x81df0004, 0x001f033b, 0xb0000000, + 0xb4000002, 0x80270000, 0xb5000001, 0x80270001, + 0x003f233b, 0x80270000, 0x003f2013, 0x8007001f, + 0x94000003, 0x5810b800, 0x83671f5c, 0x1b7bb800, + 0x003f9009, 0x1821b800, 0x00ffb801, 0x003f0013, + 0xb0010001, 0xb420fff3, 0x93bd0001, 0xb01d0004, + 0xb480ffd7, 0x803bff70, 0x00000000, 0xb0010000, + 0xb4000005, 0x81df0000, 0x00000000, 0x00000000, + 0x83640c83, 0x81df0004, 0x00000000, 0x00000000, + 0x00ffb81f, 0x007f90cb, 0x90630400, 0x007fb0cb, + 0x003f9006, 0x9421ffff, 0x90210400, 0xb001e000, + 0xb4800002, 0x8421e000, 0x9021c000, 0x8013001f, + 0x1021b800, 0x003fb006, 0x803effec, 0x00ffb81f, + 0x015f400e, 0x944a4000, 0xb0024000, 0xb4200090, + 0x954abfff, 0x015f600e, 0x820f001f, 0x802f001f, + 0x81470000, 0x015f23f9, 0x829702ec, 0x82d7ffff, + 0x82f70000, 0x81df0000, 0x00000000, 0x00000000, + 0xb6000501, 0x029fa02a, 0x82970400, 0xb6000702, + 0xb6000001, 0x029fa02a, 0x81df0004, 0x8053ff00, + 0x98420000, 0x805ebf14, 0x805ebf18, 0x805ebf1c, + 0x805ebf20, 0x805ebf24, 0x805ebf28, 0x80270000, + 0x003f2328, 0x80275480, 0x005fb801, 0x8033001f, + 0x9821c000, 0x803effe0, 0x90212000, 0x803effe4, + 0x80dbff8c, 0x80fbff90, 0x80debf14, 0x80febf18, + 0x80dbff94, 0x80fbff98, 0x80debf1c, 0x80febf20, + 0x80dbff9c, 0x80fbffa0, 0x80debf24, 0x80febf28, + 0x80dbff84, 0x80e70001, 0x00dfb001, 0x80dbff88, + 0x00ff6191, 0x00dfb002, 0x80dbffb0, 0x80470000, + 0x00dfb003, 0x80d9ff80, 0x005fb0cf, 0x005fb0c6, + 0x00df6001, 0x80470001, 0x005f618f, 0x804700ff, + 0x005f231c, 0x005f231d, 0x80470000, 0x005f204e, + 0x8047e138, 0x5c42b802, 0x814f6300, 0x80cf00a9, + 0x005fb0bc, 0x5842b802, 0x01cfb802, 0x005f90bc, + 0xb520ffff, 0x8067e16c, 0x5c62b803, 0x80270040, + 0x81df0000, 0x00000000, 0x00000000, 0xb6000209, + 0x814fffc0, 0x00cfb801, 0x007fb0bc, 0x5862b803, + 0x01cfb803, 0x007f90bc, 0xb520ffff, 0x90210020, + 0x90630020, 0x81df0004, 0x8047e398, 0x5c42b802, + 0x814fce40, 0x80cf0080, 0x005fb0bc, 0x5842b802, + 0x01cfb802, 0x005f90bc, 0xb520ffff, 0x8047e400, + 0x5c42b802, 0x814f7380, 0x80cf009a, 0x005fb0bc, + 0x5842b802, 0x01cfb802, 0x005f90bc, 0xb520ffff, + 0x8047e43c, 0x5c42b802, 0x814f18c0, 0x80cf00b6, + 0x005fb0bc, 0x5842b802, 0x01cfb802, 0x005f90bc, + 0xb520ffff, 0x80e70000, 0x00ffb0ba, 0x808f0000, + 0x806f001f, 0x80af001f, 0x8027b9fc, 0x5c22b801, + 0x80670700, 0x81df0000, 0x00000000, 0x00000000, + 0xb600080a, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0x0047b86f, 0xb0020001, + 0xb4c0fffd, 0x90210020, 0x90630020, 0x81df0004, + 0x834400d7, 0xb0180000, 0xb4200025, 0x834406d4, + 0x80c70000, 0x00df2324, 0x83640026, 0x83440220, + 0x00df0324, 0x90c60001, 0x00df2324, 0xb0060006, + 0xb4000003, 0x81472248, 0x015fb008, 0x00ffb81f, + 0x00ff90ba, 0x90e70001, 0x00ffb0ba, 0x019f9006, + 0x958cffff, 0x00df4193, 0x58c1b806, 0x118cb806, + 0xb00ce000, 0xb4800002, 0x858ce000, 0x918cc000, + 0x8153001f, 0x118cb80a, 0x819effec, 0x019fb006, + 0x015f4193, 0x5941b80a, 0x019f90cb, 0x118cb80a, + 0x019fb0cb, 0x81472230, 0x015fb008, 0x00ffb81f, + 0x015f400e, 0x194ab818, 0x015f600e, 0x802500a5, + 0x00ffb81f, 0x803bff8c, 0x805bff90, 0x803ebf14, + 0x805ebf18, 0x803bff94, 0x805bff98, 0x803ebf1c, + 0x805ebf20, 0x803bff9c, 0x805bffa0, 0x803ebf24, + 0x805ebf28, 0x80470003, 0x805ebefc, 0x003f0384, + 0x5822b801, 0x9021eb50, 0x005bb801, 0x00000000, + 0xb0020001, 0xb4200002, 0x80470001, 0x805ebefc, + 0x8073ff80, 0x98630000, 0x8027bf14, 0x8047befc, + 0x81df0000, 0x00000000, 0x00000000, 0xb6000609, + 0x009bb801, 0x00000000, 0x00a7b804, 0x6081b804, + 0x3004b803, 0xb4000001, 0x00beb802, 0x90210004, + 0x90420004, 0x81df0004, 0x00ffb81b, 0x00000000, + 0x81150010, 0x00000000, 0x00000000, 0x81350010, + 0x00000000, 0x00000000, 0x81550002, 0x00000000, + 0x015f2380, 0x81550006, 0x00000000, 0x015f2381, + 0x81550005, 0x00000000, 0x015f2382, 0x81550003, + 0x00000000, 0x015f2383, 0x81550003, 0x015f2384, + 0xb00a0001, 0xb4000005, 0x956a0001, 0xb00b0000, + 0xb4000002, 0x81750002, 0x017f2385, 0x956a0004, + 0xb00b0000, 0xb4000002, 0x81750002, 0x017f2386, + 0xb00a0002, 0xb4200003, 0x81750002, 0x00000000, + 0x017f2387, 0x81750001, 0x00000000, 0x017f2388, + 0x81750005, 0x00000000, 0x017f2389, 0x81750001, + 0x017f239f, 0xb00b0001, 0xb4200003, 0x81750008, + 0x5968b80b, 0x017f61c5, 0x81750001, 0x017f238c, + 0xb00b0001, 0xb4200003, 0x81750008, 0x00000000, + 0x017f238d, 0x81750001, 0x017f238e, 0xb00b0001, + 0xb4200005, 0x81750005, 0x00000000, 0x017f238f, + 0x81750002, 0x017f2390, 0xb00a0000, 0xb420001b, + 0x81750005, 0x00000000, 0x017f2391, 0x81750001, + 0x017f23a0, 0xb00b0001, 0xb4200003, 0x81750008, + 0x5968b80b, 0x017f61c9, 0x81750001, 0x017f2394, + 0xb00b0001, 0xb4200003, 0x81750008, 0x00000000, + 0x017f2395, 0x81750001, 0x017f2396, 0xb00b0001, + 0xb4200006, 0x81750005, 0x00000000, 0x017f2397, + 0x81750002, 0x00000000, 0x017f2398, 0x81750001, + 0x00000000, 0x017f2399, 0x81750001, 0x00000000, + 0x017f239a, 0x81750001, 0x017f239b, 0xb00b0001, + 0xb4200003, 0x8175000e, 0x00000000, 0x017f61be, + 0x81750001, 0x017f239c, 0xb00b0001, 0xb4200003, + 0x8175000e, 0x00000000, 0x017f237e, 0x81750001, + 0x017f239d, 0xb00b0001, 0xb4200006, 0x81750006, + 0x017f239e, 0x916b0001, 0x81550008, 0x856b0001, + 0xb4e0fffd, 0x00ffb81c, 0x00000000, 0x00000000, + 0x81470000, 0x015f2385, 0x015f2386, 0x015f2387, + 0x015f238d, 0x015f238f, 0x015f2390, 0x015f2391, + 0x015f2395, 0x015f2396, 0x015f2397, 0x015f2398, + 0x015f61be, 0x015f61bf, 0x82070028, 0x023f9006, + 0x83a40034, 0x83270000, 0x003fb819, 0x003f9006, + 0x5823b801, 0x83338000, 0x1b39b801, 0x003fb819, + 0x00000000, 0x00000000, 0x81550000, 0x8384ff64, + 0x017f0380, 0xad4b0026, 0x013f0381, 0x114ab809, + 0x5941b80a, 0x914ae00c, 0x0199b80a, 0x00000000, + 0x019f6193, 0xb0080b77, 0xb4200010, 0x015f0380, + 0xb00a0003, 0xb4600011, 0xb0090026, 0xb4600013, + 0x017f90ba, 0xb00b0000, 0xb4200002, 0x017f0383, + 0x017f2057, 0x015f0383, 0x017f0057, 0x300ab80b, + 0xb420000e, 0x83070000, 0x00ffb81a, 0x83070800, + 0x031f6193, 0x83070001, 0x00ffb81a, 0x83070800, + 0x031f6193, 0x83070002, 0x00ffb81a, 0x83070800, + 0x031f6193, 0x83070003, 0x00ffb81a, 0x83070003, + 0x00ffb81a, 0x5e02b810, 0x5a02b810, 0x00bf9011, + 0x00df004f, 0xa5260020, 0x81e70000, 0x82471000, + 0x95d1ffff, 0xa5cee000, 0x300eb810, 0xb4600002, + 0x05f0b80e, 0x0207b80e, 0x8267001f, 0x82c70020, + 0x82971000, 0xb0100080, 0xb4800023, 0x5a8bb813, + 0x5aa6b813, 0x1a94b815, 0x01efb812, 0x014fb814, + 0x01cfb811, 0xb520ffff, 0x81df0000, 0x00000000, + 0x00000000, 0xb636000f, 0x81470000, 0x039f8014, + 0xb6000404, 0x5948b80a, 0x957c00ff, 0x194ab80b, + 0x5f88b81c, 0xb0060020, 0xb4200001, 0x80a70000, + 0x64a6b805, 0x68e9b80a, 0x18a5b807, 0x029fa025, + 0x00a7b80a, 0x81df0004, 0x01efb812, 0x014fb814, + 0x01afb811, 0xb520ffff, 0x5ae2b816, 0x1231b817, + 0x0610b817, 0xb500ffda, 0xb0100000, 0xb4000003, + 0x5ec2b810, 0x86760001, 0xb500ffd8, 0xb00f0000, + 0xb4000005, 0x0207b80f, 0x81f3001f, 0x9a2fc000, + 0x81e70000, 0xb500ffcc, 0x015fb011, 0x00ffb81d, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x82d7ffff, 0x8357ffff, 0x83d7ffff, + 0x80770000, 0x80f70000, 0x81770000, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x83f70000, + 0xaeb40080, 0x808f0000, 0x806f001f, 0x80af001f, + 0xb0140000, 0xb4400014, 0x806f001f, 0x80af001f, + 0x8027b9fc, 0x5c22b801, 0x80670700, 0xb6000208, + 0x00cfb803, 0x003fb0bc, 0x5822b801, 0x01cfb801, + 0x003f90bc, 0xb520ffff, 0x90630020, 0x90210020, + 0x80270000, 0x80171000, 0xb6000303, 0xb6000001, + 0x001fa021, 0x00000000, 0x82670000, 0xb6000268, + 0x80170a00, 0x80970afc, 0x81170b00, 0x81970bfc, + 0x80271c00, 0x1021b813, 0x1021b813, 0x0217b801, + 0x80271ffc, 0x0421b813, 0x0421b813, 0x0297b801, + 0x80270c00, 0x1021b813, 0x1021b813, 0x0317b801, + 0x80270ffc, 0x0421b813, 0x0421b813, 0x0397b801, + 0x80478500, 0x1042b813, 0x5c42b802, 0x1022b815, + 0x80670280, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0x009f033b, + 0x80478480, 0x0442b813, 0x5c42b802, 0x1022b815, + 0x806702a0, 0x00cfb803, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0xb0040000, + 0xb4000002, 0x80479000, 0xb5000001, 0x80479c00, + 0x1042b813, 0x5c42b802, 0x1022b815, 0x806702c0, + 0x00cfb803, 0x003fb0bc, 0x5822b801, 0x01cfb801, + 0x003f90bc, 0xb520ffff, 0xb0040000, 0xb4000002, + 0x80479180, 0xb5000001, 0x80479d80, 0x0442b813, + 0x5c42b802, 0x1022b815, 0x806702e0, 0x00cfb803, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x81270000, 0x80370000, 0x80b70000, + 0x81370000, 0x81b70000, 0x82370004, 0x82b7fffc, + 0xb6002016, 0x41498008, 0x51498814, 0x51498814, + 0x51418810, 0x51418810, 0x41818814, 0x0308a02a, + 0x49958820, 0x51898810, 0x51918828, 0x414d8814, + 0x0388a7ec, 0x494d8814, 0x49458810, 0x49458810, + 0x418d8810, 0x0308a02a, 0x49918fec, 0x51858814, + 0x51958fe4, 0x00000000, 0x0388a7ec, 0x92730080, + 0x009f033b, 0x5802b814, 0x90400300, 0x001f9802, + 0x00000000, 0xb0000000, 0xb4200016, 0x80170a00, + 0x80070000, 0xb6002001, 0x001fa020, 0xb0040000, + 0xb4200002, 0x80279000, 0xb5000001, 0x80279c00, + 0xac740080, 0x5c22b801, 0x11e1b803, 0x806f001f, + 0x80af001f, 0xb6000407, 0x80cf0280, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x91ef0020, 0x007f0320, 0x011f90cd, 0xaca30006, + 0x80c7b004, 0x10a5b814, 0x58a1b805, 0x10a5b806, + 0x0099b805, 0x8027b3dc, 0x5841b804, 0x1021b802, + 0x0159b801, 0x8027b3d0, 0x5841b804, 0x1021b802, + 0x0139b801, 0x80170c00, 0x0097b80a, 0xb6000002, + 0x59478020, 0x009fa04a, 0x00ffb81b, 0x00000000, + 0x009f0011, 0x015f0012, 0xb0060000, 0xb4200007, + 0x968a0001, 0xb0140000, 0xb400000d, 0x80870001, + 0x009f2011, 0x954a0002, 0x015f2012, 0xb0060002, + 0xb4200007, 0x968a0002, 0xb0140000, 0xb4000004, + 0x80870001, 0x009f2011, 0x81470000, 0x015f2012, + 0x83640037, 0x00bf2010, 0xb0060000, 0xb4200003, + 0xb0050000, 0xb4200001, 0x836400a1, 0xb0050000, + 0xb4200001, 0x836400ca, 0x00bf0010, 0xb0050000, + 0xb420000a, 0x81df0000, 0x00000000, 0x00000000, + 0x836409e4, 0x836402f6, 0x00000000, 0x8364098c, + 0x81df0004, 0x00000000, 0xb5000009, 0x00bf0010, + 0xb0050001, 0xb4000006, 0x00000000, 0x81df0000, + 0x00000000, 0x00000000, 0x83640981, 0x81df0004, + 0x00ff0325, 0x82870000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6270002, 0x8364fefd, 0x92940001, + 0x81df0004, 0x80070001, 0x801eff70, 0x001f0010, + 0xb0000001, 0xb4000007, 0x001f033b, 0xb0000000, + 0xb4000002, 0x80270000, 0xb5000001, 0x80270001, + 0x003f233b, 0x00ffb81a, 0x00000000, 0x00000000, + 0x027f4001, 0x5e2ab813, 0x96310003, 0x81c70000, + 0x820700ff, 0xb0110000, 0xb4000005, 0x5a21b811, + 0x81c70200, 0x8207000e, 0x69d1b80e, 0x1210b811, + 0x01dfb0cd, 0x5e2cb813, 0x96310003, 0x023f2323, + 0x5e28b813, 0x96310003, 0x023f2322, 0x5e27b813, + 0x96310001, 0x023f2328, 0x5e23b813, 0x96310001, + 0x023f2321, 0x95f30007, 0x01ff2320, 0x920fe004, + 0x0258b810, 0x00000000, 0x1252b811, 0x025f2325, + 0x8167befc, 0x017f6195, 0x021f031c, 0x01df031d, + 0x3010b80f, 0xb4200003, 0x3011b80e, 0xb4200001, + 0xb5000025, 0x80270000, 0x80471000, 0x0017b802, + 0x8057ffff, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002001, 0x001fa021, 0x80270400, 0x80679000, + 0x5c62b803, 0xb6001809, 0x00cfb801, 0x007fb0bc, + 0x5862b803, 0x01afb803, 0x007f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x80679c00, + 0x5c62b803, 0xb6001809, 0x00cfb801, 0x007fb0bc, + 0x5862b803, 0x01afb803, 0x007f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x81df0004, + 0x01ff231c, 0x023f231d, 0x83970300, 0x82070000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6320001, + 0x039fa030, 0x81df0004, 0x00bf0010, 0x021f0324, + 0xb0100000, 0xb4200001, 0x80a70000, 0xb0050000, + 0xb4200008, 0xb0040000, 0xb4a00002, 0x80a70001, + 0xb5000004, 0x82070000, 0x021f204e, 0xb4000001, + 0x80a70002, 0xb0050001, 0xb4200007, 0x021f004e, + 0xb0100002, 0xb4a00002, 0x80a70002, 0x00ffb81b, + 0x92100001, 0x021f204e, 0x00000000, 0x00ffb81b, + 0x81530000, 0x003fb80a, 0x00000000, 0x00000000, + 0x003fb819, 0x00000000, 0x00000000, 0x81550000, + 0x8384fd6b, 0x81470000, 0x015f61ee, 0x015f61ef, + 0x015f23a4, 0x8297050c, 0x82d7ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6000501, 0x029fa02a, + 0x81df0004, 0x8167e004, 0x116b0384, 0x0158b80b, + 0x019f0382, 0x015f237b, 0x017f0388, 0x116bb80a, + 0xb00c0008, 0xb4a00003, 0x80a70003, 0x00bf2010, + 0x00ffb81b, 0xb00a0005, 0xb4400003, 0xb00b0006, + 0xb4400001, 0x00ffb81b, 0x80a70004, 0x00bf2010, + 0x00ffb81b, 0x00000000, 0x00000000, 0x00000000, + 0x027f0388, 0x02bf037b, 0x02df0384, 0x02ff03a1, + 0x82970400, 0x8257ffff, 0x82d7ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6350003, 0x81550001, + 0x8357ffff, 0x029fa02a, 0x82970414, 0xb6350003, + 0x81550001, 0x83d7ffff, 0x029fa02a, 0x81df0004, + 0x81550001, 0xb00a0001, 0xb4200004, 0x814d0008, + 0x6149b80a, 0x954affff, 0x015f61ee, 0xb0160000, + 0xb4200007, 0x81550001, 0xb00a0001, 0xb4200004, + 0x814d0008, 0x6149b80a, 0x954affff, 0x015f61ef, + 0x81550001, 0xb00a0001, 0xb4200042, 0x82f50001, + 0x02ff23a1, 0xb0170001, 0xb4200034, 0x82970428, + 0x81df0000, 0x00000000, 0x00000000, 0xb6350003, + 0x81550001, 0x00000000, 0x029fa02a, 0x81df0004, + 0x82970428, 0x81470000, 0x017f8034, 0xb00b0001, + 0xb4000004, 0x914a0001, 0x300ab815, 0xb480fffa, + 0xb5000001, 0x015f23a5, 0x81670000, 0xb0160002, + 0xb4200002, 0x81750001, 0x00000000, 0x017f233a, + 0x81550004, 0xadaa000c, 0x015f23a2, 0x81750004, + 0x916b0003, 0x017f23a3, 0x91ad0025, 0x01bf23a6, + 0xadab000c, 0x81e70000, 0x91ad0025, 0x01bf23a7, + 0x920a0001, 0x05abb810, 0xb00d0000, 0xb4000015, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0004, + 0x81b50001, 0x65b0b80d, 0x19efb80d, 0x92100001, + 0x81df0004, 0x01ffb0be, 0xb500000a, 0x81a70000, + 0x82970428, 0x81df0000, 0x00000000, 0x00000000, + 0xb6350001, 0x029fa02d, 0x81df0004, 0x01bf233a, + 0x01bf23a5, 0x82070000, 0x82270000, 0x82170428, + 0x81df0000, 0x00000000, 0x00000000, 0xb635003a, + 0x01bf8030, 0xb00d0001, 0xb4200036, 0x81d50001, + 0x65b1b80e, 0x1a10b80d, 0xb00e0001, 0xb4200031, + 0x81b50002, 0xadad0003, 0xae510048, 0x91cd000f, + 0x91320868, 0x015f03a2, 0xad4a0004, 0x92920700, + 0x1189b80a, 0x0297b80c, 0x1194b80a, 0x0317b80c, + 0x01ff90be, 0x015f03a2, 0x017f03a3, 0x064bb80a, + 0x0107b80a, 0xb0120000, 0xb400001e, 0xb632001d, + 0x6928b80f, 0x95290001, 0xb0090000, 0xb420000e, + 0x81350004, 0x1129b80d, 0x029fa029, 0x824d0004, + 0x5a48b812, 0x5e48b812, 0x3009b80e, 0xb4200002, + 0x5e41b812, 0xb500000d, 0x5e42b812, 0x81330040, + 0x1a52b809, 0xb5000009, 0x0127b854, 0x85290004, + 0x0397b809, 0x0287b858, 0x86940004, 0x013f803c, + 0x0397b814, 0x029fa029, 0x025f803c, 0x031fa032, + 0x91080001, 0x92310001, 0x81df0004, 0x015f03a2, + 0x017f03a3, 0x013f033a, 0xb0090001, 0xb4200023, + 0x95300002, 0x95900001, 0x1929b80c, 0xb0090000, + 0xb400001e, 0x064bb80a, 0x0107b80a, 0x81df0000, + 0x00000000, 0x00000000, 0xb6320017, 0x6928b80f, + 0x95290001, 0xb0090000, 0xb4200002, 0x81350001, + 0x013f23f8, 0x81a70700, 0x91ad0048, 0x5982b808, + 0x11adb80c, 0x0397b80d, 0x013f03f8, 0xb0090001, + 0xb4200005, 0x019f801c, 0x0196b80c, 0x81b3ff80, + 0x418cb80d, 0xb5000002, 0x019f801c, 0x0196b80c, + 0x039fa00c, 0x91080001, 0x81df0004, 0xb0160002, + 0xb420001e, 0xb0170001, 0xb4200008, 0xb00a0000, + 0xb4200002, 0x81270002, 0xb5000005, 0xb00a0002, + 0xb4400002, 0x81270003, 0xb5000001, 0x81270004, + 0x013f23a9, 0x81950001, 0xb00c0001, 0xb4200011, + 0x81a70000, 0x8397043c, 0x81df0000, 0x00000000, + 0x00000000, 0xb6290006, 0x81150001, 0x039fa028, + 0xb0080001, 0xb4200001, 0x81a70001, 0x00000000, + 0x81df0004, 0x01bf23a8, 0xb5000002, 0x81a70000, + 0x01bf23a8, 0xb0170001, 0xb4200001, 0x81b50002, + 0x82970c20, 0x81df0000, 0x00000000, 0x00000000, + 0xb6350003, 0x81550002, 0x00000000, 0x029fa02a, + 0x81df0004, 0xb0130001, 0xb4200001, 0x81150001, + 0x81c70000, 0x81df0000, 0x00000000, 0x00000000, + 0xb6350014, 0x922e0c20, 0x015ff011, 0xb00a0000, + 0xb400000f, 0x922e0428, 0x015ff011, 0xb00a0001, + 0xb4200005, 0x922e044c, 0x0297b811, 0x015f03a6, + 0x029fa00a, 0xb5000006, 0x81550006, 0xad4a0003, + 0x922e044c, 0x0297b811, 0x914a0049, 0x029fa00a, + 0x91ce0004, 0x81df0004, 0xb0170001, 0xb4200022, + 0xb00d0000, 0xb4000020, 0x852d0001, 0x81470001, + 0x6549b80a, 0xad6a0003, 0x019f03a7, 0x058c03a6, + 0x81270000, 0xb00b0000, 0xb4000005, 0x300cb80b, + 0xb4800003, 0x058cb80b, 0x91290001, 0xb500fffb, + 0x81750004, 0x5961b80b, 0x839704ec, 0x0187b860, + 0x039fa02c, 0x039fa02a, 0x039fa029, 0x039fa02b, + 0xb0090000, 0xb4000007, 0x81df0000, 0x00000000, + 0x00000000, 0xb6290003, 0x81550007, 0x00000000, + 0x00000000, 0x81df0004, 0x81c70000, 0x81df0000, + 0x00000000, 0x00000000, 0xb635002e, 0x922e0c20, + 0x01fff011, 0xb00f0000, 0xb4000029, 0x852f0001, + 0x81470001, 0x6549b80a, 0xad6a0003, 0x922e044c, + 0x025fd811, 0x86520001, 0x0227b812, 0x81270000, + 0xb00b0000, 0xb4000005, 0x3012b80b, 0xb4800003, + 0x0652b80b, 0x91290001, 0xb500fffb, 0x2e09b80b, + 0x00000000, 0x3010b811, 0xb4600001, 0x91290001, + 0xae4e0004, 0x82150004, 0x9232049c, 0x0297b811, + 0x0187b860, 0x029fa02c, 0x029fa02a, 0x029fa029, + 0x029fa030, 0xb0090000, 0xb4000004, 0xb6290003, + 0x81550007, 0x00000000, 0x00000000, 0x82270460, + 0x1231b80e, 0x0217b811, 0x81550002, 0x021fa00a, + 0x91ce0004, 0x81df0004, 0xb0130001, 0xb420000c, + 0xb0080000, 0xb400000a, 0x81550004, 0x839704fc, + 0x0167b860, 0x039fa02b, 0x81670001, 0x039fa02b, + 0x8175000e, 0x81670002, 0x039fa02b, 0x039fa02a, + 0x81150001, 0xb0080001, 0xb420000a, 0x8135000b, + 0x5d2923aa, 0x95490180, 0x5d4723ab, 0x95490060, + 0x5d4523ac, 0x95490018, 0x5d4323ad, 0x95490007, + 0x015f23ae, 0x81350001, 0xb0090001, 0xb420001b, + 0x81350006, 0x013f23af, 0xb0170001, 0xb4200005, + 0x81550004, 0x00000000, 0x015f23b0, 0x81550003, + 0x015f23b1, 0x82970474, 0x83170488, 0x81df0000, + 0x00000000, 0x00000000, 0xb6350004, 0x81550007, + 0x5e83a02a, 0x954a0007, 0x031fa02a, 0x81df0004, + 0xb0130001, 0xb4200005, 0x81750004, 0x00000000, + 0x017f23b2, 0x81750003, 0x017f23b3, 0xb0170001, + 0xb420000b, 0x81b50001, 0xb00d0001, 0xb4200008, + 0x81d50003, 0x59c8b80e, 0x91ce0300, 0x01df61da, + 0x81d50003, 0x59c8b80e, 0x91ce0300, 0x01df61db, + 0x81550001, 0xb00a0001, 0xb4200057, 0xb0170001, + 0xb4200001, 0x81550002, 0x82470000, 0x82270000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6350004, + 0x81750002, 0x6571b80b, 0x92310002, 0x1a52b80b, + 0x81df0004, 0xb0170001, 0xb420001b, 0xb00a0001, + 0xb4200015, 0x81150003, 0x91080001, 0x011f23a4, + 0x829709d0, 0x831709f0, 0x83970060, 0x81df0000, + 0x00000000, 0x00000000, 0xb6280009, 0x81750005, + 0x00000000, 0x029fa02b, 0x81750004, 0x00000000, + 0x031fa02b, 0x81750003, 0x00000000, 0x039fa02b, + 0x81df0004, 0xb5000004, 0xb00a0002, 0xb4800002, + 0x81070000, 0x011f23a4, 0x82270000, 0x81270000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6350025, + 0x6a11b812, 0x92310002, 0x96100003, 0xb0100001, + 0xb4200018, 0xada90020, 0x81750003, 0x920d0520, + 0x0217b810, 0x920d05c0, 0x0297b810, 0x920d0660, + 0x0317b810, 0x5942b809, 0x920a050c, 0x0397b810, + 0x916b0001, 0x039fa02b, 0xb62b0009, 0x81750005, + 0x00000000, 0x021fa02b, 0x81750004, 0x00000000, + 0x029fa02b, 0x81750003, 0x00000000, 0x031fa02b, + 0xb5000007, 0xb0100002, 0xb4800005, 0x59a2b809, + 0x91ad050c, 0x0397b80d, 0x82070000, 0x039fa010, + 0x91290001, 0x81df0004, 0x81550001, 0xb00a0001, + 0xb420000a, 0x81550009, 0xb00a0000, 0xb4000007, + 0x81df0000, 0x00000000, 0x00000000, 0xb62a0003, + 0x82150008, 0x00000000, 0x00000000, 0x81df0004, + 0xb00a0100, 0xb4a0000b, 0x954aff00, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008003, 0x82150010, + 0x00000000, 0x00000000, 0x81df0004, 0x854a0100, + 0xb4e0fff6, 0x00ffb81b, 0x00000000, 0x00000000, + 0x81070000, 0x011f61dc, 0x011f61de, 0x011f61e0, + 0x011f03aa, 0x9108e0f4, 0x0138b808, 0x011f03ab, + 0x013f61ac, 0x9108e0f0, 0x0138b808, 0x011f03ac, + 0x013f61ad, 0x5901b808, 0x9108e0f8, 0x0139b808, + 0x011f03ad, 0x013f61ae, 0x5901b808, 0x9108e100, + 0x0139b808, 0x011f03ae, 0x013f61b0, 0x5901b808, + 0x9108e108, 0x0179b808, 0x013f03af, 0x017f61b1, + 0x02bf037b, 0x82970474, 0xb6350002, 0x015f8034, + 0x1929b80a, 0x011f03a1, 0xb0080001, 0xb4200002, + 0x015f03b0, 0x1929b80a, 0x019f0388, 0xb00c0001, + 0xb4200002, 0x015f03b2, 0x1929b80a, 0x013f61b3, + 0x015f03a8, 0xb00a0001, 0xb420003a, 0x81a70000, + 0x01bf237a, 0x83840056, 0x806f001f, 0x80af001f, + 0x80270300, 0x8067a800, 0x5c62b803, 0xb600080a, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01afb803, + 0x007f90bc, 0x0047b86f, 0xb0020001, 0xb4c0fffd, + 0x90210020, 0x90630020, 0x81a70001, 0x01bf237a, + 0x83840043, 0x838403ce, 0x81a70000, 0x01bf237a, + 0x82470400, 0x01bff012, 0x01bf23fa, 0x83840420, + 0x83840497, 0x83840546, 0x8384059d, 0x806f001f, + 0x80af001f, 0x80270300, 0x8067ac00, 0x5c62b803, + 0xb600080a, 0x00cfb801, 0x007fb0bc, 0x5862b803, + 0x01cfb803, 0x007f90bc, 0x0047b86f, 0xb0020001, + 0xb4c0fffd, 0x90210020, 0x90630020, 0x81a70001, + 0x01bf237a, 0x82470404, 0x015ff012, 0x015f23fa, + 0x83840407, 0x8384047e, 0x8384052d, 0x83840584, + 0xb5000011, 0x81a70000, 0x01bf237a, 0xb635000e, + 0x8384001b, 0x01bf037a, 0xad4d0004, 0x00000000, + 0x914a0400, 0x01bff00a, 0x01bf23fa, 0x838403f8, + 0x8384046f, 0x8384051e, 0x83840575, 0x01df037a, + 0x91ce0001, 0x01df237a, 0x019f0388, 0xb00c0001, + 0xb4200009, 0x02bf037b, 0x02bf237a, 0x838400e8, + 0x82470000, 0x025f23fa, 0x838403e9, 0x83840460, + 0x8384050f, 0x83840566, 0x00ffb81b, 0x00000000, + 0x80770000, 0x80f70000, 0x81770000, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x83f70000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x82d7ffff, 0x8357ffff, 0x83d7ffff, + 0x017f037a, 0x5a42b80b, 0x01bf03a8, 0xb00d0001, + 0xb4200004, 0x011f9118, 0x013f9119, 0x7929b808, + 0xb5000002, 0x91b20460, 0x013ff00d, 0x91b20340, + 0x0297b80d, 0x00000000, 0x029fa009, 0x01df0384, + 0xb00e0000, 0xb4200005, 0xb00b0001, 0xb4200003, + 0x009f90c6, 0x00bf0391, 0xb5000002, 0x009f90cf, + 0x00bf0389, 0x83a40142, 0x81870000, 0x019f61b5, + 0x019f61b4, 0x5a02b80b, 0x9190044c, 0x01dfd80c, + 0x01df61b6, 0x91900488, 0x01dff00c, 0x59c1b80e, + 0x918ee118, 0x01d9b80c, 0x019f03af, 0x01df61af, + 0x858c000f, 0x5986b80c, 0x91d00474, 0x01bff00e, + 0x59c2b80d, 0x11cc61b2, 0x81870000, 0x019f61b8, + 0x91900414, 0x01dfd80c, 0x01df61b7, 0xadab0010, + 0x00000000, 0x908d049c, 0x83a40191, 0xadcb0020, + 0x5982b80b, 0x908e0520, 0x90ae05c0, 0x90ce0660, + 0x928c050c, 0x00ff9814, 0x83a40169, 0x83a401b8, + 0x017f037a, 0x59c2b80b, 0x918e0428, 0x01fff00c, + 0xb00f0001, 0xb4200081, 0x023f03a5, 0x3011b80b, + 0xb420000f, 0x01c7b860, 0x01dfb0fa, 0x01df41dc, + 0x01df61e8, 0x01df41de, 0x01df61ea, 0x01df41e0, + 0x01df61ec, 0x01df41dd, 0x01df61e9, 0x01df41df, + 0x01df61eb, 0x01df41e1, 0x01df61ed, 0xb5000024, + 0x01c7b860, 0x01dfb0f9, 0x01df41dc, 0x01df61e2, + 0x01df41de, 0x01df61e4, 0x01df41e0, 0x01df61e6, + 0x01df41dd, 0x01df61e3, 0x01df41df, 0x01df61e5, + 0x01df41e1, 0x01df61e7, 0x803f0000, 0x00000000, + 0x00000000, 0x01df90fa, 0x003fb80e, 0x00000000, + 0x00000000, 0x81d50000, 0x00000000, 0x00000000, + 0x01df41e8, 0x01df61dc, 0x01df41ea, 0x01df61de, + 0x01df41ec, 0x01df61e0, 0x01df41e9, 0x01df61dd, + 0x01df41eb, 0x01df61df, 0x01df41ed, 0x01df61e1, + 0x029f03a6, 0x029f236a, 0x029f03a7, 0x029f236c, + 0x027f03a2, 0x92b3e128, 0x0298b815, 0x019f03b0, + 0x029f2368, 0x5982b80c, 0x01df03af, 0x85ce000f, + 0x59c6b80e, 0x11cc61b2, 0x82a70001, 0x02bf61b8, + 0x82a70000, 0x02bf61b9, 0x029f41da, 0x029f61ba, + 0x029f41db, 0x029f61bb, 0x019f03b1, 0x5981b80c, + 0x918ce118, 0x0299b80c, 0xad8b0048, 0x029f61af, + 0x59a2b813, 0x118cb80d, 0x928c0868, 0x029fb0fb, + 0x928c0700, 0x029fb0fc, 0x019f41bc, 0x918c0003, + 0x019f61bc, 0x5a02b80b, 0x91900414, 0x029fd80c, + 0x029f236e, 0x808704ec, 0x83a40121, 0x808709d0, + 0x80a709f0, 0x80c70060, 0x00ff03a4, 0x83a400fc, + 0x83a4014b, 0x021f037a, 0x019f03a5, 0x300cb810, + 0xb4000016, 0x803f0000, 0x00000000, 0x00000000, + 0x01df90f9, 0x003fb80e, 0x00000000, 0x00000000, + 0x81d50000, 0x00000000, 0x00000000, 0x01df41e2, + 0x01df61dc, 0x01df41e4, 0x01df61de, 0x01df41e6, + 0x01df61e0, 0x01df41e3, 0x01df61dd, 0x01df41e5, + 0x01df61df, 0x01df41e7, 0x01df61e1, 0x029f41b6, + 0xa6d40100, 0xaeb40004, 0x81870000, 0x92b50c00, + 0x0397b815, 0xb6360001, 0x039fa02c, 0x00ffb81c, + 0x009f90cf, 0x00bf0389, 0x019f037a, 0x5982b80c, + 0x918c0340, 0x0397b80c, 0x81870000, 0x039fa00c, + 0x83a40083, 0x81870000, 0x019f61b5, 0x019f61b4, + 0x81870007, 0x019f61b6, 0x019f03b3, 0x5981b80c, + 0x918ce118, 0x01b9b80c, 0x019f03af, 0x01bf61af, + 0x858c000f, 0x5986b80c, 0x01bf03b2, 0x59a2b80d, + 0x118cb80d, 0x019f61b2, 0x81870000, 0x019f61b7, + 0x019f61b8, 0x808704fc, 0x83a400d9, 0x80870000, + 0x80a70000, 0x80c70000, 0x80e70000, 0x83a400b4, + 0x83a40103, 0x81470000, 0x81e70c1c, 0x0397b80f, + 0xb600f901, 0x039fa02a, 0x00ffb81c, 0x00000000, + 0x82270000, 0x023f2011, 0x0227b860, 0x023fb0ff, + 0x02bf9006, 0x92350028, 0x8213001f, 0x9210e000, + 0x3011b810, 0xb4800001, 0x86312000, 0x021f4193, + 0x5a01b810, 0x86100028, 0x83a4fa36, 0x82270000, + 0x003fb811, 0x02bf9006, 0x5aa3b815, 0x82338000, + 0x1a31b815, 0x003fb811, 0x8067e950, 0x5c62b803, + 0x81f50000, 0x80270400, 0x81df0000, 0x00000000, + 0x00000000, 0xb6000409, 0x814fffc0, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01cfb803, 0x007f90bc, + 0xb520ffff, 0x90210020, 0x90630020, 0x81df0004, + 0x82870000, 0x81f50010, 0x019f4193, 0x5d61b80c, + 0x5d43b80c, 0x114ab80b, 0x0187b80a, 0x960cff00, + 0x92100100, 0x858c0001, 0x81df0000, 0x00000000, + 0x00000000, 0xb62c000c, 0x81f50010, 0x5e28b80f, + 0xb6000209, 0x5a48b814, 0x9652ff00, 0x5e68b814, + 0x5981b813, 0x918c1000, 0x01dfd80c, 0x2252b811, + 0x2292b80e, 0x962f00ff, 0x81df0004, 0x81870000, + 0x86100100, 0xb4e0ffec, 0xb00a0000, 0xb4000009, + 0x81670000, 0xb0140000, 0xb4000001, 0x81670001, + 0x017f2012, 0x258a4193, 0x918c0001, 0x81470000, + 0xb500ffde, 0x81670000, 0xb0140000, 0xb4000001, + 0x81670002, 0x116b0012, 0x803f0000, 0x00000000, + 0x00000000, 0x003fb811, 0x00000000, 0x00000000, + 0x81f50000, 0x017f2012, 0x00ffb81a, 0x00000000, + 0x61f4b804, 0x91ef0001, 0x8233003f, 0x9a31ffff, + 0x5a02b804, 0x1610b811, 0x92510001, 0x1a10b812, + 0x029f03fb, 0xb0140001, 0xb4200012, 0x5a21b805, + 0x92b1e910, 0x0299b815, 0x5a22b805, 0x5a90b814, + 0x6290b814, 0x92b1e890, 0x11efb814, 0x029bb815, + 0x8233ff80, 0x3011b814, 0xb4000006, 0x4294b811, + 0x00000000, 0x0288b814, 0x4210b814, 0x00000000, + 0x0208b810, 0x029f9003, 0x82f3007f, 0x9af7ffff, + 0x3017b814, 0xb4000003, 0x4210b814, 0x00000000, + 0x0208b810, 0x82270000, 0x02c7b810, 0xb0160000, + 0xb400000a, 0x1676b812, 0x3013b812, 0xb4000003, + 0x5ac1b816, 0x92310001, 0xb500fffa, 0x81d3ff80, + 0x3010b80e, 0xb4200001, 0x1ad6b80e, 0x05efb811, + 0x027f037a, 0x5a62b813, 0x92730340, 0x0397b813, + 0x023fd813, 0x02dfb0fd, 0x5a30b811, 0x6230b811, + 0x0631b80f, 0x3010b812, 0xb4200001, 0x92310001, + 0x82470000, 0xb0110000, 0xb4800004, 0x82470003, + 0xb0110003, 0xb4400001, 0x0247b811, 0x039fa012, + 0x124f61bc, 0x00ffb81d, 0x00000000, 0x00000000, + 0x83970a10, 0x82070000, 0xb6003201, 0x039fa030, + 0xb0070000, 0xb4000019, 0x029f41b4, 0x0297b804, + 0x0317b805, 0x0397b806, 0xb6270014, 0x12948034, + 0x01df8038, 0xb00e0000, 0xb4a0000e, 0x02bf803c, + 0x5a02b814, 0x91b00a10, 0x0217b80d, 0xb62e0008, + 0x96150003, 0x91f00001, 0xadef0080, 0xb0150004, + 0xb4600001, 0x85ef0280, 0x021fa02f, 0x92940001, + 0xb5000001, 0x021f803c, 0x00000000, 0x00ffb81d, + 0x0397b804, 0x021f036a, 0x027f803c, 0x029f803c, + 0x02bf803c, 0x02df803c, 0x5a22b810, 0x92311000, + 0x0397b811, 0xb0100000, 0xb4200001, 0x039fa036, + 0xb0150000, 0xb4000021, 0x0227b860, 0x023fb0ff, + 0xb520ffff, 0x803f0000, 0x82138000, 0x1a10b813, + 0x003fb810, 0x00000000, 0x00000000, 0x82150000, + 0x00000000, 0xb635000d, 0x82550007, 0x5a42b812, + 0x9212e4b8, 0x025bb810, 0x8227000c, 0xb6000307, + 0x68d1b812, 0x94c6000f, 0x84c60002, 0x12d6b806, + 0xb6340001, 0x039fa036, 0x86310004, 0x803f0000, + 0x82138000, 0x023f90ff, 0x1a31b810, 0x003fb811, + 0x00000000, 0x00000000, 0x82150000, 0x00ffb81d, + 0x00ff41b5, 0x011f41b4, 0x019f41af, 0x01bf41ae, + 0x01df41ba, 0x01ff41bb, 0x82070000, 0x023f0380, + 0x82470000, 0xae310032, 0x029f41b3, 0x5862b807, + 0x90431000, 0x81970ad8, 0x0217b802, 0x90430c00, + 0x0297b802, 0x0317b802, 0x912802a4, 0x007ff009, + 0x58478030, 0x792341b6, 0x0529b807, 0x019fa029, + 0xb0080014, 0xb4800011, 0xa5420c00, 0x031fa02a, + 0x84690001, 0xb4a00011, 0xb623000b, 0x58678030, + 0xa4030c00, 0x031fa020, 0x044ab800, 0x0056b802, + 0x5c41b802, 0xf84200ff, 0x90620100, 0x005ff003, + 0x7d40b80a, 0x114ab802, 0xb5000004, 0xa5420c00, + 0x58478010, 0xa5620c00, 0x031fa02a, 0xb0080016, + 0xb4400043, 0xb0080013, 0xb440002c, 0xb0080006, + 0xb4400024, 0xb0080005, 0xb4400014, 0xb0080002, + 0xb4400006, 0x80440030, 0x015f619c, 0x05cab80c, + 0x05eab80d, 0x066eb810, 0xb500003c, 0x8044002a, + 0x300a419c, 0xb4800001, 0x82470001, 0x015f619c, + 0xb0120001, 0xb4200001, 0xb500001a, 0x05cab80c, + 0x05eab80d, 0x066eb810, 0xb5000030, 0x001f41b6, + 0xb0000007, 0xb4000001, 0x8044001b, 0x300a419c, + 0xb4800001, 0x82470001, 0xb0120001, 0xb4200001, + 0xb500000c, 0x05cab80c, 0x05eab80d, 0x066eb810, + 0xb5000022, 0x80440010, 0x840b0100, 0x300ab800, + 0xb4200001, 0x86100040, 0xb5000002, 0x86100080, + 0xfe100000, 0x046e41ad, 0x042ab80c, 0x7dc1b803, + 0x044f41ac, 0x042ab80d, 0x7de1b802, 0x046eb810, + 0x7e6fb803, 0xb5000011, 0x840b0100, 0x3000b80a, + 0xb4200002, 0x82070180, 0x00ffb802, 0x300ab80b, + 0xb4a00002, 0x86100040, 0xfe100000, 0x00ffb802, + 0x046e41ad, 0x042ab80c, 0x7dc1b803, 0x044f41ac, + 0x042ab80d, 0x7de1b802, 0x7e6eb80f, 0x380a41b0, + 0xb4600003, 0x242a41b0, 0x5c22b801, 0x1273b801, + 0xb0140000, 0xb4200002, 0x80071fe0, 0xb5000016, + 0x1011b808, 0x5801b800, 0x9020e26c, 0x0079b801, + 0x5842b808, 0x90420a10, 0x7c03b813, 0x003f9802, + 0x1000b801, 0x003f41b2, 0x5830b801, 0x6030b801, + 0x0400b801, 0x003f41b1, 0x5830b801, 0x6030b801, + 0x0400b801, 0xfc000000, 0xf8001fe0, 0x94001fe0, + 0x100041b1, 0x9400ffff, 0x8067003f, 0xb6290008, + 0x005f8014, 0x0442b800, 0x9442ffff, 0x5850b802, + 0x6050b802, 0xfc420000, 0x5c45b802, 0x7a82a023, + 0x10e7b809, 0x91080001, 0x300741b6, 0xb420ff6a, + 0x019f61af, 0x01bf61ae, 0x01df61ba, 0x01ff61bb, + 0x00ff41b5, 0x011f41b4, 0x019f41b8, 0x01bf41b7, + 0x01df41dd, 0x01ff41df, 0x021f41e1, 0x027f90fd, + 0x029f41bc, 0x02ff41dc, 0x031f41de, 0x033f41e0, + 0x5822b807, 0x91210c00, 0x0117b809, 0x81970ad8, + 0x91211000, 0x0217b809, 0x91210c00, 0x0317b809, + 0x80170ba0, 0x013f802c, 0xb629005f, 0x003f8038, + 0xb001000e, 0xb440001e, 0xb001000c, 0xb4400054, + 0xb001000a, 0xb4400043, 0xb0010007, 0xb440003c, + 0xb0010005, 0xb440002b, 0xb0010000, 0xb440001a, + 0xb00d0001, 0xb4200010, 0x005f418f, 0xac42bb75, + 0x8073005a, 0x9442ffff, 0x005f618f, 0x95628000, + 0x5848b802, 0xb00b8000, 0xb4200002, 0x8173ff00, + 0x1842b80b, 0x9863827a, 0x4043b802, 0x00000000, + 0x0048b802, 0xb500003f, 0x80470000, 0xb500003d, + 0x8401000f, 0x5c22b800, 0x902102d8, 0x001ff001, + 0x004db800, 0xb5000037, 0x86f70001, 0xb4600005, + 0x80750005, 0x5862b803, 0x9043e44c, 0x01d9b802, + 0x82e70002, 0x5c4cb80e, 0x9462000f, 0x5862b803, + 0x90630200, 0x005f9803, 0x59c4b80e, 0x95ceffff, + 0xb5000028, 0x87180001, 0xb4600005, 0x80750007, + 0x5862b803, 0x9043e4b8, 0x01f9b802, 0x83070002, + 0x5c4cb80f, 0x9462000f, 0x5862b803, 0x9063020c, + 0x005f9803, 0x59e4b80f, 0x95efffff, 0xb5000019, + 0x80750003, 0x5862b803, 0x90630220, 0x005f9803, + 0xb5000014, 0x87390001, 0xb4600005, 0x80750007, + 0x5862b803, 0x9043e6ac, 0x0219b802, 0x83270001, + 0x5c4cb810, 0x9462000f, 0x5862b803, 0x9063023c, + 0x005f9803, 0x5a04b810, 0x9610ffff, 0xb5000005, + 0x80750004, 0x5862b803, 0x90630268, 0x005f9803, + 0x00000000, 0x001fa022, 0x80170ba0, 0xb00c0001, + 0xb4200035, 0x023f90fb, 0x007f9811, 0x025f90fc, + 0x06d4b803, 0x007f9812, 0x4083b813, 0x00000000, + 0x0088b804, 0xb629002b, 0x24368030, 0x9421ffff, + 0x5830b801, 0x6030b801, 0x40448020, 0xb0010020, + 0xb4800003, 0x80470000, 0x80670000, 0xb500000e, + 0xb0010000, 0xb4a00004, 0x82b30080, 0x6aa1b815, + 0x4042b815, 0xb5000008, 0x6c41b802, 0x82a70017, + 0x12b5b801, 0x6875b803, 0x1842b803, 0x00000000, + 0x00000000, 0x00000000, 0x0108a022, 0x007f41b9, + 0x90630001, 0x007f61b9, 0xb003000c, 0xb420000c, + 0x92310004, 0x023fb0fb, 0x007f9811, 0x92520004, + 0x06d4b803, 0x025fb0fc, 0x007f9812, 0x80470000, + 0x4083b813, 0x00000000, 0x0088b804, 0x005f61b9, + 0x00000000, 0xb500001a, 0xb6290019, 0x24348030, + 0x9421ffff, 0x5830b801, 0x6030b801, 0x40538020, + 0xb0010020, 0xb4800003, 0x80470000, 0x80670000, + 0xb500000e, 0xb0010000, 0xb4a00004, 0x82b30080, + 0x6aa1b815, 0x4042b815, 0xb5000008, 0x6c41b802, + 0x82a70017, 0x12b5b801, 0x6875b803, 0x1842b803, + 0x00000000, 0x00000000, 0x00000000, 0x0108a022, + 0x10e7b809, 0x91080001, 0x300741b6, 0xb420ff48, + 0x00ff61b5, 0x011f61b4, 0x01df61dd, 0x01ff61df, + 0x021f61e1, 0x02ff61dc, 0x031f61de, 0x033f61e0, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x81d7ffff, + 0x8257ffff, 0x808f0000, 0x003f9113, 0x005f9114, + 0x7141b802, 0x80cf0700, 0x8027b064, 0x5c22b801, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x80cf0704, 0x8027b06c, 0x5c22b801, + 0x003fb0bc, 0x5822b801, 0x01cfb801, 0x003f90bc, + 0xb520ffff, 0x81e7043c, 0x82071c00, 0x82271c10, + 0x019f03a9, 0x806f001f, 0x80af001f, 0x80270400, + 0x8067a800, 0x5c62b803, 0xb6000808, 0x00cfb801, + 0x007fb0bc, 0x5862b803, 0x01cfb803, 0x007f90bc, + 0xb520ffff, 0x90210020, 0x90630020, 0x81971000, + 0x82170c00, 0xb6000004, 0x003f800c, 0x005f8010, + 0x021fa021, 0x019fa022, 0x00bfd810, 0x003fd811, + 0x70c1b80a, 0x001f980f, 0x91ef0004, 0x92100002, + 0x92310002, 0x5822b805, 0x90411000, 0x0197b802, + 0x90410c00, 0x0217b802, 0x0466b805, 0xb0000000, + 0xb4000005, 0xb6230004, 0x003f8010, 0x005f800c, + 0x1201a022, 0x0581a022, 0x858c0001, 0xb4e0ffea, + 0x80270400, 0x8067ac00, 0x5c62b803, 0xb6000808, + 0x00cfb801, 0x007fb0bc, 0x5862b803, 0x01afb803, + 0x007f90bc, 0xb520ffff, 0x90210020, 0x90630020, + 0x00ffb81c, 0x00000000, 0x00000000, 0x00000000, + 0x808f0000, 0x806f001f, 0x80af001f, 0x003f037a, + 0xb0010000, 0xb4400030, 0x81a7b7fc, 0x5da2b80d, + 0x80670500, 0xb6000208, 0x00cfb803, 0x01bfb0bc, + 0x59a2b80d, 0x01cfb80d, 0x01bf90bc, 0xb520ffff, + 0x90630020, 0x91ad0020, 0x81c7b8fc, 0x5dc2b80e, + 0x80670540, 0xb6000208, 0x00cfb803, 0x01dfb0bc, + 0x59c2b80e, 0x01cfb80e, 0x01df90bc, 0xb520ffff, + 0x90630020, 0x91ce0020, 0x81a7b3fc, 0x5da2b80d, + 0x80670600, 0xb6000408, 0x00cfb803, 0x01bfb0bc, + 0x59a2b80d, 0x01cfb80d, 0x01bf90bc, 0xb520ffff, + 0x90630020, 0x91ad0020, 0x81c7b5fc, 0x5dc2b80e, + 0x80670680, 0xb6000408, 0x00cfb803, 0x01dfb0bc, + 0x59c2b80e, 0x01cfb80e, 0x01df90bc, 0xb520ffff, + 0x90630020, 0x91ce0020, 0x005f03fa, 0xb0020000, + 0xb4000024, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x8257ffff, 0x82d7ffff, 0x8357ffff, + 0x83d7ffff, 0x83971300, 0x83171200, 0x82971100, + 0x82171000, 0x81170c00, 0x81970ff8, 0x80171400, + 0x80971500, 0x005f802c, 0x001f8028, 0xb6004010, + 0x41028000, 0x51008004, 0x007f876c, 0x0208a028, + 0x41008000, 0x49028004, 0x003f8068, 0x0388a028, + 0x41038000, 0x51018004, 0x005f802c, 0x0288a028, + 0x41018020, 0x49038024, 0x001f8028, 0x0308a028, + 0x00ffb81c, 0x83d7ffff, 0x8357ffff, 0x82d7ffff, + 0x8257ffff, 0x8157ffff, 0x81d7ffff, 0x8057ffff, + 0x80d7ffff, 0x82971200, 0x82171000, 0x81170c00, + 0x81970ffc, 0x83171800, 0x83971a00, 0x83370000, + 0x83b70000, 0x81370008, 0x81b7fff8, 0x4119880c, + 0xb6008006, 0x511d8808, 0x41498838, 0x0208a028, + 0x494d883c, 0x4119880c, 0x0288a02a, 0x00ffb81c, + 0x82670000, 0x82a70000, 0x003f037a, 0xb0010000, + 0xb4400018, 0x81a7bdfc, 0x5da2b80d, 0x80670580, + 0xb6000208, 0x00cfb803, 0x01bfb0bc, 0x59a2b80d, + 0x01cfb80d, 0x01bf90bc, 0xb520ffff, 0x90630020, + 0x91ad0020, 0x81a7eb70, 0x5da2b80d, 0x806705c0, + 0xb6000208, 0x00cfb803, 0x01bfb0bc, 0x59a2b80d, + 0x01cfb80d, 0x01bf90bc, 0xb520ffff, 0x90630020, + 0x91ad0020, 0x02bf03fa, 0x808f0000, 0xb0150000, + 0xb4000006, 0x81470040, 0x81670003, 0x81870002, + 0x81a71000, 0x81c71300, 0xb5000005, 0x81470080, + 0x81670004, 0x81870001, 0x81a71000, 0x81c71200, + 0x0017b80d, 0x0097b80e, 0x108db80a, 0x0117b804, + 0x108eb80a, 0x0197b804, 0x5841b80a, 0x108db802, + 0x0217b804, 0x108eb802, 0x0297b804, 0x106ab802, + 0x108db803, 0x0317b804, 0x108eb803, 0x0397b804, + 0x5ea2b80a, 0xb6350020, 0x001f8000, 0x003f8008, + 0x005f8004, 0x007f800c, 0x10c08010, 0x10a18018, + 0x10828014, 0x10e3801c, 0x1246b805, 0x0686b805, + 0x10c4b807, 0x0484b807, 0x80e70000, 0x80a70000, + 0x0008a032, 0x0108a034, 0x0088a026, 0x0188a024, + 0x04c08010, 0x04a18018, 0x04828014, 0x04e3801c, + 0x0646b807, 0x1286b807, 0x10c4b805, 0x0484b805, + 0x80e70000, 0x80a70000, 0x0208a032, 0x0308a034, + 0x0288a026, 0x0388a024, 0x5de1b80a, 0x82070004, + 0xb62b002a, 0x0017b80d, 0x0097b80e, 0x102db80f, + 0x0117b801, 0x104eb80f, 0x0197b802, 0x82171600, + 0x82971700, 0x0037b80f, 0x00b7b80f, 0x0137b80f, + 0x01b7b80f, 0xb630001b, 0x003f8030, 0x005f8034, + 0x5ee2b80f, 0x8013007f, 0x9800ffff, 0xb6370011, + 0x41008000, 0x51018008, 0x4902800c, 0x40c08000, + 0x0008a028, 0x48c18008, 0x50c2800c, 0x42808004, + 0x00c8b806, 0x52828008, 0x5281800c, 0x41008004, + 0x0088a034, 0x49028008, 0x4901800c, 0x011fa026, + 0x0188a028, 0x001f8001, 0x001f8005, 0x001f8009, + 0x001f800d, 0x5de1b80f, 0x5a01b810, 0x0017b80d, + 0x0097b80e, 0x902d0004, 0x0117b801, 0x904e0004, + 0x0197b802, 0x82171600, 0x82971700, 0x5ea1b80a, + 0x8013007f, 0x9800ffff, 0xb6350013, 0x003f8030, + 0x005f8034, 0x42408000, 0x52418008, 0x4a42800c, + 0x41008000, 0x0008a052, 0x49018008, 0x5102800c, + 0x42808004, 0x0108b808, 0x52828008, 0x5281800c, + 0x40c08004, 0x0088a054, 0x48c28008, 0x48c1800c, + 0x011fa048, 0x0188a046, 0x81a71100, 0x81c71200, + 0x858c0001, 0xb4e0ff7e, 0x00ffb81c, 0x00000000, + 0x005f03fa, 0x00000000, 0xb0020000, 0xb4000034, + 0x81b70080, 0x81d7ffff, 0x81f70001, 0x82370080, + 0x8257ffff, 0x82770001, 0x82b70080, 0x82d7ffff, + 0x82f70001, 0x83370080, 0x8357ffff, 0x83770001, + 0x81971000, 0x82171100, 0x82971200, 0x83171300, + 0x815703fc, 0x81370200, 0x81170c00, 0x83d703fc, + 0x83b70200, 0x83970f00, 0x8057ffff, 0x80d7ffff, + 0x80171400, 0x80971500, 0x001f800d, 0x003f8019, + 0xb6004012, 0x41008000, 0x51018004, 0x007f8011, + 0x0128a008, 0x41018000, 0x49008004, 0x009f8015, + 0x03a8a008, 0x41038000, 0x51048004, 0x001f800d, + 0x03a8a008, 0x41048020, 0x49038024, 0x003f8019, + 0x0128a008, 0x005f8028, 0x005f803c, 0x81f70000, + 0x82770000, 0x82f70000, 0x83770000, 0x00ffb81c, + 0x82370040, 0x8257ffff, 0x82770001, 0x82b70040, + 0x82d7ffff, 0x82f70001, 0x82171000, 0x82971200, + 0x8157ffff, 0x81170c00, 0x81d7ffff, 0x81970e00, + 0x8057ffff, 0x80d7ffff, 0x80171800, 0x80971a00, + 0xb600800a, 0x001f8011, 0x003f8015, 0x41008000, + 0x51018004, 0x00000000, 0x0108a028, 0x41018020, + 0x49008024, 0x00000000, 0x0188a028, 0x82770000, + 0x82f70000, 0x00ffb81c, 0x00000000, 0x00000000, + 0x8057ffff, 0x80d7ffff, 0x8157ffff, 0x808f0000, + 0x015f0384, 0x017f037a, 0xac4a0006, 0x8027b004, + 0x1042b80b, 0x5841b802, 0x1021b802, 0x0159b801, + 0x013f0325, 0x01bf0320, 0x5822b80b, 0x90210340, + 0x00ff9801, 0x8027b2e8, 0x5842b807, 0x1021b802, + 0x025bb801, 0x80070000, 0xac4d0006, 0x8027b004, + 0x1042b800, 0x5841b802, 0x1021b802, 0x0199b801, + 0x00000000, 0xac4c0006, 0x8027b078, 0x1042b80a, + 0x5842b802, 0x1021b802, 0x011bb801, 0x00000000, + 0x40d2b808, 0x00000000, 0xb0060000, 0xb4000080, + 0x005f033b, 0x80278400, 0xac600080, 0x5c22b801, + 0x10a1b803, 0xb0020000, 0xb4200002, 0x80279000, + 0xb5000001, 0x80279c00, 0x5c22b801, 0x11e1b803, + 0x80470300, 0x5822b800, 0x1042b801, 0x003f9802, + 0x806f001f, 0x80af001f, 0xb0010000, 0xb4200024, + 0x80170c00, 0x80971000, 0x003f8020, 0xb6000003, + 0x4201b806, 0x003f8020, 0x0088a030, 0x80270400, + 0xb6000208, 0x00cfb801, 0x00bfb0bc, 0x58a2b805, + 0x01afb805, 0x00bf90bc, 0xb520ffff, 0x90210020, + 0x90a50020, 0xb6000408, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x90210020, 0x91ef0020, 0xb6000208, 0x00cfb801, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x90210020, 0x90a50020, 0xb5000043, + 0x80270400, 0x0087b805, 0x01c7b80f, 0xb6000208, + 0x00cfb801, 0x009fb0bc, 0x5882b804, 0x01cfb804, + 0x009f90bc, 0xb520ffff, 0x90210020, 0x90840020, + 0xb6000408, 0x00cfb801, 0x01dfb0bc, 0x59c2b80e, + 0x01cfb80e, 0x01df90bc, 0xb520ffff, 0x90210020, + 0x91ce0020, 0xb6000208, 0x00cfb801, 0x009fb0bc, + 0x5882b804, 0x01cfb804, 0x009f90bc, 0xb520ffff, + 0x90210020, 0x90840020, 0x80170c00, 0x80971000, + 0x8053007f, 0x9842ffff, 0xb6000004, 0x42028004, + 0x4a068020, 0x00000000, 0x0088a030, 0x80270400, + 0xb6000208, 0x00cfb801, 0x00bfb0bc, 0x58a2b805, + 0x01afb805, 0x00bf90bc, 0xb520ffff, 0x90210020, + 0x90a50020, 0xb6000408, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01afb80f, 0x01ff90bc, 0xb520ffff, + 0x90210020, 0x91ef0020, 0xb6000208, 0x00cfb801, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x90210020, 0x90a50020, 0x5822b800, + 0x90210300, 0x0117b801, 0x80470001, 0x011fa002, + 0x90000001, 0x3000b809, 0xb480ff6b, 0x00ffb81c, + 0x8057ffff, 0x013f0325, 0x015f033b, 0x80171000, + 0x80070000, 0xb6002001, 0x001fa020, 0xb00a0001, + 0xb4c00002, 0x81679000, 0xb5000001, 0x81679c00, + 0x5d62b80b, 0x81878400, 0x5d82b80c, 0x80070000, + 0x5822b800, 0x90410300, 0x003f9802, 0x00000000, + 0xb0010000, 0xb4200019, 0xac400080, 0x00000000, + 0x10ccb802, 0x10abb802, 0x806f001f, 0x80af001f, + 0x80cf0400, 0xb6000408, 0xb520ffff, 0x00dfb0bc, + 0x58c2b806, 0x01afb806, 0x00df90bc, 0xb520ffff, + 0x80cf0400, 0x90c60020, 0x80cf0400, 0xb6000407, + 0x00bfb0bc, 0x58a2b805, 0x01afb805, 0x00bf90bc, + 0xb520ffff, 0x80cf0400, 0x90a50020, 0x90000001, + 0x3000b809, 0xb480ffde, 0x00ffb81b, 0x8057ffff, + 0x013f0325, 0x80171000, 0x80070000, 0xb6002001, + 0x001fa020, 0x81878400, 0x5d82b80c, 0x80070000, + 0x5822b800, 0x90410300, 0x003f9802, 0x00000000, + 0xb0010000, 0xb420000f, 0xac400080, 0x00000000, + 0x10ccb802, 0x806f001f, 0x80af001f, 0x80cf0400, + 0xb6000408, 0xb520ffff, 0x00dfb0bc, 0x58c2b806, + 0x01afb806, 0x00df90bc, 0xb520ffff, 0x80cf0400, + 0x90c60020, 0x90000001, 0x3000b809, 0xb480ffe8, + 0x00ffb81b, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x8139b000, 0x00000000, 0xb0090000, 0xb4000012, + 0x806f001f, 0x80af001f, 0x80cf0400, 0x013fb0bc, + 0x5922b809, 0x01cfb809, 0x013f90bc, 0xb520ffff, + 0x806f0003, 0x80af0003, 0x80cf0420, 0x91290020, + 0x013fb0bc, 0x5922b809, 0x01cfb809, 0x013f90bc, + 0xb520ffff, 0xb5000233, 0x80270000, 0x80171000, + 0xb6002401, 0x001fa021, 0x007f0384, 0x009f0320, + 0x00bf0385, 0x00df0386, 0x80e7b36c, 0x5821b803, + 0x1021b807, 0x0159b801, 0x5821b804, 0x1021b807, + 0x0179b801, 0x80e7b37c, 0x5821b803, 0x1021b807, + 0x0199b801, 0x5821b804, 0x1021b807, 0x01b9b801, + 0x80e7b38c, 0x5821b803, 0x1021b807, 0x01d9b801, + 0x5821b804, 0x1021b807, 0x01f9b801, 0x005f0385, + 0x8027b39c, 0x5842b802, 0x1021b802, 0x021bb801, + 0x005f0386, 0x8027b3ac, 0x5842b802, 0x1021b802, + 0x023bb801, 0x027f0383, 0x003f0328, 0x005f4195, + 0xb0130007, 0xb42000df, 0xb0010000, 0xb42000dd, + 0xb0020000, 0xb40000db, 0xb0030002, 0xb48000d9, + 0x029bb802, 0x82a7b108, 0xb00b0001, 0xb4200001, + 0xb5000005, 0xb00b0002, 0xb4200002, 0x92b500a0, + 0xb5000001, 0x92b50140, 0xb0030004, 0xb4600002, + 0x82870000, 0xb5000006, 0xb0030006, 0xb4600004, + 0xb0140001, 0xb4a00002, 0x82870001, 0xb5000000, + 0xac54000a, 0x806f0009, 0x80af0009, 0x5c22b815, + 0x80cf0440, 0x1021b802, 0x003fb0bc, 0x5822b801, + 0x01cfb801, 0x003f90bc, 0xb520ffff, 0xb0030003, + 0xb400000f, 0xb0030004, 0xb400001d, 0xb0030005, + 0xb400002b, 0xb0030006, 0xb4000042, 0xb0030007, + 0xb4000059, 0x80171000, 0x005f9440, 0x001fa002, + 0x80171038, 0x005f9440, 0x001fa002, 0xb5000073, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171004, + 0x005f9443, 0x001fa002, 0x8017101c, 0x005f9446, + 0x001fa002, 0x80171034, 0x005f9449, 0x001fa002, + 0x80171038, 0x005f9440, 0x001fa002, 0xb5000063, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171008, + 0x005f9441, 0x001fa002, 0x80171020, 0x005f9444, + 0x001fa002, 0x80171034, 0x005f9440, 0x001fa002, + 0x80171038, 0x005f9447, 0x001fa002, 0xb5000053, + 0x80171000, 0x005f9440, 0x001fa002, 0x80171004, + 0x005f9443, 0x001fa002, 0x8017100c, 0x005f9441, + 0x001fa002, 0x8017101c, 0x005f9446, 0x001fa002, + 0x80171024, 0x005f9444, 0x001fa002, 0x80171034, + 0x005f9449, 0x001fa002, 0x80171038, 0x005f9440, + 0x001fa002, 0x8017103c, 0x005f9447, 0x001fa002, + 0xb500003a, 0x80171000, 0x005f9440, 0x001fa002, + 0x80171008, 0x005f9441, 0x001fa002, 0x8017100c, + 0x005f9442, 0x001fa002, 0x80171020, 0x005f9444, + 0x001fa002, 0x80171024, 0x005f9445, 0x001fa002, + 0x80171034, 0x005f9440, 0x001fa002, 0x80171038, + 0x005f9447, 0x001fa002, 0x8017103c, 0x005f9448, + 0x001fa002, 0xb5000021, 0x80171000, 0x005f9440, + 0x001fa002, 0x80171004, 0x005f9443, 0x001fa002, + 0x8017100c, 0x005f9441, 0x001fa002, 0x80171010, + 0x005f9442, 0x001fa002, 0x8017101c, 0x005f9446, + 0x001fa002, 0x80171024, 0x005f9444, 0x001fa002, + 0x80171028, 0x005f9445, 0x001fa002, 0x80171034, + 0x005f9449, 0x001fa002, 0x80171038, 0x005f9440, + 0x001fa002, 0x8017103c, 0x005f9447, 0x001fa002, + 0x80171040, 0x005f9448, 0x001fa002, 0x80270001, + 0x803eff90, 0x80171000, 0x82b30020, 0x9ab50000, + 0x40158020, 0xb6000501, 0x48158020, 0x82b30020, + 0x9ab50000, 0x80470000, 0x3015b800, 0xb4600006, + 0x80171000, 0x83840226, 0xb6000603, 0x40028000, + 0x00000000, 0x0008a020, 0x80171018, 0x82b30020, + 0x9ab50000, 0x40158020, 0xb6000501, 0x48158020, + 0x82b30020, 0x9ab50000, 0x80470000, 0x3015b800, + 0xb4600006, 0x80171018, 0x83840215, 0xb6000603, + 0x40028000, 0x00000000, 0x0008a020, 0x80171030, + 0x82b30020, 0x9ab50000, 0x40158020, 0xb6000501, + 0x48158020, 0x82b30020, 0x9ab50000, 0x80470000, + 0x3015b800, 0xb4600006, 0x80171030, 0x83840204, + 0xb6000603, 0x40028000, 0x00000000, 0x0008a020, + 0xb500011e, 0x80270000, 0x803eff90, 0xb0030000, + 0xb4200067, 0x025f0322, 0xb00b0001, 0xb4200016, + 0xb0120001, 0xb4200005, 0x80171018, 0x8033007f, + 0x9821ffff, 0x001fa001, 0xb5000110, 0xb0120002, + 0xb4200005, 0x80171020, 0x8033007f, 0x9821ffff, + 0x001fa001, 0xb5000109, 0x80171018, 0x80330040, + 0x98210000, 0x001fa001, 0x80171020, 0x00000000, + 0x001fa001, 0xb5000101, 0xb00b0002, 0xb420002c, + 0xb0120000, 0xb4200008, 0x80171000, 0x8033007f, + 0x9821ffff, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000f5, 0xb0120001, 0xb4200008, + 0x80171000, 0x8033005a, 0x98218279, 0x001fa001, + 0x80171030, 0x00000000, 0x001fa001, 0xb50000eb, + 0xb0120002, 0xb4200008, 0x80171008, 0x8033005a, + 0x98218279, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000e1, 0x80171000, 0x80330040, + 0x98210000, 0x001fa001, 0x80171008, 0x00000000, + 0x001fa001, 0x8017100c, 0x00000000, 0x001fa001, + 0x80171038, 0x00000000, 0x001fa001, 0xb50000d3, + 0xb0120000, 0xb4200008, 0x80171000, 0x8033007f, + 0x9821ffff, 0x001fa001, 0x80171038, 0x00000000, + 0x001fa001, 0xb50000c9, 0xb0120001, 0xb4200005, + 0x80171018, 0x8033007f, 0x9821ffff, 0x001fa001, + 0xb50000c2, 0xb0120002, 0xb4200005, 0x80171020, + 0x8033007f, 0x9821ffff, 0x001fa001, 0xb50000bb, + 0x80171018, 0x80330040, 0x98210000, 0x001fa001, + 0x80171020, 0x00000000, 0x001fa001, 0xb50000b3, + 0x80070000, 0x8033007f, 0x9821ffff, 0xb600050e, + 0x144eb80f, 0xb0028000, 0xb4c00008, 0xac400006, + 0x00000000, 0x1042b800, 0x5842b802, 0x90421000, + 0x0017b802, 0x00000000, 0x001fa001, 0x90000001, + 0x59c1b80e, 0x59e1b80f, 0xb0040000, 0xb4200023, + 0xb00a0002, 0xb4000007, 0x80171004, 0x8033005a, + 0x98218279, 0x001fa001, 0x80171034, 0x00000000, + 0x001fa001, 0xb00c0002, 0xb4000009, 0x8017100c, + 0x8033ffa5, 0x98217d87, 0x001fa001, 0x8017103c, + 0x8033005a, 0x98218279, 0x001fa001, 0xb500008b, + 0x8017100c, 0x8033ffa5, 0x98217d87, 0x001fa001, + 0x80171010, 0x00000000, 0x001fa001, 0x8017103c, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171040, + 0x00000000, 0x001fa001, 0xb500007c, 0xb0040001, + 0xb420002a, 0xb00a0001, 0xb4000007, 0x80171018, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171020, + 0x00000000, 0x001fa001, 0xb00a0003, 0xb420000a, + 0x8053005a, 0x98428279, 0x4030b802, 0x8017101c, + 0x5821b801, 0x00000000, 0x00000000, 0x00000000, + 0x0028b801, 0x001fa001, 0xb00c0001, 0xb4200007, + 0x8053005a, 0x98428279, 0x4031b802, 0x80171024, + 0x0028b801, 0x001fa001, 0xb500005c, 0xb00c0002, + 0xb420005a, 0x8053005a, 0x98428279, 0x4031b802, + 0x80171024, 0x0028b801, 0x001fa001, 0x80171028, + 0x00000000, 0x001fa001, 0xb5000050, 0xb00b0002, + 0xb4200012, 0xb00a0001, 0xb4200008, 0x80171004, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171034, + 0x00000000, 0x001fa001, 0xb5000008, 0xb00a0003, + 0xb4200006, 0x80171004, 0x00000000, 0x001fa010, + 0x80171034, 0x00000000, 0x001fa010, 0xb00c0001, + 0xb4200025, 0x027f0383, 0x003f0328, 0xb0130007, + 0xb420000b, 0xb00b0003, 0xb4200009, 0xb0010000, + 0xb4200007, 0x80171024, 0x00000000, 0x001fa011, + 0x80171054, 0x80270000, 0x001fa001, 0xb500002b, + 0xb00d0000, 0xb420000a, 0x8033005a, 0x98218279, + 0x4041b811, 0x8017100c, 0x0048b802, 0x001fa002, + 0x8017103c, 0x00000000, 0x001fa002, 0xb500001f, + 0xb00d0002, 0xb420001d, 0x80171054, 0x8033005a, + 0x98218279, 0x001fa001, 0x8017106c, 0x00000000, + 0x001fa001, 0xb5000015, 0xb00c0002, 0xb4200013, + 0xb00d0000, 0xb4200007, 0x8017100c, 0x00000000, + 0x001fa011, 0x80171040, 0x00000000, 0x001fa011, + 0xb500000a, 0xb00d0001, 0xb4200008, 0x80171054, + 0x8033005a, 0x98218279, 0x001fa001, 0x80171058, + 0x00000000, 0x001fa001, 0xb5000000, 0x029f0388, + 0x02bf0321, 0xb0140000, 0xb4000006, 0xb0150000, + 0xb4000004, 0x8017108c, 0x8033007f, 0x9821ffff, + 0x001fa001, 0x8027b078, 0x5c22b801, 0x806f001f, + 0x80af001f, 0x80cf0400, 0x003fb0bc, 0x5822b801, + 0x01afb801, 0x003f90bc, 0xb520ffff, 0x90210020, + 0x806f0003, 0x80af0003, 0x80cf0420, 0x003fb0bc, + 0x5822b801, 0x01afb801, 0x003f90bc, 0xb520ffff, + 0x81270000, 0x8033007f, 0x9821ffff, 0x80171000, + 0xb600060a, 0x80470000, 0xb6000603, 0x015f8020, + 0x0156b80a, 0x1042b80a, 0x3002b801, 0xb4a00001, + 0x81270001, 0x00000000, 0x00000000, 0x015f0323, + 0x00000000, 0xb00a0000, 0xb4200002, 0x81670000, + 0xb5000001, 0x81670001, 0x017f23fb, 0x01ff41ee, + 0x59f0b80f, 0x61f0b80f, 0x021f41ef, 0x5a10b810, + 0x6210b810, 0xb00a0003, 0xb420003b, 0x017f039f, + 0x019f41c5, 0x5990b80c, 0x6190b80c, 0xb00b0000, + 0xb400000c, 0xb00c0000, 0xb4000005, 0xac4c0100, + 0x8033001d, 0x98215500, 0x12c1b802, 0xb500000f, + 0xac4f0100, 0x8033001d, 0x98215500, 0x12c1b802, + 0xb500000a, 0xb0090000, 0xb4000005, 0xac4f0100, + 0x8033ffe2, 0x9821ab00, 0x12c1b802, 0xb5000003, + 0xac4f0100, 0x00000000, 0x02c7b802, 0xb0030000, + 0xb420007e, 0x01bf03a0, 0x01df41c9, 0x59d0b80e, + 0x61d0b80e, 0xb00d0000, 0xb400000c, 0xb00e0000, + 0xb4000005, 0xac4e0100, 0x8033001d, 0x98215500, + 0x12e1b802, 0xb5000071, 0xac500100, 0x8033001d, + 0x98215500, 0x12e1b802, 0xb500006c, 0xb0090000, + 0xb4000005, 0xac500100, 0x8033ffe2, 0x9821ab00, + 0x12e1b802, 0xb5000065, 0xac500100, 0x00000000, + 0x02e7b802, 0xb5000061, 0xb00a0002, 0xb420002f, + 0x023f9002, 0x025f9001, 0xb00f0000, 0xb4a00007, + 0xac4f0100, 0x00000000, 0x4022b811, 0x00000000, + 0x0028b801, 0x02c7b801, 0xb500000c, 0xb0090000, + 0xb4000004, 0xac4f0100, 0x00000000, 0x02c7b802, + 0xb5000006, 0xac4f0100, 0x00000000, 0x4022b812, + 0x00000000, 0x0028b801, 0x02c7b801, 0xb0030000, + 0xb4200046, 0xb0100000, 0xb4a00007, 0xac500100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02e7b801, 0xb500003d, 0xb0090000, 0xb4000004, + 0xac500100, 0x00000000, 0x02e7b802, 0xb5000037, + 0xac500100, 0x00000000, 0x4022b812, 0x00000000, + 0x0028b801, 0x02e7b801, 0xb5000030, 0x023f9002, + 0x025f9001, 0xb00f0000, 0xb4a00007, 0xac4f0100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02c7b801, 0xb5000006, 0xac4f0100, 0x00000000, + 0x4022b812, 0x00000000, 0x0028b801, 0x02c7b801, + 0xb0090000, 0xb4000005, 0x0047b816, 0x8033ffe2, + 0x9821ab00, 0x1042b801, 0x02c7b802, 0xb0030000, + 0xb4200016, 0xb0100000, 0xb4a00007, 0xac500100, + 0x00000000, 0x4022b811, 0x00000000, 0x0028b801, + 0x02e7b801, 0xb5000006, 0xac500100, 0x00000000, + 0x4022b812, 0x00000000, 0x0028b801, 0x02e7b801, + 0xb0090000, 0xb4000005, 0x0047b817, 0x8033ffe2, + 0x9821ab00, 0x1042b801, 0x02e7b802, 0x00000000, + 0x00000000, 0x02c8b816, 0x02dfb0cf, 0xb0030000, + 0xb4200002, 0x02e8b817, 0x02ffb0c6, 0x00ffb81b, + 0xb6001807, 0x5841b802, 0x3015b800, 0xb4800002, + 0x06b5b800, 0x98420001, 0x5aa1b815, 0x00000000, + 0x00ffb81c, 0x00000000, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000015, 0x815bb3f0, 0x81070000, 0x812707f8, + 0xb00a0000, 0xb4000006, 0x81070800, 0x81270ff8, + 0xb00a0001, 0xb4000002, 0x81071000, 0x812717f8, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000f, 0x3001b809, + 0xb4a00031, 0xb500000c, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81070000, 0xb5000007, 0xb0040001, + 0xb4200002, 0x81070800, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81071000, 0xb0040000, 0xb4200001, + 0x8384020c, 0x80af001f, 0x808f0000, 0x806f0000, + 0x80670400, 0x5d22b808, 0x81df0000, 0x00000000, + 0x00000000, 0xb600100a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x801bb3f8, 0x80270001, 0xb0000001, + 0xb4000002, 0x802600a0, 0x803eb3f8, 0x914a0001, + 0xb00a0002, 0xb4a00001, 0x81470000, 0x815eb3f0, + 0x80270001, 0x003f2013, 0x00ffb81b, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009c, 0x96b48000, 0xb0158000, + 0xb4000195, 0x96b40100, 0xb0150100, 0xb40001ab, + 0x96b40400, 0xb0150400, 0xb40001ac, 0x96b40001, + 0xb0150001, 0xb400000c, 0x96b40008, 0xb0150008, + 0xb400019e, 0x96b44000, 0xb0154000, 0xb40001ab, + 0x96b40002, 0xb0150002, 0xb4000162, 0x00000000, + 0x00000000, 0xb50001bd, 0x02bf9017, 0x92b50001, + 0x02bfb017, 0x82850082, 0x5efdb814, 0x96f70001, + 0xb0170001, 0xb420000b, 0x83050069, 0x9718003f, + 0x82e50064, 0x12f7b818, 0x86f70109, 0x82feff74, + 0x02e7b86f, 0x9af74000, 0x01ffb817, 0x96f7bfff, + 0x01ffb817, 0x83050081, 0x82a5009a, 0x96b50001, + 0xb0150001, 0xb4200014, 0x82a70000, 0x02bfb017, + 0x96b41840, 0xb0150800, 0xb420000c, 0x96b40008, + 0x5aa9b815, 0x96d46000, 0x5ec3b816, 0x82f3000f, + 0x9af7c00f, 0x1718b817, 0x1ab5b818, 0x1ab5b816, + 0x9ab50340, 0x82a60081, 0xb5000132, 0x9b180180, + 0x83060081, 0xb500012f, 0x82a5009a, 0x96b50002, + 0xb0150002, 0xb420001b, 0x82a70000, 0x02bfb017, + 0x96b41800, 0xb0151800, 0xb4000013, 0x96b40040, + 0xb0150040, 0xb4200004, 0xa3180c00, 0x9b180340, + 0x83060081, 0xb500011f, 0x96b40008, 0x5aa9b815, + 0x96d46000, 0x5ec3b816, 0x82f3000f, 0x9af7c00f, + 0x1718b817, 0x1ab5b818, 0x1ab5b816, 0x9ab50340, + 0x82a60081, 0xb5000113, 0x9b180180, 0x83060081, + 0xb5000110, 0x82a500c1, 0x96b5000f, 0xb015000b, + 0xb420000e, 0x96b40020, 0xb0150020, 0xb400000b, + 0x96b40200, 0xb0150200, 0xb4000008, 0x82c50086, + 0x82e50094, 0x3016b817, 0xb4400004, 0x06f7b816, + 0xb017ff00, 0xb4400001, 0xb50000fe, 0x96b46000, + 0xb0156000, 0xb4000011, 0x96b41820, 0xb0150820, + 0xb4200004, 0x9b391000, 0x82a5009a, 0x96b5feff, + 0x82a6009a, 0x96b40040, 0xb0150040, 0xb4200001, + 0x9739efff, 0x96b91000, 0xb0151000, 0xb4200003, + 0x82a5009a, 0x9ab50100, 0x82a6009a, 0x96b40040, + 0xb0150040, 0xb4200019, 0x96b41800, 0xb0151800, + 0xb4200006, 0x96b98000, 0xb0158000, 0xb4200003, + 0x9b180180, 0x83060081, 0xb50000de, 0x96d80c00, + 0x82b300ff, 0x9ab5f3ff, 0x1718b815, 0xb0160c00, + 0xb4000007, 0x82e50098, 0x96f70400, 0xb0170400, + 0xb4200002, 0x82c70c00, 0xb5000001, 0xa2d60c00, + 0x1b18b816, 0x9b180340, 0xb50000c4, 0x96b40220, + 0xb0150000, 0xb4e00028, 0x82a5009d, 0x82f3ffff, + 0x16b5b817, 0x82f3000e, 0x3015b817, 0xb4200022, + 0x96f98000, 0xb0178000, 0xb400001f, 0x82a70000, + 0x02bfb017, 0x82c50081, 0x9ab60020, 0x82a60081, + 0x82a50086, 0x92b50bb8, 0x82a60094, 0x82c60081, + 0x82c5009d, 0x96d6ffff, 0x82b30032, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b30022, 0x9ab58001, 0x1ab5b816, 0x82c5009a, + 0x96d60020, 0xb0160020, 0xb4200002, 0x82b30032, + 0x9ab58001, 0x82a6009d, 0x02ff9017, 0x00000000, + 0xb0170040, 0xb4800000, 0x5eb5b814, 0x96b500f0, + 0x96f46000, 0x5eedb817, 0x1ab5b817, 0xb0170003, + 0xb4000004, 0x96b500ef, 0x96f70001, 0x5ae4b817, + 0x1ab5b817, 0x96d41800, 0xb0161800, 0xb400000a, + 0x96f900ff, 0x96b500ff, 0x9739ff00, 0x1b39b815, + 0x02a7b817, 0x96b500f3, 0x96d40008, 0x5ec1b816, + 0x1ab5b816, 0xb500000c, 0x96f98000, 0xb0178000, + 0xb4200007, 0x5efeb814, 0x96f70001, 0xb0170001, + 0xb4000003, 0x9b180180, 0x83060081, 0xb5000081, + 0x96b500f3, 0x9ab50008, 0x9739fff3, 0x96d40020, + 0xb0160020, 0xb4200017, 0x9b398000, 0x82c70000, + 0x02dfb017, 0x96d40010, 0x5ac8b816, 0x82f300ff, + 0x9af7cfff, 0x1718b817, 0x1b18b816, 0x9b180340, + 0x82c5009d, 0x96d6ffff, 0x82f3000e, 0x9af78001, + 0x1af7b816, 0x82c5009a, 0x96d60020, 0xb0160020, + 0xb4200002, 0x82f30032, 0x9af78001, 0x82e6009d, + 0xb500005a, 0x97397fff, 0x96b500ff, 0x5aaab815, + 0x82f300fc, 0x9af703ff, 0x1718b817, 0x1b18b815, + 0x9b180340, 0x82c5009a, 0x96d60010, 0xb0160010, + 0xb4200024, 0x82c70000, 0x02dfb017, 0x82c50086, + 0x92d60bb8, 0x82c60086, 0x82c50094, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4200002, 0x82e70bb8, + 0xb5000001, 0x82e70bb8, 0x12d6b817, 0x82e50081, + 0x9af70020, 0x82e60081, 0x82c60094, 0xa2f70020, + 0x82e60081, 0x82f30001, 0x16f7b818, 0x5ef0b817, + 0xb0170001, 0xb4000004, 0x96f84000, 0x5ee4b817, + 0x9718f3ff, 0x1b18b817, 0x82f3000a, 0x9af78000, + 0x82e6009d, 0x83060081, 0x83070001, 0x8306009f, + 0xb5000096, 0x82c5009d, 0x82f3000e, 0x9af78001, + 0x3016b817, 0xb420000f, 0x82b30032, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b30022, 0x9ab58001, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b30032, 0x9ab58001, + 0x82a6009d, 0x82c5009a, 0x96d60080, 0xb0160080, + 0xb4000011, 0x02df9017, 0x00000000, 0xb0160010, + 0xb480000d, 0x82c500c1, 0x96d6000f, 0xb016000b, + 0xb4000009, 0x82c50087, 0x96d60080, 0x5ac7b816, + 0x96f84000, 0x3017b816, 0xb4200003, 0x033f400f, + 0x9b394000, 0xb500000b, 0x9739bfff, 0x82e50061, + 0x96f70008, 0xb0170008, 0xb4000005, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4000001, 0x9718ffff, + 0x83060081, 0x83070001, 0x8306009f, 0x00000000, + 0xb500005e, 0x82850083, 0x96b400ff, 0xb015003c, + 0xb4200019, 0x96b92000, 0xb0152000, 0xb4000002, + 0x9b392000, 0xb5000014, 0x9739d3ff, 0x82870000, + 0x82860087, 0x82870008, 0x82860083, 0x829bff78, + 0x82a7001f, 0xb0140400, 0xb4000001, 0x82a70010, + 0x82a600c9, 0x829bff78, 0x00000000, 0x828600cb, + 0x8285009d, 0x82b3ffff, 0x9ab5fffd, 0x1694b815, + 0x8286009d, 0xb5000000, 0x83070002, 0x8306009f, + 0x00000000, 0xb500003d, 0x96b90800, 0xb0150800, + 0xb4200009, 0x9739f7ff, 0x82a703fd, 0x82a600cb, + 0x82a7003c, 0x82a60083, 0x8285009d, 0x9a940002, + 0x8286009d, 0xb5000004, 0x82850087, 0x5a82b814, + 0xa2940200, 0x82860087, 0xb5000000, 0x83078000, + 0x8306009f, 0x00000000, 0xb5000028, 0x83070008, + 0x8306009f, 0x00000000, 0xb5000024, 0x83070100, + 0x8306009f, 0x00000000, 0xb5000020, 0x83070000, + 0x83050081, 0x9b180180, 0x83060081, 0x83070400, + 0x8306009f, 0x00000000, 0xb5000018, 0x82870000, + 0x82850082, 0x5eb7b814, 0x96b500fc, 0x96d40006, + 0x5ec1b816, 0x1ab5b816, 0x5aacb815, 0x83050081, + 0x82d3001c, 0x9ad600ff, 0x1718b816, 0x1b18b815, + 0x9b180e00, 0x83060081, 0x83074000, 0x8306009f, + 0x8305009d, 0x82d300ff, 0x9ad6bfff, 0x1718b816, + 0x8306009d, 0x00000000, 0xb5000000, 0x029f9005, + 0x01ffb814, 0x033f600f, 0x029f900a, 0x02bf900b, + 0x02df900c, 0x02ff900d, 0x031f900e, 0x033f900f, + 0x00ffb81e, 0x02ff9010, 0x92f70b43, 0x02ffb010, + 0x02ff90cb, 0x82bbffdc, 0x829bffd8, 0x93150004, + 0x3014b815, 0xb400000f, 0x02dbb818, 0x029bb815, + 0x3017b816, 0xb480000b, 0x5a81b814, 0x029fb010, + 0x82860095, 0x8293001f, 0x9294fe00, 0x92b50008, + 0x3015b814, 0xb4800002, 0x82b3001f, 0x92b5fa00, + 0x82beffdc, 0x029f9010, 0x83250094, 0x06d4b819, + 0x02d6b816, 0xb016ffff, 0xb4a0000a, 0x8293000e, + 0x9a948001, 0x82c5009d, 0x96d6ffff, 0x1a94b816, + 0x82c5009a, 0x96d60010, 0xb0160010, 0xb4000001, + 0x8286009d, 0x00ffb81c, 0x82870001, 0x829ef500, + 0x82850086, 0x83250094, 0x06d4b819, 0x02d6b816, + 0xb016ffff, 0xb4a0000b, 0x82870001, 0x829ef504, + 0x82c50081, 0x9ab60020, 0x82a60081, 0x82a50086, + 0x92b50bbb, 0x82a60094, 0x82c60081, 0x86b505df, + 0x82a6009b, 0x00ffb81c, 0x82070028, 0x023f9006, + 0x83a4ef48, 0x80070000, 0x001fb011, 0x001f204f, + 0x003fb800, 0x001f9006, 0x5803b800, 0x80338000, + 0x1800b801, 0x003fb800, 0x005f4193, 0x5c41b802, + 0x80350000, 0x00000000, 0x0027b860, 0x80150010, + 0x5810b800, 0x80750010, 0x1863b800, 0x8087ffff, + 0x80a7770b, 0x80c70000, 0x1403b804, 0x3000b805, + 0xb4000008, 0x5888b804, 0x58a8b805, 0x90c60001, + 0xb0060003, 0xb4a0fff8, 0x84420001, 0xb4e0ffee, + 0xb5000027, 0xb0060003, 0xb4200007, 0x80150010, + 0x5810b800, 0x81150010, 0x950800ff, 0xb0080077, + 0xb4000001, 0xb500fff4, 0x001f400e, 0x98000010, + 0x98004000, 0x9400fffe, 0x001f600e, 0x80e71fe0, + 0x001f4000, 0x94000080, 0xb0000080, 0xb4200001, + 0x80e77580, 0x00ffb008, 0x80e70020, 0xb0060000, + 0xb400000e, 0x58e3b806, 0x90210020, 0x81070000, + 0x5938b803, 0x1908b809, 0x9523ff00, 0x5928b809, + 0x1908b809, 0x5d28b803, 0x9529ff00, 0x1908b809, + 0x5d38b803, 0x1908b809, 0x011fb011, 0x00ff204f, + 0x80137fff, 0x9800ffe7, 0x1421b800, 0x5c23b801, + 0x001f9006, 0x0441b800, 0x3001b800, 0xb4600002, + 0x0440b801, 0xa4422000, 0x007f90cb, 0x1063b802, + 0x007fb0cb, 0x003fb006, 0x803effec, 0x80470001, + 0x005f2013, 0xb500eba6, 0x001f400e, 0x9400000f, + 0xb0000000, 0xb4200001, 0x00ffb81f, 0xb0000001, + 0xb4000005, 0xb0000003, 0xb4000003, 0xb0000002, + 0xb4000001, 0x00ffb81f, 0x80070001, 0x001f2013, + 0xb500eb97, 0x00000000, 0x00000000, 0x00000000, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x803bff68, 0x8078ff6c, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x803bff68, + 0x8078ff6c, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x83840126, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e7ef98, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x80270180, 0x81e7ee90, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801bef90, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x8018ef94, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x819eff68, 0x817cff6c, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801bef90, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x8018ef94, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801bef90, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x8018ef94, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e7ec70, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270240, + 0x81e7ed70, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e7ee90, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x806f0007, + 0x80af0007, 0x80270280, 0x81e7ee70, 0x5de2b80f, + 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, + 0x01ff90bc, 0xb520ffff, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x015f400e, 0x944a4000, 0xb0024000, 0xb420001e, + 0x954abfff, 0x015f600e, 0x820f001f, 0x802f001f, + 0x81470000, 0x015f23f9, 0x015fb0ba, 0x8057ffff, + 0x80770000, 0x82970400, 0x82d7ffff, 0x82f70000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6000702, + 0xb6000001, 0x029fa02a, 0x81df0004, 0x80275480, + 0x005fb801, 0x8033001f, 0x9821c000, 0x803effe0, + 0x90212000, 0x803effe4, 0x80d9ff80, 0x00df6001, + 0x81477608, 0x015fb008, 0x003f0324, 0xb0010000, + 0xb420007e, 0x8344ebde, 0xb0180000, 0xb4000004, + 0x011f400e, 0x1908b818, 0x011f600e, 0x00ffb81f, + 0x8344f1d7, 0xb00b0000, 0xb4000006, 0x023f400e, + 0x9a310002, 0x023f600e, 0x82270000, 0x023f2012, + 0x00ffb81f, 0x8364ed6a, 0x82270000, 0x023f2011, + 0x80070000, 0x80170800, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002002, 0xb6003001, 0x001fa020, + 0x81df0004, 0x82270000, 0x003fb811, 0x02bf9006, + 0x5aa3b815, 0x82338000, 0x1a31b815, 0x003fb811, + 0x8067e950, 0x5c62b803, 0x81f50000, 0x019f4193, + 0x0267b80c, 0xadcc0010, 0x80170800, 0x80130000, + 0x9800f872, 0x001fa020, 0x80134e1f, 0x98000001, + 0x001fa020, 0x59d0b80e, 0x81150010, 0x1908b80e, + 0x001fa028, 0x858c0001, 0x5e01b80c, 0x5e25b810, + 0x81df0000, 0x00000000, 0x00000000, 0xb6310006, + 0xb6002005, 0x81150010, 0x5910b808, 0x00000000, + 0x81350010, 0x1808a029, 0x9630001f, 0xb0110000, + 0xb4000006, 0xb6310005, 0x81150010, 0x5910b808, + 0x00000000, 0x81350010, 0x1808a029, 0x81df0004, + 0x962c0001, 0xb0110000, 0xb4000003, 0x81150010, + 0x5910b808, 0x001fa028, 0x019f9006, 0x958cffff, + 0x00df4193, 0x58c1b806, 0x118cb806, 0xb00ce000, + 0xb4800002, 0x858ce000, 0x918cc000, 0x8153001f, + 0x118cb80a, 0x819effec, 0x019fb006, 0x015f4193, + 0x5941b80a, 0x019f90cb, 0x118cb80a, 0x019fb0cb, + 0x019f90ba, 0x918c0001, 0x019fb0ba, 0xb00c0002, + 0xb4200016, 0x019f400e, 0x940c8000, 0xb0008000, + 0xb4200012, 0x958c7fff, 0x019f600e, 0x80070000, + 0x800600a0, 0x80073da1, 0x800600a1, 0x801bff60, + 0x00000000, 0x801eff60, 0x00000000, 0x801bff60, + 0x00000000, 0x801eff60, 0x80130001, 0x98003da1, + 0x800600a1, 0x80070001, 0x800600a0, 0x003f0324, + 0x90210001, 0xb0010005, 0xb4a00001, 0x80270000, + 0x003f2324, 0x00ffb81f, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815bb3f0, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x81271800, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00032, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200001, + 0x8384fbf4, 0x80af001f, 0x808f0002, 0x806f0000, + 0x807bbf34, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600080a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290060, + 0x81df0004, 0x808f0000, 0x813bb3f8, 0x80270001, + 0xb0090001, 0xb4000002, 0x802600a0, 0x803eb3f8, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813eb3f0, 0xb0030800, 0xb4800001, 0x80670200, + 0x807ebf34, 0x80270001, 0x003f2013, 0x00ffb81b, +}; + +static u32 AC3I2SUcode1f8000[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00020000, 0xffff0005, 0xffffffff, + 0x00050001, 0xffffffff, 0xffffffff, 0x00020000, + 0xffff0005, 0xffffffff, 0x00010000, 0x00050002, + 0xffffffff, 0x00020000, 0x00050003, 0xffffffff, + 0x00010000, 0x00030002, 0xffff0005, 0x00020000, + 0x00040003, 0xffff0005, 0x00010000, 0x00030002, + 0x00050004, 0x0019000d, 0x003d0025, 0x00250019, + 0x00fd003d, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x007fffff, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x007fffff, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00599999, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00599999, + 0x007fffff, 0x00599999, 0x00000000, 0x00599999, + 0x00000000, 0x00000000, 0x00000000, 0x00599999, + 0x00000000, 0x00599999, 0x007fffff, 0x00000000, + 0x00599999, 0x00599999, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00599999, 0x00599999, + 0x007fffff, 0x007fffff, 0x00000000, 0x00599999, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00599999, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x007fffff, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x007fffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x007fffff, 0x00000000, + 0x007fffff, 0x00000000, 0x007fffff, 0x00400000, + 0x00200000, 0x00100000, 0x00080000, 0x00040000, + 0x00020000, 0x00010000, 0x00008000, 0x00004000, + 0x00002000, 0x00001000, 0x00000800, 0x00000400, + 0x00000200, 0x00000100, 0x00000080, 0x00000040, + 0x00000020, 0x00000010, 0x00000008, 0x00000004, + 0x00000002, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010002, + 0x00030002, 0x00030002, 0x00030002, 0x00000000, + 0x00000000, 0x00010001, 0x00020002, 0x4000a000, + 0xe000a000, 0xf000b000, 0xf800b800, 0x005a8279, + 0x004c1bf8, 0x00400000, 0x004c1bf8, 0x005a8279, + 0x00400000, 0x00000000, 0x00400000, 0x03020100, + 0x00000000, 0x00000080, 0x00000020, 0x00000008, + 0x00000000, 0x00000001, 0x00010001, 0x10001000, + 0x10001004, 0x10041004, 0x10041004, 0x10041004, + 0x00000000, 0x00000000, 0x00000000, 0xff80000a, + 0xff80031f, 0xff800b24, 0xff801818, 0xff8029fa, + 0xff8040c9, 0xff805c86, 0xff807d2e, 0xff80a2c1, + 0xff80cd3c, 0xff80fc9f, 0xff8130e8, 0xff816a14, + 0xff81a821, 0xff81eb0e, 0xff8232d6, 0xff827f79, + 0xff82d0f2, 0xff83273e, 0xff83825b, 0xff83e244, + 0xff8446f7, 0xff84b06e, 0xff851ea6, 0xff85919b, + 0xff860949, 0xff8685aa, 0xff8706ba, 0xff878c74, + 0xff8816d3, 0xff88a5d1, 0xff89396a, 0xff89d196, + 0xff8a6e51, 0xff8b0f94, 0xff8bb55a, 0xff8c5f9b, + 0xff8d0e51, 0xff8dc176, 0xff8e7902, 0xff8f34ef, + 0xff8ff535, 0xff90b9cc, 0xff9182ae, 0xff924fd3, + 0xff932132, 0xff93f6c3, 0xff94d07f, 0xff95ae5d, + 0xff969054, 0xff97765b, 0xff98606a, 0xff994e78, + 0xff9a407c, 0xff9b366b, 0xff9c303e, 0xff9d2de9, + 0xff9e2f64, 0xff9f34a4, 0xffa03da0, 0xffa14a4c, + 0xffa25aa0, 0xffa36e8f, 0xffa48610, 0xffa5a118, + 0xffa6bf9c, 0xffa7e191, 0xffa906ec, 0xffaa2fa0, + 0xffab5ba4, 0xffac8aeb, 0xffadbd6a, 0xffaef315, + 0xffb02bdf, 0xffb167be, 0xffb2a6a4, 0xffb3e886, + 0xffb52d56, 0xffb67509, 0xffb7bf92, 0xffb90ce4, + 0xffba5cf2, 0xffbbafb0, 0xffbd050f, 0xffbe5d04, + 0xffbfb780, 0xffc11477, 0xffc273db, 0xffc3d59f, + 0xffc539b4, 0xffc6a00d, 0xffc8089d, 0xffc97355, + 0xffcae027, 0xffcc4f05, 0xffcdbfe2, 0xffcf32af, + 0xffd0a75d, 0xffd21ddf, 0xffd39625, 0xffd51022, + 0xffd68bc7, 0xffd80904, 0xffd987cd, 0xffdb0810, + 0xffdc89c1, 0xffde0cd0, 0xffdf912d, 0xffe116cb, + 0xffe29d9a, 0xffe4258b, 0xffe5ae8f, 0xffe73896, + 0xffe8c392, 0xffea4f74, 0xffebdc2b, 0xffed69aa, + 0xffeef7df, 0xfff086bd, 0xfff21634, 0xfff3a634, + 0xfff536ad, 0xfff6c792, 0xfff858d1, 0xfff9ea5b, + 0xfffb7c22, 0xfffd0e16, 0xfffea026, 0xffffcdbc, + 0xfffe3ba0, 0xfffca995, 0xfffb17ac, 0xfff985f3, + 0xfff7f479, 0xfff6634f, 0xfff4d284, 0xfff34228, + 0xfff1b249, 0xfff022f7, 0xffee9442, 0xffed0638, + 0xffeb78ea, 0xffe9ec67, 0xffe860bd, 0xffe6d5fd, + 0xffe54c35, 0xffe3c374, 0xffe23bcb, 0xffe0b547, + 0xffdf2ff7, 0xffddabec, 0xffdc2933, 0xffdaa7dd, + 0xffd927f6, 0xffd7a98f, 0xffd62cb7, 0xffd4b17b, + 0xffd337ea, 0xffd1c013, 0xffd04a05, 0xffced5ce, + 0xffcd637c, 0xffcbf31d, 0xffca84c1, 0xffc91874, + 0xffc7ae45, 0xffc64641, 0xffc4e078, 0xffc37cf6, + 0xffc21bc9, 0xffc0bcff, 0xffbf60a5, 0xffbe06c9, + 0xffbcaf79, 0xffbb5ac0, 0xffba08ae, 0xffb8b94d, + 0xffb76cac, 0xffb622d8, 0xffb4dbdc, 0xffb397c6, + 0xffb256a2, 0xffb1187d, 0xffafdd62, 0xffaea55f, + 0xffad707e, 0xffac3ecc, 0xffab1054, 0xffa9e523, + 0xffa8bd44, 0xffa798c2, 0xffa677a8, 0xffa55a02, + 0xffa43fdb, 0xffa3293d, 0xffa21634, 0xffa106c9, + 0xff9ffb08, 0xff9ef2fa, 0xff9deeab, 0xff9cee23, + 0xff9bf16c, 0xff9af892, 0xff9a039c, 0xff991295, + 0xff982586, 0xff973c78, 0xff965774, 0xff957683, + 0xff9499ad, 0xff93c0fb, 0xff92ec75, 0xff921c24, + 0xff91500f, 0xff90883f, 0xff8fc4bb, 0xff8f058b, + 0xff8e4ab6, 0xff8d9443, 0xff8ce239, 0xff8c349f, + 0xff8b8b7d, 0xff8ae6d7, 0xff8a46b5, 0xff89ab1e, + 0xff891416, 0xff8881a3, 0xff87f3cc, 0xff876a96, + 0xff86e606, 0xff866621, 0xff85eaed, 0xff85746d, + 0xff8502a6, 0xff84959e, 0xff842d57, 0xff83c9d7, + 0xff836b20, 0xff831138, 0xff82bc20, 0xff826bdc, + 0xff822070, 0xff81d9de, 0xff819829, 0xff815b54, + 0xff812360, 0xff80f051, 0xff80c228, 0xff8098e6, + 0xff80748e, 0xff805521, 0xff803a9f, 0xff80250b, + 0xff801464, 0xff8008ad, 0xff8001e4, 0xff800027, + 0xff800c7e, 0xff802c8f, 0xff806056, 0xff80a7cb, + 0xff8102e4, 0xff817191, 0xff81f3c3, 0xff828964, + 0xff83325f, 0xff83ee98, 0xff84bdf3, 0xff85a04f, + 0xff86958b, 0xff879d7f, 0xff88b804, 0xff89e4ee, + 0xff8b240e, 0xff8c7533, 0xff8dd82a, 0xff8f4cbb, + 0xff90d2ad, 0xff9269c4, 0xff9411c1, 0xff95ca62, + 0xff979365, 0xff996c81, 0xff9b5570, 0xff9d4de4, + 0xff9f5590, 0xffa16c24, 0xffa3914e, 0xffa5c4b8, + 0xffa8060d, 0xffaa54f3, 0xffacb10e, 0xffaf1a03, + 0xffb18f70, 0xffb410f7, 0xffb69e33, 0xffb936c0, + 0xffbbda37, 0xffbe8830, 0xffc14042, 0xffc40201, + 0xffc6cd00, 0xffc9a0d2, 0xffcc7d05, 0xffcf612b, + 0xffd24ccf, 0xffd53f80, 0xffd838c8, 0xffdb3833, + 0xffde3d49, 0xffe14795, 0xffe4569d, 0xffe769e9, + 0xffea80ff, 0xffed9b67, 0xfff0b8a4, 0xfff3d83c, + 0xfff6f9b5, 0xfffa1c91, 0xfffd4056, 0xffff9b78, + 0xfffc7756, 0xfff953c0, 0xfff63130, 0xfff31025, + 0xffeff117, 0xffecd484, 0xffe9bae5, 0xffe6a4b6, + 0xffe39270, 0xffe0848b, 0xffdd7b82, 0xffda77cb, + 0xffd779de, 0xffd48231, 0xffd19138, 0xffcea769, + 0xffcbc535, 0xffc8eb10, 0xffc61969, 0xffc350af, + 0xffc09151, 0xffbddbbb, 0xffbb3059, 0xffb88f92, + 0xffb5f9d0, 0xffb36f78, 0xffb0f0ef, 0xffae7e96, + 0xffac18cf, 0xffa9bff9, 0xffa7746f, 0xffa5368c, + 0xffa306aa, 0xffa0e51e, 0xff9ed23c, 0xff9cce56, + 0xff9ad9bc, 0xff98f4bc, 0xff971f9f, 0xff955aae, + 0xff93a62f, 0xff920266, 0xff906f92, 0xff8eedf3, + 0xff8d7dc4, 0xff8c1f3c, 0xff8ad294, 0xff8997fd, + 0xff886fa8, 0xff8759c3, 0xff865679, 0xff8565f2, + 0xff848852, 0xff83bdbd, 0xff830651, 0xff82622b, + 0xff81d163, 0xff815411, 0xff80ea47, 0xff809416, + 0xff80518b, 0xff8022b1, 0xff80078e, 0x00000475, + 0x000007fe, 0x00000c02, 0x000010a3, 0x000015f5, + 0x00001c08, 0x000022ed, 0x00002ab5, 0x00003371, + 0x00003d32, 0x0000480a, 0x0000540d, 0x0000614b, + 0x00006fda, 0x00007fcd, 0x00009138, 0x0000a431, + 0x0000b8cc, 0x0000cf1f, 0x0000e741, 0x00010148, + 0x00011d4b, 0x00013b61, 0x00015ba2, 0x00017e25, + 0x0001a302, 0x0001ca51, 0x0001f42c, 0x000220a9, + 0x00024fe2, 0x000281f0, 0x0002b6ea, 0x0002eee9, + 0x00032a07, 0x0003685a, 0x0003a9fc, 0x0003ef04, + 0x0004378a, 0x000483a5, 0x0004d36d, 0x000526f7, + 0x00057e5b, 0x0005d9ae, 0x00063904, 0x00069c74, + 0x00070410, 0x00076feb, 0x0007e01a, 0x000854ac, + 0x0008cdb3, 0x00094b40, 0x0009cd61, 0x000a5425, + 0x000adf98, 0x000b6fc8, 0x000c04bf, 0x000c9e87, + 0x000d3d2a, 0x000de0ae, 0x000e891a, 0x000f3674, + 0x000fe8c0, 0x00109fff, 0x00115c34, 0x00121d5d, + 0x0012e37b, 0x0013ae89, 0x00147e84, 0x00155366, + 0x00162d27, 0x00170bbf, 0x0017ef23, 0x0018d748, + 0x0019c421, 0x001ab59f, 0x001babb2, 0x001ca648, + 0x001da54f, 0x001ea8b0, 0x001fb058, 0x0020bc2d, + 0x0021cc18, 0x0022dffd, 0x0023f7c2, 0x00251348, + 0x00263272, 0x00275520, 0x00287b31, 0x0029a482, + 0x002ad0f1, 0x002c0059, 0x002d3294, 0x002e677c, + 0x002f9ee8, 0x0030d8b1, 0x003214ac, 0x003352b0, + 0x00349290, 0x0035d422, 0x00371738, 0x00385ba5, + 0x0039a13b, 0x003ae7cc, 0x003c2f2a, 0x003d7725, + 0x003ebf8d, 0x00400834, 0x004150e9, 0x0042997d, + 0x0043e1c0, 0x00452981, 0x00467092, 0x0047b6c3, + 0x0048fbe3, 0x004a3fc6, 0x004b823b, 0x004cc316, + 0x004e0228, 0x004f3f45, 0x00507a40, 0x0051b2ef, + 0x0052e925, 0x00541cba, 0x00554d85, 0x00567b5e, + 0x0057a61d, 0x0058cd9e, 0x0059f1bb, 0x005b1252, + 0x005c2f3f, 0x005d4863, 0x005e5d9d, 0x005f6ed0, + 0x00607bde, 0x006184ad, 0x00628923, 0x00638927, + 0x006484a3, 0x00657b81, 0x00666daf, 0x00675b19, + 0x006843b1, 0x00692767, 0x006a062d, 0x006adff9, + 0x006bb4c2, 0x006c847d, 0x006d4f27, 0x006e14b8, + 0x006ed52f, 0x006f9089, 0x007046c6, 0x0070f7e9, + 0x0071a3f3, 0x00724aea, 0x0072ecd3, 0x007389b6, + 0x0074219d, 0x0074b490, 0x0075429b, 0x0075cbcc, + 0x00765031, 0x0076cfd8, 0x00774ad3, 0x0077c132, + 0x00783308, 0x0078a068, 0x00790968, 0x00796e1c, + 0x0079ce9a, 0x007a2af9, 0x007a8350, 0x007ad7b8, + 0x007b2849, 0x007b751d, 0x007bbe4c, 0x007c03f1, + 0x007c4625, 0x007c8504, 0x007cc0a8, 0x007cf92c, + 0x007d2eaa, 0x007d613e, 0x007d9101, 0x007dbe10, + 0x007de883, 0x007e1076, 0x007e3603, 0x007e5943, + 0x007e7a4f, 0x007e9942, 0x007eb633, 0x007ed13a, + 0x007eea6f, 0x007f01ea, 0x007f17c0, 0x007f2c08, + 0x007f3ed7, 0x007f5043, 0x007f605e, 0x007f6f3c, + 0x007f7cf1, 0x007f898e, 0x007f9525, 0x007f9fc6, + 0x007fa982, 0x007fb268, 0x007fba86, 0x007fc1eb, + 0x007fc8a4, 0x007fcebe, 0x007fd443, 0x007fd941, + 0x007fddc2, 0x007fe1cf, 0x007fe572, 0x007fe8b4, + 0x007feb9e, 0x007fee36, 0x007ff086, 0x007ff293, + 0x007ff463, 0x007ff5fd, 0x007ff765, 0x007ff8a1, + 0x007ff9b6, 0x007ffaa7, 0x007ffb79, 0x007ffc2f, + 0x007ffccb, 0x007ffd52, 0x007ffdc6, 0x007ffe28, + 0x007ffe7b, 0x007ffec2, 0x007ffefd, 0x007fff2f, + 0x007fff58, 0x007fff7b, 0x007fff97, 0x007fffae, + 0x007fffc0, 0x007fffcf, 0x007fffdb, 0x007fffe4, + 0x007fffec, 0x007ffff1, 0x007ffff6, 0x007ffff9, + 0x007ffffb, 0x007ffffd, 0x007ffffe, 0x007fffff, + 0x007fffff, 0x007fffff, 0x007fffff, 0xff800000, + 0x00000000, 0xffa57d86, 0x005a827a, 0xff89be51, + 0x0030fbc5, 0xffcf043b, 0x007641af, 0xff8275a1, + 0x0018f8b8, 0xffb8e313, 0x006a6d99, 0xff959267, + 0x00471ced, 0xffe70748, 0x007d8a5f, 0xff809dc9, + 0x000c8bd3, 0xffaecc33, 0x0062f202, 0xff8f1d34, + 0x003c56ba, 0xffdad7f4, 0x007a7d05, 0xff8582fb, + 0x0025280c, 0xffc3a946, 0x0070e2cc, 0xff9d0dfe, + 0x005133cd, 0xfff3742d, 0x007f6237, 0xff802778, + 0x000647d9, 0xffaa0a5b, 0x005ed77d, 0xff8c4a14, + 0x0036ba20, 0xffd4e0cb, 0x00788484, 0xff83d604, + 0x001f19f9, 0xffbe31e2, 0x006dca0d, 0xff99307f, + 0x004c3fe0, 0xffed37f0, 0x007e9d56, 0xff8162aa, + 0x0012c810, 0xffb3c020, 0x0066cf81, 0xff9235f3, + 0x0041ce1e, 0xffe0e607, 0x007c29fc, 0xff877b7c, + 0x002b1f35, 0xffc945e0, 0x0073b5ec, 0xffa12883, + 0x0055f5a5, 0xfff9b827, 0x007fd888, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static u32 AC3I2SUcode1fe000[] = { + 0x00000000, 0x03020102, 0x05040403, 0x00400040, + 0x00500050, 0x00600060, 0x00700070, 0x00800080, + 0x00a000a0, 0x00c000c0, 0x00e000e0, 0x01000100, + 0x01400140, 0x01800180, 0x01c001c0, 0x02000200, + 0x02800280, 0x03000300, 0x03800380, 0x04000400, + 0x04800480, 0x05000500, 0x00460045, 0x00580057, + 0x00690068, 0x007a0079, 0x008c008b, 0x00af00ae, + 0x00d100d0, 0x00f400f3, 0x01170116, 0x015d015c, + 0x01a201a1, 0x01e801e7, 0x022e022d, 0x02b902b8, + 0x03440343, 0x03d003cf, 0x045b045a, 0x04e604e5, + 0x05720571, 0x00600060, 0x00780078, 0x00900090, + 0x00a800a8, 0x00c000c0, 0x00f000f0, 0x01200120, + 0x01500150, 0x01800180, 0x01e001e0, 0x02400240, + 0x02a002a0, 0x03000300, 0x03c003c0, 0x04800480, + 0x05400540, 0x06000600, 0x06c006c0, 0x07800780, + 0x7b67533f, 0x1513110f, 0x04d80540, 0x04100478, + 0x07000000, 0x0b000900, 0x02b002f0, 0x02300270, + 0x017001f0, 0xf80000f0, 0x01000080, 0x02000180, + 0x03000280, 0x04000380, 0x2725231f, 0x2c2b2a29, + 0x2e2e2d2d, 0x30302f2f, 0x04030201, 0x08070605, + 0x0c0b0a09, 0x100f0e0d, 0x14131211, 0x18171615, + 0x1c1b1a19, 0x2825221f, 0x37312e2b, 0x4f49433d, + 0x796d6155, 0xcdb59d85, 0x0000fde5, 0x3d3e3f40, + 0x393a3b3c, 0x35363738, 0x32333434, 0x2f2f3031, + 0x2c2c2d2e, 0x29292a2b, 0x26262728, 0x23242425, + 0x21212223, 0x1e1f2020, 0x1c1d1d1e, 0x1a1b1b1c, + 0x1819191a, 0x16171718, 0x15151516, 0x13131414, + 0x12121213, 0x10111111, 0x0f0f1010, 0x0e0e0e0f, + 0x0d0d0d0d, 0x0c0c0c0c, 0x0b0b0b0b, 0x0a0a0a0a, + 0x0909090a, 0x08080909, 0x08080808, 0x07070707, + 0x06060707, 0x06060606, 0x05050606, 0x05050505, + 0x04040505, 0x04040404, 0x04040404, 0x03030304, + 0x03030303, 0x03030303, 0x02030303, 0x02020202, + 0x02020202, 0x02020202, 0x02020202, 0x01010202, + 0x01010101, 0x01010101, 0x01010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010101, 0x00000101, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x04d004d0, + 0x04000440, 0x03c003e0, 0x03b003b0, 0x03a003a0, + 0x03a003a0, 0x039003a0, 0x03900390, 0x03800380, + 0x03700370, 0x03600360, 0x03500350, 0x03400340, + 0x03200330, 0x03000310, 0x02f002f0, 0x02f002f0, + 0x03100300, 0x03900340, 0x042003e0, 0x04900460, + 0x046004a0, 0x04400440, 0x08000520, 0x08400840, + 0x04f004f0, 0x04100460, 0x03d003e0, 0x03b003c0, + 0x03a003b0, 0x03a003a0, 0x03a003a0, 0x03900390, + 0x03800390, 0x03800380, 0x03700370, 0x03600360, + 0x03500350, 0x03400340, 0x03100320, 0x02f00300, + 0x02f002f0, 0x030002f0, 0x03500320, 0x03e00390, + 0x04500420, 0x049004a0, 0x04400460, 0x06300480, + 0x08400840, 0x05800580, 0x045004b0, 0x03f00420, + 0x03d003e0, 0x03b003c0, 0x03b003b0, 0x03a003a0, + 0x03a003a0, 0x03a003a0, 0x03a003a0, 0x03900390, + 0x03900390, 0x03800380, 0x03700380, 0x03500360, + 0x03300340, 0x03100320, 0x02f00300, 0x02f002f0, + 0x03100300, 0x03500330, 0x041003c0, 0x04a00470, + 0x04400460, 0x04e00450, 0xffaaaaab, 0x00000000, + 0x00555555, 0xff99999a, 0xffcccccd, 0x00000000, + 0x00333333, 0x00666666, 0xff924925, 0xffb6db6e, + 0xffdb6db7, 0x00000000, 0x00249249, 0x00492492, + 0x006db6db, 0xff8ba2e9, 0xffa2e8ba, 0xffba2e8c, + 0xffd1745d, 0xffe8ba2f, 0x00000000, 0x001745d1, + 0x002e8ba3, 0x0045d174, 0x005d1746, 0x00745d17, + 0xff888889, 0xff99999a, 0xffaaaaab, 0xffbbbbbc, + 0xffcccccd, 0xffddddde, 0xffeeeeef, 0x00000000, + 0x00111111, 0x00222222, 0x00333333, 0x00444444, + 0x00555555, 0x00666666, 0x00777777, 0x08070605, + 0x0c0b0a09, 0x10100e0e, 0x00000010, 0x00000000, + 0x00000010, 0x00000020, 0x00000100, 0x00000110, + 0x00000120, 0x00000200, 0x00000210, 0x00000220, + 0x00001000, 0x00001010, 0x00001020, 0x00001100, + 0x00001110, 0x00001120, 0x00001200, 0x00001210, + 0x00001220, 0x00002000, 0x00002010, 0x00002020, + 0x00002100, 0x00002110, 0x00002120, 0x00002200, + 0x00002210, 0x00002220, 0x00000000, 0x00000010, + 0x00000020, 0x00000030, 0x00000040, 0x00000100, + 0x00000110, 0x00000120, 0x00000130, 0x00000140, + 0x00000200, 0x00000210, 0x00000220, 0x00000230, + 0x00000240, 0x00000300, 0x00000310, 0x00000320, + 0x00000330, 0x00000340, 0x00000400, 0x00000410, + 0x00000420, 0x00000430, 0x00000440, 0x00001000, + 0x00001010, 0x00001020, 0x00001030, 0x00001040, + 0x00001100, 0x00001110, 0x00001120, 0x00001130, + 0x00001140, 0x00001200, 0x00001210, 0x00001220, + 0x00001230, 0x00001240, 0x00001300, 0x00001310, + 0x00001320, 0x00001330, 0x00001340, 0x00001400, + 0x00001410, 0x00001420, 0x00001430, 0x00001440, + 0x00002000, 0x00002010, 0x00002020, 0x00002030, + 0x00002040, 0x00002100, 0x00002110, 0x00002120, + 0x00002130, 0x00002140, 0x00002200, 0x00002210, + 0x00002220, 0x00002230, 0x00002240, 0x00002300, + 0x00002310, 0x00002320, 0x00002330, 0x00002340, + 0x00002400, 0x00002410, 0x00002420, 0x00002430, + 0x00002440, 0x00003000, 0x00003010, 0x00003020, + 0x00003030, 0x00003040, 0x00003100, 0x00003110, + 0x00003120, 0x00003130, 0x00003140, 0x00003200, + 0x00003210, 0x00003220, 0x00003230, 0x00003240, + 0x00003300, 0x00003310, 0x00003320, 0x00003330, + 0x00003340, 0x00003400, 0x00003410, 0x00003420, + 0x00003430, 0x00003440, 0x00004000, 0x00004010, + 0x00004020, 0x00004030, 0x00004040, 0x00004100, + 0x00004110, 0x00004120, 0x00004130, 0x00004140, + 0x00004200, 0x00004210, 0x00004220, 0x00004230, + 0x00004240, 0x00004300, 0x00004310, 0x00004320, + 0x00004330, 0x00004340, 0x00004400, 0x00004410, + 0x00004420, 0x00004430, 0x00004440, 0x00000000, + 0x00000100, 0x00000200, 0x00000300, 0x00000400, + 0x00000500, 0x00000600, 0x00000700, 0x00000800, + 0x00000900, 0x00000a00, 0x00001000, 0x00001100, + 0x00001200, 0x00001300, 0x00001400, 0x00001500, + 0x00001600, 0x00001700, 0x00001800, 0x00001900, + 0x00001a00, 0x00002000, 0x00002100, 0x00002200, + 0x00002300, 0x00002400, 0x00002500, 0x00002600, + 0x00002700, 0x00002800, 0x00002900, 0x00002a00, + 0x00003000, 0x00003100, 0x00003200, 0x00003300, + 0x00003400, 0x00003500, 0x00003600, 0x00003700, + 0x00003800, 0x00003900, 0x00003a00, 0x00004000, + 0x00004100, 0x00004200, 0x00004300, 0x00004400, + 0x00004500, 0x00004600, 0x00004700, 0x00004800, + 0x00004900, 0x00004a00, 0x00005000, 0x00005100, + 0x00005200, 0x00005300, 0x00005400, 0x00005500, + 0x00005600, 0x00005700, 0x00005800, 0x00005900, + 0x00005a00, 0x00006000, 0x00006100, 0x00006200, + 0x00006300, 0x00006400, 0x00006500, 0x00006600, + 0x00006700, 0x00006800, 0x00006900, 0x00006a00, + 0x00007000, 0x00007100, 0x00007200, 0x00007300, + 0x00007400, 0x00007500, 0x00007600, 0x00007700, + 0x00007800, 0x00007900, 0x00007a00, 0x00008000, + 0x00008100, 0x00008200, 0x00008300, 0x00008400, + 0x00008500, 0x00008600, 0x00008700, 0x00008800, + 0x00008900, 0x00008a00, 0x00009000, 0x00009100, + 0x00009200, 0x00009300, 0x00009400, 0x00009500, + 0x00009600, 0x00009700, 0x00009800, 0x00009900, + 0x00009a00, 0x0000a000, 0x0000a100, 0x0000a200, + 0x0000a300, 0x0000a400, 0x0000a500, 0x0000a600, + 0x0000a700, 0x0000a800, 0x0000a900, 0x0000aa00, + 0xff800000, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xffb82995, 0xffaf5d75, 0xffa57d87, 0xff9a6806, + 0xff8df708, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xffb82995, 0xffaf5d75, 0xffa57d87, 0xff9a6806, + 0xff8df708, 0xff800000, 0xffb82995, 0xffaf5d75, + 0xffa57d87, 0xff9a6806, 0xff8df708, 0xff800000, + 0xfffb0000, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, + 0xfffdfffd, 0xfffdfffd, 0xfffdfffd, 0xfffefffe, + 0xfffefffe, 0xfffefffe, 0xffffffff, 0xffffffff, + 0xffffffff, 0x00000000, 0x00000000, 0x00000000, + 0x80050000, 0x000a800f, 0x001e801b, 0x80110014, + 0x00368033, 0x8039003c, 0x802d0028, 0x00228027, + 0x00668063, 0x8069006c, 0x807d0078, 0x00728077, + 0x80550050, 0x005a805f, 0x004e804b, 0x80410044, + 0x00c680c3, 0x80c900cc, 0x80dd00d8, 0x00d280d7, + 0x80f500f0, 0x00fa80ff, 0x00ee80eb, 0x80e100e4, + 0x80a500a0, 0x00aa80af, 0x00be80bb, 0x80b100b4, + 0x00968093, 0x8099009c, 0x808d0088, 0x00828087, + 0x01868183, 0x8189018c, 0x819d0198, 0x01928197, + 0x81b501b0, 0x01ba81bf, 0x01ae81ab, 0x81a101a4, + 0x81e501e0, 0x01ea81ef, 0x01fe81fb, 0x81f101f4, + 0x01d681d3, 0x81d901dc, 0x81cd01c8, 0x01c281c7, + 0x81450140, 0x014a814f, 0x015e815b, 0x81510154, + 0x01768173, 0x8179017c, 0x816d0168, 0x01628167, + 0x01268123, 0x8129012c, 0x813d0138, 0x01328137, + 0x81150110, 0x011a811f, 0x010e810b, 0x81010104, + 0x03068303, 0x8309030c, 0x831d0318, 0x03128317, + 0x83350330, 0x033a833f, 0x032e832b, 0x83210324, + 0x83650360, 0x036a836f, 0x037e837b, 0x83710374, + 0x03568353, 0x8359035c, 0x834d0348, 0x03428347, + 0x83c503c0, 0x03ca83cf, 0x03de83db, 0x83d103d4, + 0x03f683f3, 0x83f903fc, 0x83ed03e8, 0x03e283e7, + 0x03a683a3, 0x83a903ac, 0x83bd03b8, 0x03b283b7, + 0x83950390, 0x039a839f, 0x038e838b, 0x83810384, + 0x82850280, 0x028a828f, 0x029e829b, 0x82910294, + 0x02b682b3, 0x82b902bc, 0x82ad02a8, 0x02a282a7, + 0x02e682e3, 0x82e902ec, 0x82fd02f8, 0x02f282f7, + 0x82d502d0, 0x02da82df, 0x02ce82cb, 0x82c102c4, + 0x02468243, 0x8249024c, 0x825d0258, 0x02528257, + 0x82750270, 0x027a827f, 0x026e826b, 0x82610264, + 0x82250220, 0x022a822f, 0x023e823b, 0x82310234, + 0x02168213, 0x8219021c, 0x820d0208, 0x02028207, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000001, 0x00000002, 0x00000002, + 0x00000000, 0xff800000, 0xffa57d86, 0xffa57d86, + 0xffcf043b, 0xff89be51, 0xff89be51, 0xffcf043b, + 0xffe70748, 0xff8275a1, 0xff959267, 0xffb8e313, + 0xffb8e313, 0xff959267, 0xff8275a1, 0xffe70748, + 0xfff3742d, 0xff809dc9, 0xff9d0dfe, 0xffaecc33, + 0xffc3a946, 0xff8f1d34, 0xff8582fb, 0xffdad7f4, + 0xffdad7f4, 0xff8582fb, 0xff8f1d34, 0xffc3a946, + 0xffaecc33, 0xff9d0dfe, 0xff809dc9, 0xfff3742d, + 0xfff9b827, 0xff802778, 0xffa12883, 0xffaa0a5b, + 0xffc945e0, 0xff8c4a14, 0xff877b7c, 0xffd4e0cb, + 0xffe0e607, 0xff83d604, 0xff9235f3, 0xffbe31e2, + 0xffb3c020, 0xff99307f, 0xff8162aa, 0xffed37f0, + 0xffed37f0, 0xff8162aa, 0xff99307f, 0xffb3c020, + 0xffbe31e2, 0xff9235f3, 0xff83d604, 0xffe0e607, + 0xffd4e0cb, 0xff877b7c, 0xff8c4a14, 0xffc945e0, + 0xffaa0a5b, 0xffa12883, 0xff802778, 0xfff9b827, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; + +static u32 AC3I2SUcode1fff80[] = { + 0x0000240f, 0x007fffff, 0x007fffff, 0x00000003, + 0xff000000, 0xff000000, 0xff000000, 0xff000000, + 0xff000000, 0x00000000, 0x00000000, 0x00000000, + 0x007fffff, 0x00000000, 0x00000000, 0x00000000, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/lpcm.h linux.20pre2-ac1/drivers/media/video/ls220/lpcm.h --- linux.20pre2/drivers/media/video/ls220/lpcm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/lpcm.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,818 @@ +static u32 PCMUcode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb50001f7, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x029f9014, 0x829efef0, + 0x8286000f, 0x02bf0054, 0x82bcfef4, 0x82a6000e, + 0x80074000, 0x001f6193, 0x8013001f, 0x9020c000, + 0x003fb006, 0x803effe8, 0x803effec, 0x9020fa00, + 0x803effd0, 0x803effdc, 0x803effd8, 0x9020fe00, + 0x803effd4, 0x90400000, 0x804600a2, 0x90421800, + 0x804600a3, 0x80132000, 0x98000040, 0x800600a6, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x80070000, 0x001f23f9, 0x801e4b0c, + 0x001f210c, 0x80070001, 0x001f2324, 0x80070800, + 0x001f600f, 0x001fb0cb, 0x001fb010, 0x801efff0, + 0x98004000, 0x001f600e, 0x83e40121, 0x80070000, + 0x801e4b14, 0x800500a0, 0xb0000001, 0xb4000009, + 0x80070001, 0x800600a0, 0x80050080, 0x98000020, + 0x80060080, 0x9400ffdf, 0x80060080, 0x80070000, + 0x800600a0, 0x80074000, 0x801e4b04, 0x81df0004, + 0x801bfff0, 0x00000000, 0x940000ff, 0xb0000000, + 0xb4200033, 0x003f400e, 0x94010010, 0xb0000000, + 0xb400fff7, 0x003f0013, 0xb0010001, 0xb420001f, + 0x803bffe8, 0x801bffec, 0x805b4b04, 0x00000000, + 0x3001b800, 0xb4600001, 0x9021a000, 0x0421b800, + 0x3001b802, 0xb460000d, 0x80050086, 0x005f9044, + 0x0420b802, 0xb00101e0, 0xb4a0ffe5, 0x001fb010, + 0x001f010c, 0xb0000001, 0xb400ffe1, 0x80070001, + 0x001f210c, 0x83e400ee, 0xb500ffdd, 0x8007001f, + 0x94000003, 0x5810b800, 0x83e719ec, 0x1bffb800, + 0x003f9008, 0x1821b800, 0x00ffb801, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671a14, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0x80070000, 0x001f210c, 0xb500ffc8, + 0x003f400e, 0xb0000086, 0xb4400056, 0xb0000084, + 0xb4000040, 0xb0000085, 0xb4000046, 0xb0000086, + 0xb4000048, 0xb0000083, 0xb4000000, 0x815bff7c, + 0x00000000, 0x940a0080, 0x5c07b800, 0xb0000001, + 0xb4000074, 0x81674b18, 0x940a0007, 0x5803b800, + 0x116bb800, 0x005bb80b, 0x916b0004, 0x001bb80b, + 0x80530030, 0x98422000, 0x8013ffcf, 0x9800cfff, + 0x806500d4, 0x1463b800, 0x1863b802, 0x806600d4, + 0x80073cfb, 0x801e4b00, 0x800600a1, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x8013007f, + 0x9800ffff, 0x001fb040, 0x80070001, 0x001f2013, + 0x80070000, 0x001f2324, 0x001f600f, 0x001fb0cb, + 0x001fb010, 0x001fb041, 0x001fb042, 0x80073470, + 0x001fb008, 0x80071e50, 0x001fb009, 0x98214000, + 0xb5000010, 0x94011000, 0xb0001000, 0xb4200001, + 0x9421efff, 0x98210010, 0xb500000a, 0x80070000, + 0x001fb0cb, 0x83e4009a, 0x003f400e, 0x9421ffef, + 0xb5000004, 0x83e40096, 0x003f400e, 0x98211000, + 0x9421ffef, 0x003f600e, 0x80070100, 0x801efff0, + 0xb500ff6f, 0xb000008b, 0xb4000018, 0xb0000087, + 0xb400ffee, 0xb0000088, 0xb4000016, 0xb000008a, + 0xb4000016, 0xb000008c, 0xb4000017, 0xb0000089, + 0xb4000019, 0xb00000a0, 0xb400001b, 0xb00000a1, + 0xb4000048, 0xb00000a2, 0xb4000055, 0xb00000a3, + 0xb400004d, 0xb00000a4, 0xb4000057, 0xb00000a5, + 0xb400005b, 0xb00000a6, 0xb400005f, 0x803efff8, + 0xb500ffe1, 0x9421ffdf, 0xb500ffde, 0x80270100, + 0x803efff8, 0xb500ffdc, 0x803bffb0, 0x00000000, + 0x003fb040, 0xb500ffd8, 0x803bff80, 0x00000000, + 0x003f6001, 0xb500ffd4, 0x003f90ba, 0x803efff8, + 0xb500ffd1, 0x81674b18, 0x940a0007, 0x5803b800, + 0x116bb800, 0x005bb80b, 0x916b0004, 0x001bb80b, + 0x806500d4, 0x1463b800, 0x1863b802, 0x806600d4, + 0x80130001, 0x98003d21, 0x800600a1, 0x801e4b00, + 0x80074000, 0x801e4b04, 0x8013001f, 0x98405000, + 0x805effe0, 0x005fb006, 0x805effe8, 0x805effec, + 0x9042a000, 0x805effe4, 0x9040fa00, 0x805effd0, + 0x805effdc, 0x805effd8, 0x9040fe00, 0x805effd4, + 0x80070001, 0x001f2013, 0x80070000, 0x001f2324, + 0x001f600f, 0x001fb0cb, 0x001fb010, 0x80073cb0, + 0x001fb008, 0x800744a0, 0x001fb009, 0x98214000, + 0xb500ffa4, 0x80270000, 0x8047fef0, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x81df0000, 0x00000000, + 0x00000000, 0x83640475, 0x81df0004, 0xb500ff96, + 0x81df0000, 0x00000000, 0x00000000, 0x8364041f, + 0x81df0004, 0xb500ff90, 0x81df0000, 0x00000000, + 0x00000000, 0x836403da, 0x81df0004, 0xb500ff8a, + 0x81df0000, 0x00000000, 0x00000000, 0x83440339, + 0x81df0004, 0xb500ff84, 0x81df0000, 0x00000000, + 0x00000000, 0x8344031e, 0x81df0004, 0xb500ff7e, + 0x80070000, 0x80470000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002003, 0xb6003002, 0x001eb802, + 0x90420004, 0x80171000, 0x8057ffff, 0xb6002002, + 0xb6001801, 0x001fa020, 0x81df0004, 0x00ffb81f, + 0x83a70000, 0x8057ffff, 0x80770000, 0x8073007a, + 0x9863e7d2, 0x0207b803, 0x81df0000, 0x00000000, + 0x00000000, 0x80171000, 0xb6008007, 0x003fc0c0, + 0x005fc740, 0x40c1b810, 0x4102b810, 0x001fe0c6, + 0x001fe0c8, 0x4210b803, 0x81df0004, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671e34, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0x003f0013, 0xb0010001, 0xb420fff3, + 0x93bd0001, 0xb01d0004, 0xb480ffe3, 0x00ffb81f, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270be8, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717e8, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00059, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x83840237, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0xb6002009, 0x58708000, + 0x6068b803, 0x40c4b803, 0x00000000, 0x00c8b806, + 0x00000000, 0x00000000, 0x00000000, 0x5807a026, + 0x81df0004, 0x80670400, 0x5d22b80a, 0x81df0000, + 0x00000000, 0x00000000, 0xb600180a, 0x00cfb803, + 0x013fb0bc, 0x5922b809, 0x01afb809, 0x013f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x91290020, 0x81df0004, 0x808f0000, 0x801b4b14, + 0x80270001, 0xb0000001, 0xb4000002, 0x802600a0, + 0x803e4b14, 0x81270c00, 0xb00a0000, 0xb4000001, + 0x81270000, 0x813e4b0c, 0x80270001, 0x003f2013, + 0x80050086, 0x001fb044, 0x00ffb81b, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009c, 0x96b48000, 0xb0158000, + 0xb400018d, 0x96b40100, 0xb0150100, 0xb40001a9, + 0x96b40400, 0xb0150400, 0xb40001b0, 0x96b40001, + 0xb0150001, 0xb400000c, 0x96b40008, 0xb0150008, + 0xb4000196, 0x96b44000, 0xb0154000, 0xb40001af, + 0x96b40002, 0xb0150002, 0xb400015e, 0x00000000, + 0x00000000, 0xb50001c1, 0x02bf9017, 0x92b50001, + 0x02bfb017, 0x82850082, 0x83050081, 0x82a5009a, + 0x96b50001, 0xb0150001, 0xb4200014, 0x82a70000, + 0x02bfb017, 0x96b41840, 0xb0150800, 0xb420000c, + 0x96b40008, 0x5aa9b815, 0x96d46000, 0x5ec3b816, + 0x82f3000f, 0x9af7c00f, 0x1718b817, 0x1ab5b818, + 0x1ab5b816, 0x9ab50340, 0x82a60081, 0xb500013d, + 0x9b180180, 0x83060081, 0xb500013a, 0x82a5009a, + 0x96b50002, 0xb0150002, 0xb420001b, 0x82a70000, + 0x02bfb017, 0x96b41800, 0xb0151800, 0xb4000013, + 0x96b40040, 0xb0150040, 0xb4200004, 0xa3180c00, + 0x9b180340, 0x83060081, 0xb500012a, 0x96b40008, + 0x5aa9b815, 0x96d46000, 0x5ec3b816, 0x82f3000f, + 0x9af7c00f, 0x1718b817, 0x1ab5b818, 0x1ab5b816, + 0x9ab50340, 0x82a60081, 0xb500011e, 0x9b180180, + 0x83060081, 0xb500011b, 0x82a500c1, 0x96b5000f, + 0xb015000b, 0xb420000e, 0x96b40020, 0xb0150020, + 0xb400000b, 0x96b40200, 0xb0150200, 0xb4000008, + 0x82c50086, 0x82e50094, 0x3016b817, 0xb4400004, + 0x06f7b816, 0xb017ff00, 0xb4400001, 0xb5000109, + 0x96b46000, 0xb0156000, 0xb4000011, 0x96b41820, + 0xb0150820, 0xb4200004, 0x9b391000, 0x82a5009a, + 0x96b5feff, 0x82a6009a, 0x96b40040, 0xb0150040, + 0xb4200001, 0x9739efff, 0x96b91000, 0xb0151000, + 0xb4200003, 0x82a5009a, 0x9ab50100, 0x82a6009a, + 0x96b40040, 0xb0150040, 0xb4200019, 0x96b41800, + 0xb0151800, 0xb4200006, 0x96b98000, 0xb0158000, + 0xb4200003, 0x9b180180, 0x83060081, 0xb50000e9, + 0x96d80c00, 0x82b300ff, 0x9ab5f3ff, 0x1718b815, + 0xb0160c00, 0xb4000007, 0x82e50098, 0x96f70400, + 0xb0170400, 0xb4200002, 0x82c70c00, 0xb5000001, + 0xa2d60c00, 0x1b18b816, 0x9b180340, 0xb50000cf, + 0x96b40220, 0xb0150000, 0xb4e00033, 0x82a5009d, + 0x82f3ffff, 0x16b5b817, 0x82f3000e, 0x3015b817, + 0xb420002d, 0x96f98000, 0xb0178000, 0xb400002a, + 0x82a70000, 0x02bfb017, 0x82c50081, 0x9ab60020, + 0x82a60081, 0x82a50086, 0x92b50bb8, 0x82a60094, + 0x82c60081, 0x82c5009d, 0x96d6ffff, 0x82b30032, + 0x9ab58001, 0x82e500c1, 0x96f7000f, 0xb017000b, + 0xb4000002, 0x82b30022, 0x9ab58001, 0x1ab5b816, + 0x82c5009a, 0x96d60020, 0xb0160020, 0xb4200002, + 0x82b30032, 0x9ab58001, 0x82a6009d, 0x02ff9017, + 0x00000000, 0xb0170040, 0xb480000b, 0x96f41c00, + 0xb0171c00, 0xb4200008, 0x82e50086, 0x82c50094, + 0x92d63000, 0x3016b817, 0xb4400003, 0x9b180180, + 0x83060081, 0xb50000a3, 0x5eb5b814, 0x96b500f0, + 0x96f46000, 0x5eedb817, 0x1ab5b817, 0xb0170003, + 0xb4000004, 0x96b500ef, 0x96f70001, 0x5ae4b817, + 0x1ab5b817, 0x96d41800, 0xb0161800, 0xb400000a, + 0x96f900ff, 0x96b500ff, 0x9739ff00, 0x1b39b815, + 0x02a7b817, 0x96b500f3, 0x96d40008, 0x5ec1b816, + 0x1ab5b816, 0xb500000c, 0x96f98000, 0xb0178000, + 0xb4200007, 0x5efeb814, 0x96f70001, 0xb0170001, + 0xb4000003, 0x9b180180, 0x83060081, 0xb5000081, + 0x96b500f3, 0x9ab50008, 0x9739fff3, 0x96d40020, + 0xb0160020, 0xb4200017, 0x9b398000, 0x82c70000, + 0x02dfb017, 0x96d40010, 0x5ac8b816, 0x82f300ff, + 0x9af7cfff, 0x1718b817, 0x1b18b816, 0x9b180340, + 0x82c5009d, 0x96d6ffff, 0x82f3000e, 0x9af78001, + 0x1af7b816, 0x82c5009a, 0x96d60020, 0xb0160020, + 0xb4200002, 0x82f30032, 0x9af78001, 0x82e6009d, + 0xb500005a, 0x97397fff, 0x96b500ff, 0x5aaab815, + 0x82f300fc, 0x9af703ff, 0x1718b817, 0x1b18b815, + 0x9b180340, 0x82c5009a, 0x96d60010, 0xb0160010, + 0xb4200024, 0x82c70000, 0x02dfb017, 0x82c50086, + 0x92d60bb8, 0x82c60086, 0x82c50094, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4200002, 0x82e70bb8, + 0xb5000001, 0x82e70bb8, 0x12d6b817, 0x82e50081, + 0x9af70020, 0x82e60081, 0x82c60094, 0xa2f70020, + 0x82e60081, 0x82f30001, 0x16f7b818, 0x5ef0b817, + 0xb0170001, 0xb4000004, 0x96f84000, 0x5ee4b817, + 0x9718f3ff, 0x1b18b817, 0x82f3000a, 0x9af78000, + 0x82e6009d, 0x83060081, 0x83070001, 0x8306009f, + 0xb500009e, 0x82c5009d, 0x82f3000e, 0x9af78001, + 0x3016b817, 0xb420000f, 0x82b30032, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b30022, 0x9ab58001, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b30032, 0x9ab58001, + 0x82a6009d, 0x82c5009a, 0x96d60080, 0xb0160080, + 0xb4000011, 0x02df9017, 0x00000000, 0xb0160010, + 0xb480000d, 0x82c500c1, 0x96d6000f, 0xb016000b, + 0xb4000009, 0x82c50087, 0x96d60080, 0x5ac7b816, + 0x96f84000, 0x3017b816, 0xb4200003, 0x033f400f, + 0x9b394000, 0xb500000b, 0x9739bfff, 0x82e50061, + 0x96f70008, 0xb0170008, 0xb4000005, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4000001, 0x9718ffff, + 0x83060081, 0x83070001, 0x8306009f, 0x00000000, + 0xb5000066, 0x82850083, 0x96b400ff, 0xb015003c, + 0xb4200015, 0x96b92000, 0xb0152000, 0xb4000002, + 0x9b392000, 0xb5000010, 0x9739d3ff, 0x82870000, + 0x82860087, 0x82870008, 0x82860083, 0x8287001f, + 0x828600c9, 0x829bff78, 0x00000000, 0x828600cb, + 0x8285009d, 0x82b3ffff, 0x9ab5fffd, 0x1694b815, + 0x8286009d, 0xb5000000, 0x83070002, 0x8306009f, + 0x00000000, 0xb5000049, 0x96b90800, 0xb0150800, + 0xb4200009, 0x9739f7ff, 0x82a703fd, 0x82a600cb, + 0x82a7003c, 0x82a60083, 0x8285009d, 0x9a940002, + 0x8286009d, 0xb5000004, 0x82850087, 0x5a82b814, + 0xa2940200, 0x82860087, 0xb5000000, 0x83078000, + 0x8306009f, 0x00000000, 0xb5000034, 0x82850086, + 0x82a50094, 0x3015b814, 0xb4800002, 0x86b50bb8, + 0x82a60086, 0x83070008, 0x8306009f, 0x00000000, + 0xb500002a, 0x83050081, 0x82f3001c, 0x9af703ff, + 0x1718b817, 0x9b180140, 0x83060081, 0x83070100, + 0x8306009f, 0x00000000, 0xb5000020, 0x83070000, + 0x83050081, 0x9b180180, 0x83060081, 0x83070400, + 0x8306009f, 0x00000000, 0xb5000018, 0x82870000, + 0x82850082, 0x5eb7b814, 0x96b500fc, 0x96d40006, + 0x5ec1b816, 0x1ab5b816, 0x5aacb815, 0x83050081, + 0x82d3001c, 0x9ad600ff, 0x1718b816, 0x1b18b815, + 0x9b180e00, 0x83060081, 0x83074000, 0x8306009f, + 0x8305009d, 0x82d300ff, 0x9ad6bfff, 0x1718b816, + 0x8306009d, 0x00000000, 0xb5000000, 0x029f9005, + 0x01ffb814, 0x033f600f, 0x029f900a, 0x02bf900b, + 0x02df900c, 0x02ff900d, 0x031f900e, 0x033f900f, + 0x00ffb81e, 0x02ff9010, 0x92f70b43, 0x02ffb010, + 0x02ff90cb, 0x82bbffdc, 0x829bffd8, 0x93150004, + 0x3014b815, 0xb4000010, 0x02dbb818, 0x029bb815, + 0x3017b816, 0xb480000c, 0x5a81b814, 0x029fb010, + 0x82860095, 0x8293001f, 0x9294fe00, 0x92b50008, + 0x3015b814, 0xb4800002, 0x82b3001f, 0x92b5fa00, + 0x82beffdc, 0xb500ffeb, 0x029f9010, 0x83250094, + 0x06d4b819, 0x02d6b816, 0xb016ffff, 0xb4a0000a, + 0x8293000e, 0x9a948001, 0x82c5009d, 0x96d6ffff, + 0x1a94b816, 0x82c5009a, 0x96d60010, 0xb0160010, + 0xb4000001, 0x8286009d, 0x00ffb81c, 0x80070000, + 0x001fb0bf, 0x001f2329, 0x003fb800, 0x001f9006, + 0x5803b800, 0x80338000, 0x1800b801, 0x003fb800, + 0x005f4193, 0x5c41b802, 0x80350000, 0x00000000, + 0x0027b860, 0x80150010, 0x5810b800, 0x80750010, + 0x1863b800, 0x8087ffff, 0x80a7770b, 0x80c70000, + 0x1403b804, 0x3000b805, 0xb4000008, 0x5888b804, + 0x58a8b805, 0x90c60001, 0xb0060003, 0xb4a0fff8, + 0x84420001, 0xb4e0ffee, 0xb5000020, 0xb0060003, + 0xb4200007, 0x80150010, 0x5810b800, 0x81150010, + 0x950800ff, 0xb0080077, 0xb4000001, 0xb500fff4, + 0x001f400e, 0x98000010, 0x98004000, 0x9400fffe, + 0x001f600e, 0x80e70020, 0xb0060000, 0xb400000e, + 0x58e3b806, 0x90210020, 0x81070000, 0x5938b803, + 0x1908b809, 0x9523ff00, 0x5928b809, 0x1908b809, + 0x5d28b803, 0x9529ff00, 0x1908b809, 0x5d38b803, + 0x1908b809, 0x011fb0bf, 0x00ff2329, 0x80137fff, + 0x9800ffe7, 0x1421b800, 0x5c23b801, 0x001f9006, + 0x0441b800, 0x3001b800, 0xb4600002, 0x0440b801, + 0xa4422000, 0x007f90cb, 0x1063b802, 0x007fb0cb, + 0x003fb006, 0x803effec, 0x80470001, 0x005f2013, + 0xb500fbe3, 0x001f400e, 0x9400000f, 0xb0000000, + 0xb4200001, 0x00ffb81f, 0xb0000001, 0xb4000005, + 0xb0000003, 0xb4000003, 0xb0000002, 0xb4000001, + 0x00ffb81f, 0x80070001, 0x001f2013, 0xb500fbd4, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x003f9304, 0x007f0c14, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x003f9304, + 0x007f0c14, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x8384012a, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e74e58, 0x5de2b80f, + 0xb600020a, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0x0047b86f, 0xb0020001, + 0xb4c0fffd, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e74d50, 0x5de2b80f, 0xb600020a, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801b4e50, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x80184e54, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x019fb304, 0x017f2c14, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801b4e50, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x80184e54, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801b4e50, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x80184e54, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e74b30, 0x5de2b80f, 0xb600020a, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x91ef0020, + 0x90210020, 0x80270240, 0x81e74c30, 0x5de2b80f, + 0xb600020a, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0x0047b86f, 0xb0020001, + 0xb4c0fffd, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e74d50, 0x5de2b80f, 0xb600020a, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x91ef0020, + 0x90210020, 0x806f0007, 0x80af0007, 0x80270280, + 0x81e74d30, 0x5de2b80f, 0x00cfb801, 0x01ffb0bc, + 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x829bff80, 0x80af000f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60010, 0x90210010, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6001005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6001018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6002004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb4000099, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb4000022, 0xb00a0003, + 0xb400002f, 0xb00a0004, 0xb400005d, 0xb00a0005, + 0xb4000066, 0xb00a0006, 0xb400008a, 0xb00a0007, + 0xb4000088, 0xb00a0008, 0xb4000086, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004010, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x5c708028, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000070, 0x81df0000, 0x00000000, 0x00000000, + 0x8027ffff, 0xb6004008, 0x14618008, 0x019fa023, + 0x019fa020, 0x019fa020, 0x5c708028, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb5000061, + 0xb0130000, 0xb4000004, 0xb0130001, 0xb4000009, + 0xb0130002, 0xb400001a, 0x83a40102, 0x80170f00, + 0x007f8028, 0x001fa023, 0x007f8028, 0x001fa023, + 0xb5000054, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8000, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400ed, + 0x80170f00, 0x007f8028, 0x001fa023, 0xb5000041, + 0x80170f00, 0x00000000, 0x007f8020, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x83a400da, 0xb5000031, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002005, + 0x007f8008, 0x019fa023, 0x007f8008, 0x019fa023, + 0x019fa020, 0x81df0004, 0xb5000026, 0xb0130000, + 0xb4000008, 0xb0130001, 0xb4000012, 0xb0130002, + 0xb400001f, 0xb0130003, 0xb400001d, 0xb0130004, + 0xb400001b, 0x83a400d5, 0x007f8028, 0x019fa023, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000010, 0x80170f00, 0x00000000, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x83a400bf, + 0x80170f00, 0x007f8028, 0x001fa023, 0xb5000001, + 0xb5000000, 0x00000000, 0x00000000, 0xb500008e, + 0xb00a0001, 0xb400000e, 0xb00a0002, 0xb400001a, + 0xb00a0003, 0xb4000027, 0xb00a0004, 0xb4000055, + 0xb00a0005, 0xb400005e, 0xb00a0006, 0xb4000082, + 0xb00a0007, 0xb4000080, 0xb00a0008, 0xb400007e, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004008, + 0x007f8028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000070, 0x81df0000, 0x00000000, + 0x00000000, 0x8027ffff, 0xb6002008, 0x14618008, + 0x019fa023, 0x019fa020, 0x019fa020, 0x5c708048, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a40098, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40083, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a40070, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a4006b, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a40055, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x92730001, 0x92520001, + 0x3012b811, 0xb480fe76, 0x003f0324, 0x90210001, + 0xb0010006, 0xb4a00001, 0x80270001, 0x003f2324, + 0x2c8db811, 0x803bffe0, 0x805bffe4, 0x5886b804, + 0x1015b804, 0xad440003, 0x3000b802, 0xb4800001, + 0x8400a000, 0x801effec, 0x015f6193, 0x809e4b04, + 0x00ffb81f, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002a0c, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x81df0004, 0x00ffb81d, 0x81df0000, 0x00000000, + 0x00000000, 0xb600190f, 0x007f8028, 0x019fa023, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x81df0004, 0x00ffb81d, 0x00000000, + 0x829bff80, 0x80af001f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60020, 0x90210020, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6002005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb400008e, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb400001c, 0xb00a0003, + 0xb4000024, 0xb00a0004, 0xb4000052, 0xb00a0005, + 0xb400005b, 0xb00a0006, 0xb400007f, 0xb00a0007, + 0xb400007d, 0xb00a0008, 0xb400007b, 0x81df0000, + 0x00000000, 0x00000000, 0xb600800a, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x5c708028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x81df0004, 0xb500006b, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008004, 0x007f8028, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a400fa, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a400e5, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400d2, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6004005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a400cd, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a400b7, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x00000000, 0x00000000, + 0xb5000086, 0xb00a0001, 0xb400000e, 0xb00a0002, + 0xb4000017, 0xb00a0003, 0xb400001f, 0xb00a0004, + 0xb400004d, 0xb00a0005, 0xb4000056, 0xb00a0006, + 0xb400007a, 0xb00a0007, 0xb4000078, 0xb00a0008, + 0xb4000076, 0x81df0000, 0x00000000, 0x00000000, + 0xb6008005, 0x007f8028, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb500006b, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004004, + 0x007f8048, 0x019fa023, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000061, 0xb0130000, 0xb4000004, + 0xb0130001, 0xb4000009, 0xb0130002, 0xb400001a, + 0x83a40098, 0x80170f00, 0x007f8028, 0x001fa023, + 0x007f8028, 0x001fa023, 0xb5000054, 0x80170f00, + 0x00000000, 0x007f8020, 0x019fa023, 0x007f8000, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x83a40083, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000041, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40070, 0xb5000031, 0x81df0000, 0x00000000, + 0x00000000, 0xb6004005, 0x007f8008, 0x019fa023, + 0x007f8008, 0x019fa023, 0x019fa020, 0x81df0004, + 0xb5000026, 0xb0130000, 0xb4000008, 0xb0130001, + 0xb4000012, 0xb0130002, 0xb400001f, 0xb0130003, + 0xb400001d, 0xb0130004, 0xb400001b, 0x83a4006b, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x80170f00, + 0x007f8028, 0x001fa023, 0xb5000010, 0x80170f00, + 0x00000000, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x83a40055, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000001, 0xb5000000, 0x92730001, + 0x92520001, 0x3012b811, 0xb480fe89, 0x003f0324, + 0x90210001, 0xb0010006, 0xb4a00001, 0x80270001, + 0x003f2324, 0x2c8db811, 0x803bffe0, 0x805bffe4, + 0x5887b804, 0x1015b804, 0xad440003, 0x3000b802, + 0xb4800001, 0x8400a000, 0x801effec, 0x015f6193, + 0x809e4b04, 0x00ffb81f, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002a0c, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb600190f, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x81df0004, + 0x00ffb81d, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270be8, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717e8, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a0005d, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x8384f8a3, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6001811, 0xb6002010, 0x14618000, + 0x6068b803, 0x40c4b803, 0x14608000, 0x00c8b806, + 0x5870b803, 0x6068b803, 0x4104b803, 0x58c8b806, + 0x0108b808, 0x14c6b801, 0x00000000, 0x00000000, + 0x5d08b808, 0x1508b800, 0x1806a028, 0x81df0004, + 0x80670400, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x808f0000, 0x803b4b00, 0x00000000, + 0x802600a1, 0x80270001, 0x802600a0, 0x81270c00, + 0xb00a0000, 0xb4000001, 0x81270000, 0x813e4b0c, + 0x80270001, 0x003f2013, 0x00ffb81b, 0x00000000, +}; + +static u32 PCMUcode1f4b00[] = { + 0x00000000, 0x00000000, 0x00060504, 0x00000000, + 0x00000000, 0x00000000, 0x00300000, 0xffcfcfff, + 0x00302000, 0xffcfcfff, 0x00380000, 0xffc7c7ff, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/mpg_240.h linux.20pre2-ac1/drivers/media/video/ls220/mpg_240.h --- linux.20pre2/drivers/media/video/ls220/mpg_240.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/mpg_240.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1594 @@ +static u32 MPG240Ucode1f1800[] = { +0x820f001f,0x802f001f,0xb500000d,0x00000000, +0x00ffb81e,0x00000000,0x00000000,0x00000000, +0x00ffb81e,0x00000000,0x00000000,0x00000000, +0xb5000b5f,0x00000000,0x00000000,0x00000000, +0x80070800,0x001f6047,0x8013001f,0x90208000, +0x003fb174,0x803effe8,0x803effec,0x9020fa00, +0x803effd0,0x803effdc,0x803effd8,0x9020fe00, +0x803effd4,0x805bff7c,0x802500d4,0x94020080, +0xb0000000,0xb4200023,0x8013ffcf,0x9800cfff, +0x80730030,0x98631000,0x94420007,0xb0020002, +0xb4200005,0x8013ffc7,0x9800c7ff,0x80730038, +0x98631000,0xb5000006,0xb0020001,0xb4200004, +0x8013ffcf,0x9800cfff,0x80730030,0x98631000, +0x1421b800,0x1821b803,0x802600d4,0x8033001f, +0x98210000,0x802600a2,0x8033001f,0x98210300, +0x802600a3,0x80270225,0x80530001,0x98420100, +0x1821b802,0x80530200,0x98420000,0x804600a6, +0xb500001d,0x805bff7c,0x8013ffcf,0x9800cfff, +0x80730030,0x98631000,0x94420007,0xb0020002, +0xb4200005,0x8013ffc7,0x9800c7ff,0x80730038, +0x98631000,0xb5000006,0xb0020001,0xb4200004, +0x8013ffcf,0x9800cfff,0x80730030,0x98631000, +0x1421b800,0x1821b803,0x802600d4,0x8033001f, +0x98210000,0x802600a2,0x8033001f,0x98210300, +0x802600a3,0x80270c25,0x802600a1,0x80270002, +0x803eff84,0x80070000,0x801effc0,0x801effc4, +0x801effc8,0x801effcc,0x801eff88,0x80770000, +0x8057ffff,0x80170080,0x80070000,0xb6003f02, +0xb6002001,0x001fa020,0x8007ffff,0x801eff84, +0x80070001,0x001f25dc,0x001f20b1,0x80070000, +0x001f6046,0x001fb17c,0x001fb17d,0x80070000, +0x801e78d0,0x98004000,0x001f62ea,0x80070100, +0x801efff0,0x81df0004,0x00000000,0x00000000, +0x801bfff0,0x00000000,0x940000ff,0xb0000000, +0xb4200057,0x003f42ea,0x94010010,0xb0000000, +0xb400fff7,0x003f05dc,0xb0010001,0xb4200034, +0x803bffe8,0x801bffec,0x00000000,0x3001b800, +0xb4600001,0x90214000,0x0421b800,0xb0010800, +0xb460000d,0x80050086,0x005f902e,0xb0020000, +0xb4200002,0x001fb02e,0xb5000006,0x0420b802, +0xb0010930,0xb4a0ffe2,0x80070000,0x001fb02e, +0x83e40146,0xb500ffde,0x83e40111,0x80070000, +0x001fb02e,0x001f42ea,0x9400000f,0xb0000000, +0xb4000010,0x9400fff0,0x001f62ea,0x003f9174, +0x9421ffff,0x90210004,0xb001c000,0xb4800002, +0x8421c000,0x90218000,0x8013001f,0x1821b800, +0x003fb174,0x003f917c,0x90210004,0x003fb17c, +0x83e4012e,0x8013001f,0x83e71b0c,0x1bffb800, +0x003f9179,0x1821b800,0x00ffb801,0xb5000008, +0x80270000,0x003f25dc,0x8013001f,0x83e71b30, +0x1bffb800,0x003f917a,0x1821b800,0x00ffb801, +0x80070000,0x001f20b1,0x001f42ea,0x9420000f, +0xb0010000,0xb4200003,0x98000800,0x001f62ea, +0xb500ffaf,0x9400fff0,0x001f62ea,0x80270000, +0x8057ffff,0x80770000,0x80171800,0xb6000302, +0xb6002001,0x001fa021,0xb500ffa5,0xb500ffa4, +0x803bffc0,0x805bffc4,0x807bffc8,0x809bffcc, +0x5828b801,0x5cb8b802,0x1821b805,0x5848b802, +0x5cb8b803,0x1842b805,0x5868b803,0x5cb8b804, +0x1863b805,0x5888b804,0x1884b800,0x803effc0, +0x805effc4,0x807effc8,0x809effcc,0x003f42ea, +0xb0000086,0xb4400079,0xb0000084,0xb4000049, +0xb0000085,0xb4000063,0xb0000086,0xb400006c, +0xb0000081,0xb4000005,0xb0000082,0xb4000003, +0xb0000080,0xb4000001,0xb5000069,0x8013007f, +0x9800ffff,0x001fb02d,0x80070000,0x001fb17c, +0x8013001f,0x9040fa00,0x805effd0,0x805effdc, +0x805effd8,0x9040fe00,0x805effd4,0x9040c000, +0x805effe4,0x90008000,0x801effe0,0x001fb174, +0x801effe8,0x801effec,0x80078000,0x801e78d4, +0x80070000,0x001fb17c,0x001fb17d,0x001fb02e, +0x83e400ce,0x8013001f,0x98000000,0x800600a2, +0x8013001f,0x98000300,0x800600a3,0x805bff7c, +0x80070c25,0x94420080,0xb0020080,0xb420000d, +0x8013001f,0x98000000,0x800600a2,0x8013001f, +0x98000300,0x800600a3,0x80070225,0x80530001, +0x98420100,0x1800b802,0x80530200,0x98420000, +0x804600a6,0x800600a1,0x80050080,0x98000022, +0x80060080,0x80072000,0x001fb179,0x80074360, +0x001fb17a,0x80070001,0x001f25dc,0x98214000, +0xb5000029,0x8047ffff,0x805eff84,0x805bff88, +0x00000000,0xb0020001,0xb4200002,0x80470000, +0x805eff88,0x805bff7c,0x80070c25,0x94420080, +0xb0020080,0xb4200007,0x80070225,0x80530001, +0x98420100,0x1800b802,0x80530200,0x98420000, +0x804600a6,0x800600a1,0x80070001,0x800600a0, +0x9421efff,0x98210010,0xb500000f,0x80070000, +0x001fb17c,0x80070001,0x001f25dc,0x83e4008b, +0x80050081,0x80330008,0x98210000,0x1800b801, +0x80060081,0x003f42ea,0x9421ffef,0xb5000002, +0x98211000,0x9421ffef,0x83e40080,0x003f62ea, +0x80070100,0x801efff0,0xb500ff15,0xb000008b, +0xb400001c,0xb0000087,0xb400ffe8,0xb0000088, +0xb4000023,0xb000008a,0xb4000024,0xb000008c, +0xb4000019,0xb000008e,0xb4000014,0xb000008d, +0xb400001d,0xb0000089,0xb400001f,0xb00000a0, +0xb4000021,0xb00000a1,0xb4000022,0xb00000a2, +0xb400002b,0xb00000a3,0xb4000027,0xb00000a4, +0xb4000029,0xb00000a5,0xb4000029,0xb00000a6, +0xb4000029,0x803efff8,0xb500ffdd,0x80070000, +0x001fb17e,0xb500ffda,0x803bffb0,0x00000000, +0x003fb02d,0xb500ffd6,0x98210020,0xb500ffd2, +0x9421ffdf,0xb500ffd0,0xb500ffd1,0x80270341, +0x803efff8,0xb500ffce,0x803bff80,0x00000000, +0x003f62ef,0xb500ffca,0x003f917b,0x803efff8, +0xb500ffc7,0x80270000,0x8047fef0,0x003eb802, +0x90420004,0x003eb802,0x90420004,0x003eb802, +0x90420004,0x003eb802,0x83640d7c,0xb500ffbc, +0x83640d2a,0xb500ffba,0x83640ce9,0xb500ffb8, +0x83440c50,0xb500ffb6,0x83440c39,0xb500ffb4, +0x817bffe8,0x815b78d4,0x00000000,0x956bffff, +0x300bb80a,0xb4600001,0x916b4000,0x056bb80a, +0xb00b0080,0xb4a00026,0x80af001f,0x808f0000, +0x806f0000,0x81b300ff,0x8057ffff,0x5d67b80b, +0x5d42b80a,0xb62b001c,0xb00a3000,0xb4800001, +0x854a1000,0x80cf0400,0x015fb178,0x5942b80a, +0x01cfb80a,0x015f9178,0xb520ffff,0x80171000, +0xb600200a,0x01ff8000,0x5a18b80f,0x5a28b80f, +0x1631b80d,0x5e48b80f,0x9652ff00,0x5e78b80f, +0x1a73b810,0x1a73b811,0x1813a032,0x80cf0400, +0x015fb178,0x5942b80a,0x01afb80a,0x015f9178, +0xb520ffff,0x914a0020,0x5942b80a,0x815e78d4, +0x00000000,0x00000000,0x00ffb81f,0x80070000, +0x80470000,0x81171800,0xb6002003,0xb6003002, +0x001eb802,0x90420004,0xb6002003,0x011fa020, +0x011fa020,0x011fa020,0x00ffb81f,0x80070000, +0x80478000,0xb6002003,0xb6008002,0x001eb802, +0x90420004,0x00ffb81f,0x00000000,0x00000000, +0x015f42ea,0x944a4000,0xb0024000,0xb4200071, +0x954abfff,0x015f62ea,0x808f0000,0x80ef007c, +0x80171000,0x80971400,0x80270000,0xb6001003, +0xb6002002,0x001fa021,0x009fa021,0x80a76604, +0x80271400,0xb6001004,0x01efb801,0x01afb805, +0xb520ffff,0x90a50080,0x80a76e04,0x80271400, +0xb6001004,0x01efb801,0x01afb805,0xb520ffff, +0x90a50080,0x806f001f,0x80af001f,0x80276400, +0x5c22b801,0x806701e1,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x80275c00,0x5c22b801, +0x80670200,0xb600100a,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90210020,0x90630020, +0x808f0000,0x806f001f,0x80af001f,0x8027647c, +0x5c22b801,0x8067017e,0xb600020a,0x00cfb803, +0x003fb178,0x5822b801,0x01cfb801,0x003f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x90210020, +0x90630020,0x806f0010,0x80af0010,0x8027657c, +0x5c22b801,0x806701be,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x802765c0,0x5c22b801, +0x806701cf,0x00cfb803,0x003fb178,0x5822b801, +0x01cfb801,0x003f9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x80276000,0x005fb801,0x8033001f, +0x98218000,0x803effe0,0x90214000,0x803effe4, +0x8193001f,0x998c8000,0x019fb174,0x83270000, +0x003fb819,0x003f9174,0x5823b801,0x83338000, +0x1b39b801,0x003fb819,0x00000000,0x00000000, +0x81550000,0x0187b860,0x858c0040,0x81b380fc, +0x99ad0000,0x300cb80d,0xb4600003,0x81b30002, +0x99ad0000,0x118cb80d,0x003fb80c,0x00000000, +0x00000000,0x81550000,0x8257ffff,0x82d7ffff, +0x8357ffff,0x81672000,0x83440189,0xb00a0001, +0xb4000141,0x0187b860,0x858c0010,0x5988b80c, +0x5d8bb80c,0x958cffff,0xb00cc000,0xb4800002, +0x858cc000,0x918c8000,0x81b3001f,0x198cb80d, +0x801bffec,0x00000000,0x819effec,0x819e78d8, +0x019fb174,0x05acb800,0x300cb800,0xb4600001, +0x91ad4000,0x001f917c,0x1000b80d,0x001fb17c, +0x83440194,0xb00a0000,0xb4200127,0x015f0081, +0xb00a0002,0xb4200124,0x037f0082,0xb01b0000, +0xb400001e,0x0367b860,0x5b68b81b,0x5f68b81b, +0x017f4047,0x916b0010,0x5963b80b,0x83440160, +0x801bff84,0xb00a0001,0xb400000b,0xb00b00c0, +0xb460fffa,0x803f0000,0x80138000,0x1b7bb800, +0x003fb81b,0x00000000,0x00000000,0x80150000, +0x801bff84,0xb5000009,0x803f0000,0x80138000, +0x1b7bb800,0x003fb81b,0x00000000,0x00000000, +0x80150000,0x801bff84,0xb5000103,0x801bff84, +0x003f0084,0x3000b801,0x803eff84,0xb4000073, +0x801bff7c,0x00000000,0x94800080,0xb0040080, +0xb4200036,0x94800007,0x80730200,0xb0010002, +0xb420000e,0x80270265,0xb0040001,0xb4200003, +0x80130030,0x98000000,0xb5000006,0x80130030, +0x98000000,0xb0040000,0xb4000002,0x80130038, +0x98000000,0x98630060,0xb500001f,0xb0010000, +0xb420000e,0x80270225,0xb0040001,0xb4200003, +0x80130030,0x98001000,0xb5000006,0x80130030, +0x98001000,0xb0040000,0xb4000002,0x80130038, +0x98001000,0x98630000,0xb500000f,0xb0010001, +0xb420004a,0x80270225,0xb0040001,0xb4200003, +0x80130030,0x98002000,0xb5000006,0x80130030, +0x98000000,0xb0040000,0xb4000002,0x80130038, +0x98000000,0x98630040,0x806600a6,0x80530001, +0x98420100,0x1821b802,0xb500002d,0x94800007, +0xb0010002,0xb420000d,0x80270c65,0xb0040001, +0xb4200003,0x80130030,0x98000000,0xb5000006, +0x80130030,0x98000000,0xb0040000,0xb4000002, +0x80130038,0x98000000,0xb500001d,0xb0010000, +0xb420000d,0x80270c25,0xb0040001,0xb4200003, +0x80130030,0x98001000,0xb5000006,0x80130030, +0x98001000,0xb0040000,0xb4000002,0x80130038, +0x98001000,0xb500000e,0xb0010001,0xb4200017, +0x80270c25,0xb0040001,0xb4200003,0x80130030, +0x98002000,0xb5000006,0x80130030,0x98000000, +0xb0040000,0xb4000002,0x80130038,0x98000000, +0x806500d4,0x8053ffcf,0x9842cfff,0xb0040002, +0xb4200002,0x8053ffc7,0x9842c7ff,0x802600a1, +0x1463b802,0x1863b800,0x806600d4,0x807bff7c, +0x00000000,0x94630080,0xb0030080,0xb420000b, +0x807bff88,0x00000000,0xb0030001,0xb4000007, +0x802500a1,0x80670001,0x807eff88,0x80530001, +0x98420100,0x1821b802,0x802600a1,0x81070000, +0x011f62e2,0x011f62e3,0x011f0082,0xb0080000, +0xb4200004,0x81150010,0x00000000,0x00000000, +0x011f62de,0x011f0081,0xb0080001,0xb4200026, +0x81070020,0x011f25c1,0x81070180,0x011f62e1, +0x8344022a,0x8344024e,0x011f0082,0xb0080000, +0xb4200004,0x834401b1,0x8344019e,0xb00a0000, +0xb4200061,0x80c70000,0x00df25cb,0x83440261, +0x834405e7,0x02ff05b9,0x82a70000,0x82870000, +0x834403cf,0x92940001,0x3014b817,0xb480fffc, +0x8344067f,0x80270000,0x003f25dc,0x83440760, +0x003f05dc,0xb0010001,0xb4000003,0x802725d4, +0x003fb17a,0x00ffb81f,0x80d3001f,0x834725ac, +0x1b5ab806,0xb500002d,0xb0080002,0x81470004, +0xb4200045,0x81070008,0x011f25c1,0x81070480, +0x011f62e1,0x83440276,0x834402b0,0x011f0082, +0xb0080000,0xb4200004,0x8344019a,0x83440175, +0xb00a0000,0xb4200038,0x80c70000,0x00df25cb, +0x83440334,0x02df05cb,0x5ec2b816,0x834405ff, +0x02ff05b9,0x82a70000,0x82870000,0x834403a4, +0x92940001,0x3014b817,0xb480fffc,0x92b50001, +0xb0150003,0xb480fff8,0x83440651,0x80270000, +0x003f25dc,0x83440732,0x003f05dc,0xb0010001, +0xb4000003,0x8027268c,0x003fb17a,0x00ffb81f, +0x80d3001f,0x83472650,0x1b5ab806,0x80db78d8, +0x80fbffec,0x00000000,0x3006b807,0xb4200007, +0x00df05cb,0x90c60001,0x00df25cb,0xb006000c, +0xb4000002,0x035fb179,0x00ffb81f,0x80c70000, +0x00df25cb,0x80fb78dc,0x00000000,0x90e70001, +0xb00701b9,0xb4a00001,0x80e70001,0x80fe78dc, +0xb500feb0,0x802500a5,0x8153001f,0x3001b80a, +0xb420fffc,0x00ffb81f,0x001f42ea,0x1800b80a, +0x001f62ea,0x017f4047,0x5963b80b,0x0187b860, +0x118cb80b,0x81b380fe,0x99ad0000,0x300cb80d, +0xb4800003,0x81b30002,0x99ad0000,0x058cb80d, +0x003fb80c,0x00000000,0x00000000,0x81550000, +0x0187b860,0x5988b80c,0x5d8bb80c,0x958cffff, +0xb00cc000,0xb4800002,0x858cc000,0x918c8000, +0x81b3001f,0x198cb80d,0x801bffec,0x00000000, +0x819effec,0x019fb174,0x05acb800,0x300cb800, +0xb4600001,0x91ad4000,0x001f917c,0x1000b80d, +0x001fb17c,0x80171000,0x80971400,0x80270000, +0xb6001003,0xb6002002,0x001fa021,0x009fa021, +0x80171800,0xb6000602,0xb6002001,0x001fa021, +0x806f001f,0x80af001f,0x80a76604,0x80271400, +0xb6001004,0x01efb801,0x01afb805,0xb520ffff, +0x90a50080,0x80a76e04,0x80271400,0xb6001004, +0x01efb801,0x01afb805,0xb520ffff,0x90a50080, +0x81472000,0x015fb179,0x00ffb81f,0x00000000, +0x811be024,0x0107b860,0x95080007,0xb0080000, +0xb4000004,0xa5080008,0x00000000,0x0155b808, +0x00000000,0x8115000c,0x856b000c,0xb0080fff, +0xb400000b,0x81550004,0x856b0004,0x5904b808, +0x1908b80a,0x95080fff,0xb0080fff,0xb4000004, +0x81470001,0xb00b0020,0xb440fff6,0xb500000c, +0x81d50004,0x856b0004,0x00000000,0xb00e000f, +0xb400fffb,0x940b0007,0xb0000000,0xb420ffed, +0x001f42ea,0x9400fffe,0x81470000,0x001f62ea, +0x00ffb81a,0x950e0008,0x5d03b808,0x00000000, +0xb0080000,0xb40000c9,0x011f2080,0x950e0006, +0x5d01b808,0x81270004,0x0529b808,0x950e0001, +0x013f2081,0x011f2082,0x81150004,0x00000000, +0xb0080000,0xb40000bd,0xb008000f,0xb40000bb, +0x011f2083,0x81150002,0x00000000,0x81670004, +0xb0080002,0xb46000b5,0x011f2084,0x013f0081, +0xb0090002,0xb4200011,0x013f0083,0xb0080000, +0xb4200002,0x81077844,0xb5000005,0xb0080001, +0xb4200002,0x81077884,0xb5000001,0x81077824, +0x013f0083,0x5921b809,0x1129b808,0x0119b809, +0x00000000,0x00000000,0x011f6047,0x81150001, +0x00000000,0x011f2085,0x81150001,0x00000000, +0x011f2086,0x81350002,0x00000000,0x013f2087, +0x81150002,0x00000000,0x011f2088,0x81150001, +0x00000000,0x011f2089,0x81150001,0x00000000, +0x011f208a,0x81150002,0x00000000,0x011f208b, +0x81070001,0xb0090003,0xb4000001,0x81070002, +0x011f25b9,0x81070020,0x013f0081,0xb0090002, +0xb4200065,0x85290001,0xad29000f,0x00000000, +0x011f0083,0x1108b809,0x5901b808,0x910877c8, +0x0139b808,0x011f05b9,0x85080001,0x6928b809, +0x011f0084,0xb0090038,0xb4800007,0xb0080001, +0xb4000002,0xb0090050,0xb4400003,0x81270000, +0x8107001b,0xb5000010,0xb0080001,0xb4000005, +0xb0090060,0xb4800003,0x81270001,0x8107001e, +0xb5000009,0xb0080002,0xb4000005,0xb0090030, +0xb4400003,0x81270002,0x81070008,0xb5000002, +0x81270003,0x8107000c,0x011f25bb,0x013f25c0, +0xb0090002,0xb460001b,0x80477604,0x5c42b802, +0x814fffc0,0x80cf0037,0x005fb178,0x5842b802, +0x01cfb802,0x005f9178,0xb520ffff,0x90420020, +0x814fb580,0x80cf0057,0x005fb178,0x5842b802, +0x01cfb802,0x005f9178,0xb520ffff,0x804778a4, +0x5c42b802,0x814f39c0,0x80cf002f,0x005fb178, +0x5842b802,0x01cfb802,0x005f9178,0xb520ffff, +0xb5000021,0x804776e0,0x5c42b802,0x814fef40, +0x80cf0037,0x005fb178,0x5842b802,0x01cfb802, +0x005f9178,0xb520ffff,0x8297013c,0x8317018c, +0xb6000602,0x005f8034,0x031fa022,0x82970124, +0x83170160,0xb6000602,0x005f8034,0x031fa022, +0x8297010c,0x83170134,0xb6000602,0x005f8034, +0x031fa022,0x804778c4,0x5c42b802,0x814f1080, +0x80cf002f,0x005fb178,0x5842b802,0x01cfb802, +0x005f9178,0xb520ffff,0x013f0081,0xb0090001, +0xb420000e,0x808f0000,0x806f001b,0x80af001b, +0x80277758,0x5c22b801,0x80670037,0x00cfb803, +0x003fb178,0x5822b801,0x01cfb801,0x003f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x011f25bb, +0x011f0087,0xb0080001,0xb4000002,0x011f05bb, +0xb5000003,0x011f0088,0x91080001,0x5902b808, +0x011f25ba,0x81470000,0x00ffb81a,0x81470008, +0x00ffb81a,0x81270000,0x81470000,0x300842de, +0xb400000b,0x013f42e2,0x91290001,0x013f62e2, +0x013f42e3,0x91290001,0x013f62e3,0x83640006, +0x00000000,0x00000000,0x013f42e2,0x81470002, +0x013f62e2,0x00ffb81a,0x00ffb81b,0x83640041, +0x80c70004,0x80270000,0xb600200d,0x00ff05b9, +0x5c42b801,0x300205ba,0xb4800001,0x80e70001, +0x80470000,0xb6270005,0x1062b801,0x914301b8, +0x00fff00a,0x83840050,0x90420080,0x90210004, +0x00ffb81a,0x8364002f,0x017f05bb,0x800700bc, +0x80270000,0xb00b0000,0xb4000015,0xb62b0014, +0x00ff05b9,0x5c42b801,0x300205ba,0xb4800001, +0x80e70001,0x80470000,0xb0070000,0xb400000b, +0xb627000a,0x1062b801,0x914301b8,0x00fff00a, +0x5c62b801,0x1063b800,0x00bff003,0x90650134, +0x00dff003,0x83840034,0x90420080,0x90210004, +0x019f05b9,0x80c70002,0x80270000,0xb00b0000, +0xb400000f,0xb62b000e,0x80470000,0xb00c0000, +0xb400000a,0xb62c0009,0x1062b801,0x914301b8, +0x00fff00a,0xb0070000,0xb4000003,0x906302b8, +0x00fff003,0x83840020,0x90420080,0x90210004, +0x00ffb81a,0x8107ffff,0x80c70004,0x00ff0083, +0x83840019,0x80c70002,0x00ff0084,0x83840016, +0x80c70001,0x00ff0085,0x83840013,0x80c70001, +0x00ff0086,0x83840010,0x80c70002,0x00ff0087, +0x8384000d,0x80c70002,0x00ff0088,0x8384000a, +0x80c70001,0x00ff0089,0x83840007,0x80c70001, +0x00ff008a,0x83840004,0x80c70002,0x00ff008b, +0x83840001,0x00ffb81b,0x80a70001,0x64a6b805, +0x5ca1b805,0xb0050000,0xb400000e,0x95288000, +0xb0090000,0xb4000001,0x81270001,0x5901b808, +0x1547b805,0xb00a0000,0xb4000001,0x81470001, +0x2129b80a,0xb0090000,0xb4000001,0xa1088005, +0xb500ffef,0x9508ffff,0x00ffb81c,0x015f05ba, +0x013f05b9,0x800700bc,0xb0090000,0xb400000f, +0xb00a0000,0xb400000d,0x80270000,0xb62a000b, +0x80470000,0xb6290008,0x80950004,0x5865b802, +0x1063b801,0x5862b803,0x906301b8,0x0217b803, +0x90420001,0x021fa004,0x90210001,0xa54a0020, +0xb4c0000e,0xb0090000,0xb400000c,0xb62a000b, +0x80950004,0x80470000,0xb6290007,0x5865b802, +0x1063b801,0x5862b803,0x906301b8,0x0217b803, +0x90420001,0x021fa004,0x90210001,0x00ffb81a, +0x013f05b9,0xb0090000,0xb4000019,0x80270000, +0xb6002017,0x80470000,0xb6290014,0x5865b802, +0x1063b801,0x5862b803,0x914301b8,0x009ff00a, +0xad420060,0x00000000,0x114ab801,0x5942b80a, +0x914a1c80,0x0217b80a,0xb0040000,0xb4000004, +0x80950006,0x00000000,0x021fa004,0xb5000002, +0x8087003f,0x021fa004,0x90420001,0x90210001, +0x00ffb81a,0x8257ffff,0x82d7ffff,0x011f05ba, +0x013f05b9,0x80270000,0xb0090000,0xb400002b, +0xb6280015,0x80470000,0xb6290012,0x5865b802, +0x1063b801,0x5862b803,0x914301b8,0xaca20060, +0x009ff00a,0x10a5b801,0x58a2b805,0x90a502b8, +0x0217b805,0x80670000,0xb0040000,0xb4000003, +0x90840001,0x0075b804,0x00000000,0x021fa003, +0x90420001,0x90210001,0xa5480020,0xb4000013, +0x5822b801,0xb62a0011,0x914101b8,0x90a102b8, +0x0217b805,0x009ff00a,0xb0040000,0x80670000, +0xb4000002,0x90840001,0x0075b804,0xb6290006, +0x021fa203,0x009f8210,0x009f8210,0x009f8210, +0x009f8210,0x009f8210,0x90210004,0x00ffb81a, +0x015f05ba,0x013f05b9,0x800700bc,0xb0090000, +0xb4000013,0xb00a0000,0xb4000011,0x80270000, +0xb62a000f,0x80470000,0xb629000c,0x1080b801, +0x007ff004,0x90830134,0x007ff004,0x0095b803, +0x5865b802,0x1063b801,0x5862b803,0x906301b8, +0x0217b803,0x90420001,0x021fa004,0x90210001, +0x011f05bb,0x254ab808,0xb4c0000d,0xb62a000c, +0x1080b801,0x007ff004,0x90830134,0x007ff004, +0x0095b803,0x5862b801,0x906301b8,0x0217b803, +0x90210001,0x021fa204,0x007f8210,0x021fa004, +0xa5480020,0xb4c0000e,0xb0090000,0xb400000c, +0x80870000,0xb62a000a,0x80470000,0xb6290007, +0x5865b802,0x1063b801,0x5862b803,0x906301b8, +0x0217b803,0x90420001,0x021fa004,0x90210001, +0x00000000,0x00000000,0x00ffb81a,0x011f05bb, +0x013f05b9,0xb0080000,0xb4000015,0xb0090000, +0xb4000013,0x00000000,0x80270000,0xb6280010, +0x80470000,0xb629000d,0x5865b802,0x1063b801, +0x5862b803,0x914301b8,0x009ff00a,0xb0040000, +0xb4000005,0x80950002,0x906302b8,0x0217b803, +0x00000000,0x021fa004,0x90420001,0x90210001, +0xa5480020,0xb00a0000,0xb4000010,0xb0090000, +0xb400000e,0x00000000,0x80870000,0xb62a000b, +0x80470000,0xb6290008,0x5865b802,0x1063b801, +0x5862b803,0x906302b8,0x0217b803,0x00000000, +0x021fa004,0x90420001,0x90210001,0xb0080000, +0xb400004c,0xb0090000,0xb400004a,0x00000000, +0x80270000,0xb6280047,0x80470000,0xb6290044, +0x5865b802,0x1063b801,0x5862b803,0x914301b8, +0x009ff00a,0xad420060,0x00000000,0x00000000, +0x00000000,0x114ab801,0x5942b80a,0x914a1c80, +0x0217b80a,0xb0040000,0xb400002e,0x906302b8, +0x009ff003,0xb0040000,0xb420000a,0x80950006, +0x00000000,0x021fa204,0x80950006,0x015f8210, +0x021fa204,0x80950006,0x015f8210,0x021fa004, +0xb5000026,0xb0040001,0xb4200009,0x80950006, +0x00000000,0x021fa204,0x015f8210,0x021fa204, +0x80950006,0x015f8210,0x021fa004,0xb500001b, +0xb0040003,0xb4200009,0x80950006,0x00000000, +0x021fa204,0x80950006,0x015f8210,0x021fa204, +0x015f8210,0x021fa004,0xb5000010,0xb0040002, +0xb420000e,0x80950006,0x00000000,0x021fa204, +0x015f8210,0x021fa204,0x015f8210,0x021fa004, +0xb5000006,0x8087003f,0x021fa204,0x015f8210, +0x021fa204,0x015f8210,0x021fa004,0x90420001, +0x90210001,0xa5480020,0xb4c00011,0xb0090000, +0xb400000f,0x8087003f,0x5862b801,0x90631afc, +0xb62a000b,0x90630004,0x0047b803,0xb6290008, +0x90420180,0x0217b802,0x00000000,0x021fa204, +0x003f8210,0x021fa204,0x003f8210,0x021fa004, +0x00ffb81a,0x8257ffff,0x82d7ffff,0x011f05bb, +0x013f05b9,0x80270000,0x00e7b809,0x300105ba, +0xb4800001,0x80e70001,0x800700bc,0x80470000, +0xb0070000,0xb400004c,0xb627004b,0x5865b802, +0x1063b801,0x5862b803,0x914301b8,0xaca20060, +0x009ff00a,0x10a5b801,0x58a2b805,0x90a502b8, +0x0217b805,0xb0040000,0xb400002b,0x1060b801, +0x00bff003,0x10a5b804,0x90650160,0x00dff003, +0xb0060003,0xb4200007,0x90650134,0x00dff003, +0xb6000303,0x0075b806,0x021fa203,0x007f8210, +0xb5000021,0x5861b805,0x906300dc,0x009fd803, +0x90650134,0x00dff003,0xaca20060,0x00000000, +0x00000000,0x00000000,0x0075b806,0x10a5b801, +0x58a2b805,0x90a502b8,0x0217b805,0x588fb804, +0xb600030c,0xb6001007,0x04a3b804,0xb4600002, +0x58a1b803,0xb5000002,0x58a1b805,0x90a50001, +0x0067b805,0x9465ffff,0x5d50b805,0x021fa20a, +0x015f8210,0xb5000004,0x81470000,0xb6000302, +0x021fa20a,0x009f8210,0x009f05b9,0xb0040002, +0xb420000c,0x300105ba,0xb480000a,0x58a2b801, +0x90a502b8,0x0217b805,0x90a50180,0x0297b805, +0xb6000304,0x00bf8210,0x009f8210,0x029fa205, +0x009f8214,0x90420001,0x90210001,0x3001b808, +0xb480ffa9,0xa5480020,0xb00a0000,0xb4000015, +0xb0090000,0xb4000013,0x58a2b801,0x90a502b8, +0xb62a0010,0x80470000,0xb629000d,0xaca20060, +0x00000000,0x00000000,0x00000000,0x80670000, +0x10a5b801,0x58a2b805,0x90a502b8,0x0217b805, +0xb6000302,0x021fa203,0x00bf8210,0x90420001, +0x90210001,0x00ffb81a,0x00000000,0x00000000, +0x80770000,0x8057ffff,0x80f70000,0x80d7ffff, +0x81770000,0x8157ffff,0x81f70000,0x81d7ffff, +0xac140060,0xac350020,0x00000000,0x00000000, +0x12c0b801,0x5ac2b816,0x92d61980,0x83a400a5, +0xad940400,0x009f9173,0x013f05ca,0x914c6604, +0x114ab804,0x001f97e0,0x001eb80a,0xb0090000, +0xb4000003,0x80a76e44,0x80c76644,0xb5000002, +0x80a76644,0x80c76e44,0x808f000f,0x806f0000, +0x80af000e,0x80cf07e1,0x11e5b80c,0x11efb804, +0x5de2b80f,0x01ffb178,0x59e2b80f,0x01afb80f, +0x01ff9178,0x0047b86f,0xb0020001,0xb4c0fffd, +0x80cf07f0,0x1206b80c,0x1210b804,0x5e02b810, +0x021fb178,0x5a02b810,0x01afb810,0x021f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x916c6e04, +0x116bb804,0x001f97ff,0x001eb80b,0x808f0000, +0x806f001f,0x80af001f,0x90ac6604,0x5ca2b805, +0x80270400,0xb600080a,0x00cfb801,0x00bfb178, +0x58a2b805,0x01cfb805,0x00bf9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90210020,0x90a50020, +0x90ac6e04,0x5ca2b805,0x80270500,0xb600080a, +0x00cfb801,0x00bfb178,0x58a2b805,0x01cfb805, +0x00bf9178,0x0047b86f,0xb0020001,0xb4c0fffd, +0x90210020,0x90a50020,0x81530020,0xac140060, +0xac350020,0x80170800,0x80d7003c,0x12c0b801, +0x5ac2b816,0x92d602b8,0x0117b816,0x90241000, +0x0097b801,0x80470000,0x4002b803,0xb6000804, +0x005f8020,0x480287e4,0x005f8020,0x500287e4, +0x00000000,0x00000000,0x00000000,0x1021b80a, +0x5c36b801,0x5801b800,0x18c0b801,0xb0090000, +0xb4000002,0x90641440,0xb5000001,0x90641040, +0xb6000f0d,0x0097b803,0x80470000,0x4002b803, +0xb6001002,0x005f8020,0x480287e4,0x0108a026, +0x90630040,0x00000000,0x1021b80a,0x5c36b801, +0x5801b800,0x18c0b801,0x90641400,0x0097b803, +0x80470000,0x4002b803,0x005f8020,0x005f87e4, +0xb6000802,0x005f8040,0x480287c4,0x005f87e0, +0x0108a026,0x00000000,0x1021b80a,0x5c36b801, +0x5801b800,0x18c0b801,0xb0090000,0xb4000002, +0x906417c0,0xb5000001,0x906413c0,0xb6000f0f, +0x0097b803,0x80470000,0x4002b803,0xb6000804, +0x005f8020,0x500287e4,0x005f8020,0x480287e4, +0x0108a026,0x84630040,0x00000000,0x1021b80a, +0x5c36b801,0x5801b800,0x18c0b801,0xb0140000, +0xb4200005,0x90840004,0x9484003f,0x009fb173, +0xa1290001,0x013f25ca,0x80d7ffff,0x0108a026, +0x00ffb81a,0x81330004,0x8093007f,0x9884ffff, +0x80b3ff80,0x0017b816,0x90360040,0x0097b801, +0x81530010,0xb6001004,0x400a8000,0x404a8004, +0x0008a020,0x0088a022,0x0017b816,0x9036007c, +0x0097b801,0x81171000,0xb6001004,0x40048020, +0x480487e4,0x00000000,0x0108a020,0x81470000, +0x81670001,0x81870008,0x81a70040,0x81c707c4, +0x81e70040,0xb6000432,0xb00a0001,0xb4e00004, +0x80c71000,0x80e71000,0x81171040,0xb5000003, +0x80c71040,0x80e71040,0x81171000,0x844d0004, +0x10e7b802,0xb62b001f,0x0017b806,0x0097b807, +0xb62c0004,0x40048020,0x480487e4,0x00000000, +0x0108a020,0x0017b806,0x0097b807,0x0197b80e, +0x00000000,0x001f8020,0x042087e4,0xb62c000f, +0x4041800c,0x001f8020,0x0048b802,0x5e38802c, +0x2e11b801,0x042087e4,0x1042b810,0x0462b804, +0xb4a00002,0x0047b804,0xb5000003,0x0462b805, +0xb4600001,0x0047b805,0x011fa022,0x10c6b80f, +0x10e7b80f,0x5961b80b,0x5d81b80c,0x5da1b80d, +0x5de1b80f,0x914a0001,0x954a0001,0x11ceb80f, +0x80171018,0x81171fcc,0x80470000,0x41448020, +0x494487c0,0x00000000,0x0188b80a,0x494487e0, +0x00000000,0x0148b80a,0x0502a10a,0x4145b80c, +0x494580e0,0x00000000,0x0108a5ea,0x41448080, +0x494487c0,0x00000000,0x0108a78a,0x49448020, +0x00000000,0x0108a2ea,0x41448020,0x49448720, +0x00000000,0x0188b80a,0x4145b80c,0x49458080, +0x494587a0,0x00000000,0x0108a68a,0x4145b80c, +0x49458080,0x494587a0,0x00000000,0x0108a08a, +0x4145b80c,0x49458020,0x49458040,0x00000000, +0x0188b80a,0x494587e0,0x00000000,0x0108a08a, +0x4144b80c,0x494587a0,0x00000000,0x0108a52a, +0x41448080,0x49448040,0x494486c0,0x00000000, +0x0108a04a,0x41448040,0x49448720,0x00000000, +0x0108a36a,0x04028020,0x011fa420,0x001f8040, +0x011fa100,0x001f8080,0x011fa080,0x001f8100, +0x011fa040,0x001f8660,0x011fa120,0x41458020, +0x49458000,0x00000000,0x0108a00a,0x0017b816, +0x9036007c,0x0097b801,0x81171000,0x81970784, +0x00000000,0x001f8020,0x042087e4,0xb600100f, +0x4041800c,0x001f8020,0x0048b802,0x5e38802c, +0x2e11b801,0x042087e4,0x1042b810,0x0462b804, +0xb4a00002,0x0047b804,0xb5000003,0x0462b805, +0xb4600001,0x0047b805,0x011fa022,0x81470000, +0x81670001,0x81870008,0x81a70040,0x81c707c4, +0x81e70040,0xb6000432,0xb00a0001,0xb4e00004, +0x80c71000,0x80e71000,0x81171040,0xb5000003, +0x80c71040,0x80e71040,0x81171000,0x844d0004, +0x10e7b802,0xb62b001f,0x0017b806,0x0097b807, +0xb62c0004,0x40048020,0x480487e4,0x00000000, +0x0108a020,0x0017b806,0x0097b807,0x0197b80e, +0x00000000,0x001f8020,0x042087e4,0xb62c000f, +0x4041800c,0x001f8020,0x0048b802,0x5e38802c, +0x2e11b801,0x042087e4,0x1042b810,0x0462b804, +0xb4a00002,0x0047b804,0xb5000003,0x0462b805, +0xb4600001,0x0047b805,0x011fa022,0x10c6b80f, +0x10e7b80f,0x5961b80b,0x5d81b80c,0x5da1b80d, +0x5de1b80f,0x914a0001,0x954a0001,0x11ceb80f, +0x80171034,0x81171f84,0x80470000,0x41448040, +0x49448640,0x00000000,0x0188b80a,0x49448100, +0x49448780,0x00000000,0x0108a08a,0x4144b80c, +0x49448040,0x49448080,0x494487c0,0x00000000, +0x0108a16a,0x4145b80c,0x49458700,0x00000000, +0x0188b80a,0x494581a0,0x494586e0,0x00000000, +0x0108a66a,0x4145b80c,0x49448040,0x494487e0, +0x00000000,0x0188b80a,0x011fa1ec,0x4145b80c, +0x49458100,0x49458780,0x00000000,0x0108a08a, +0x41458720,0x49458100,0x494586e0,0x49458160, +0x49458020,0x49458020,0x49458760,0x00000000, +0x0108a08a,0x414587a0,0x49458080,0x49458760, +0x494580c0,0x49458700,0x49458140,0x49458020, +0x49458760,0x00000000,0x0108a74a,0x414587a0, +0x49458080,0x49458760,0x494580e0,0x49458700, +0x49458120,0x49458020,0x49458760,0x00000000, +0x0108a08a,0x41458720,0x49458100,0x494586e0, +0x49458140,0x49458040,0x49458020,0x49458720, +0x00000000,0x0108a0ca,0x41458080,0x49458040, +0x49458020,0x49458620,0x00000000,0x0188b80a, +0x49458080,0x00000000,0x0108a7ca,0x4144b80c, +0x49458040,0x49458020,0x49458080,0x00000000, +0x0108a5ea,0x41448080,0x49448700,0x00000000, +0x0188b80a,0x49448780,0x00000000,0x0108a7ca, +0x4144b80c,0x49448140,0x00000000,0x0108a7ca, +0x49448040,0x00000000,0x0108a0ca,0x41448700, +0x00000000,0x0188b80a,0x49448000,0x00000000, +0x0108a04a,0x011fa00c,0x80171f80,0xb6002006, +0x40048000,0x48048000,0x48048000,0x48048000, +0x00000000,0x0008a020,0x00ffb81d,0x00000000, +0x80770000,0x8057ffff,0x015f05b9,0x017f05bb, +0x8293ffff,0x9a94ffff,0x81a70000,0xb62a003a, +0xaded0180,0xae0d0180,0xadcd0080,0x902f1980, +0x0017b801,0xb6002033,0x904e01b8,0x00000000, +0x013ff002,0xb0090000,0xb400001f,0x904f02b8, +0x80c70000,0x011fd802,0x6829b808,0x94210001, +0xb0010001,0xb4e00001,0x00c7b814,0x6429b806, +0x80470001,0x6449b802,0x84420001,0x1442b808, +0x84690001,0x5863b803,0x906300dc,0x1042b801, +0x003f9803,0x90420001,0x4082b801,0x90630004, +0x003f9803,0x00000000,0x5897b804,0x1804b805, +0x4082b801,0x00000000,0x00000000,0x00000000, +0x10a4b800,0xb5000001,0x80a70000,0x90501c80, +0x00000000,0x007ff002,0x5842b803,0x904205f8, +0x0097b802,0x00000000,0x40058004,0x48058004, +0x00000000,0x0008a020,0x91ce0004,0x91ef0004, +0x92100004,0x91ad0001,0x00ffb81a,0x80770000, +0x8057ffff,0x80d7ffff,0x015f05b9,0x017f05bb, +0x8293ff80,0x9a940000,0x82a70020,0x81a70000, +0x81e702b8,0x80171980,0xb62a004f,0xb600034d, +0xac0d0080,0xac4d0180,0xac960080,0x822700bc, +0x91c001b8,0x00000000,0x1042b804,0x92021c80, +0xb62b003a,0x013ff00e,0x00fff011,0xb0090000, +0xb4000027,0x10e7b809,0x5821b807,0x902100dc, +0x00000000,0x001fd801,0x82470000,0x80270001, +0x6452b801,0x3002b800,0xb4600002,0x92520001, +0xb500fffb,0x86520001,0x80c70000,0x011fd80f, +0x6832b808,0xb0010001,0xb4e00001,0x00c7b814, +0x84520017,0x0056b802,0x80270001,0x6432b801, +0x84210001,0x1408b801,0x6402b800,0x10c6b800, +0x9027018c,0x00000000,0x001ff001,0x5802b800, +0x9020073c,0x904006f8,0x007f9801,0x0097b802, +0x10c6b803,0x40868004,0x48868004,0xb5000003, +0x80c70000,0x40868004,0x00000000,0x0088b804, +0x003ff010,0x5822b801,0x902105f8,0x0097b801, +0x91ce0004,0x91ef0004,0x40448004,0x48448004, +0x92100004,0x0008a022,0x92310001,0x0435b80b, +0xb4000007,0x80870000,0xb6210005,0x001fa024, +0x91ce0004,0x91ef0004,0x92100004,0x92310001, +0x00000000,0x91ad0001,0x00ffb81a,0x00000000, +0x007f05b9,0x001f0081,0xb0000001,0xb4400029, +0x001f05d8,0xac400080,0x801702b8,0x80970438, +0x90421800,0x0117b802,0x8087ffff,0x80b3ffff, +0x80d3007f,0x98c6ff00,0x80f3ff80,0x81070080, +0xb6002018,0x10088020,0x0056b800,0x0442b806, +0xb4a00004,0xb0000000,0x0007b806,0xb4400001, +0x0007b807,0x0027b800,0x5c08b800,0x1400b804, +0xb0030001,0xb4000008,0x10288024,0x0056b801, +0x0442b806,0xb4a00004,0xb0010000,0x0027b806, +0xb4400001,0x0027b807,0x5828b801,0x1421b805, +0x1900a021,0x001f05d8,0x90000001,0x001f25d8, +0x00ffb81a,0x801702b8,0x80970438,0x81171800, +0x8087ffff,0x80b3ffff,0x80d3007f,0x98c6ff00, +0x80f3ff80,0x81070080,0xb6006018,0x10088020, +0x0056b800,0x0442b806,0xb4a00004,0xb0000000, +0x0007b806,0xb4400001,0x0007b807,0x0027b800, +0x5c08b800,0x1400b804,0xb0030001,0xb4000008, +0x10288024,0x0056b801,0x0442b806,0xb4a00004, +0xb0010000,0x0027b806,0xb4400001,0x0027b807, +0x5828b801,0x1421b805,0x1900a021,0x00ffb81a, +0x001f0081,0xb0000001,0xb4400006,0x001f05d8, +0xb0000003,0xb4000003,0x80270001,0x003f25dc, +0x00ffb81a,0x003f05d9,0x009f05cb,0xb0010000, +0xb400000e,0x015f42ed,0x81070000,0x8127017c, +0xb00a0000,0xb4000002,0x81070180,0x812702fc, +0x802500a5,0x9421ffff,0x3001b808,0xb4800011, +0x3001b809,0xb4a00079,0xb500000e,0x001f0081, +0xb0000001,0xb4400003,0xb0040002,0xb4200006, +0xb5000002,0xb0040000,0xb4200003,0x802702ff, +0x81470000,0xb5000003,0x80270001,0x003f25d9, +0x81470180,0xb0040000,0xb4200001,0x83840348, +0x80070000,0x001f25d8,0x009f902d,0x80af001f, +0x808f0000,0x806f0000,0x8007ffff,0x8033ffff, +0x80171800,0x807bff8c,0x94630003,0xb0030003, +0xb4000016,0xb0030002,0xb4000035,0xb0030001, +0xb4000024,0xb6006010,0x14618000,0x6068b803, +0x40c4b803,0x14608000,0x00c8b806,0x5870b803, +0x6068b803,0x4104b803,0x58c8b806,0x0108b808, +0x14c6b801,0x00000000,0x00000000,0x5d08b808, +0x1508b800,0x1806a028,0xb5000030,0xb6006010, +0x14618000,0x6068b803,0x40c4b803,0x14608000, +0x00c8b806,0x5870b803,0x6068b803,0x4104b803, +0x5cc8b806,0x0108b808,0x14c6b800,0x00000000, +0x00000000,0x5908b808,0x1508b801,0x1806a028, +0xb500001e,0xb600600d,0x14618000,0x6068b803, +0x40c4b803,0x00000000,0x00c8b806,0x00000000, +0x00000000,0x00000000,0x5d08b806,0x1508b800, +0x58c8b806,0x14c6b801,0x1806a028,0xb500000f, +0xb600600e,0x14608000,0x5868b803,0x6068b803, +0x40c4b803,0x00000000,0x00c8b806,0x00000000, +0x00000000,0x00000000,0x5d08b806,0x1508b800, +0x58c8b806,0x14c6b801,0x1806a028,0x80670600, +0x5d22b80a,0xb600030a,0x00cfb803,0x013fb178, +0x5922b809,0x01afb809,0x013f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90630020,0x91290020, +0x81270180,0xb00a0000,0xb4000001,0x81270000, +0x013f62ed,0x80270001,0x003f25dc,0x00ffb81a, +0x001f0081,0xb0000001,0xb4400006,0x001f05d8, +0xb0000003,0xb4000003,0x80270001,0x003f25dc, +0x00ffb81a,0x003f05d9,0x009f05cb,0xb0010000, +0xb400000e,0x015f42ed,0x81070000,0x8127017c, +0xb00a0000,0xb4000002,0x81070180,0x812702fc, +0x802500a5,0x9421ffff,0x3001b808,0xb4800011, +0x3001b809,0xb4a00079,0xb500000e,0x001f0081, +0xb0000001,0xb4400003,0xb0040002,0xb4200006, +0xb5000002,0xb0040000,0xb4200003,0x802702ff, +0x81470000,0xb5000003,0x80270001,0x003f25d9, +0x81470180,0xb0040000,0xb4200001,0x838402b4, +0x80070000,0x001f25d8,0x009f902d,0x80af001f, +0x808f0000,0x806f0000,0x8007ffff,0x8033ffff, +0x80171800,0x807bff8c,0x94630003,0xb0030003, +0xb4000016,0xb0030002,0xb4000035,0xb0030001, +0xb4000024,0xb6006010,0x14618000,0x6068b803, +0x40c4b803,0x14608000,0x00c8b806,0x5870b803, +0x6068b803,0x4104b803,0x58c8b806,0x0108b808, +0x14c6b801,0x00000000,0x00000000,0x5d08b808, +0x1508b800,0x1806a028,0xb5000030,0xb6006010, +0x14618000,0x6068b803,0x40c4b803,0x14608000, +0x00c8b806,0x5870b803,0x6068b803,0x4104b803, +0x5cc8b806,0x0108b808,0x14c6b800,0x00000000, +0x00000000,0x5908b808,0x1508b801,0x1806a028, +0xb500001e,0xb600600d,0x14618000,0x6068b803, +0x40c4b803,0x00000000,0x00c8b806,0x00000000, +0x00000000,0x00000000,0x5908b806,0x1508b801, +0x5cc8b806,0x14c6b800,0x1806a028,0xb500000f, +0xb600600e,0x14608000,0x5870b803,0x6068b803, +0x40c4b803,0x00000000,0x00c8b806,0x00000000, +0x00000000,0x00000000,0x5908b806,0x1508b801, +0x5cc8b806,0x14c6b800,0x1806a028,0x80670600, +0x5d22b80a,0xb600030a,0x00cfb803,0x013fb178, +0x5922b809,0x01afb809,0x013f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90630020,0x91290020, +0x81270180,0xb00a0000,0xb4000001,0x81270000, +0x013f62ed,0x80270001,0x003f25dc,0x00ffb81a, +0x029fb024,0x02bfb025,0x02dfb026,0x02ffb027, +0x031fb028,0x033fb029,0x033f4046,0x0287b86f, +0x029fb02a,0x8285009d,0x9a940008,0x8286009d, +0x8285009c,0x96b48000,0xb0158000,0xb40001b5, +0x96b40100,0xb0150100,0xb400020b,0x96b40400, +0xb0150400,0xb400020c,0x96b40001,0xb0150001, +0xb400000c,0x96b40008,0xb0150008,0xb40001ad, +0x96b44000,0xb0154000,0xb400020b,0x96b40002, +0xb0150002,0xb4000182,0x00000000,0x00000000, +0xb500021d,0x02bf917e,0x92b50001,0x02bfb17e, +0x82850082,0x96f40001,0xb0170000,0xb4000171, +0x5efdb814,0x96f70001,0xb0170001,0xb420000b, +0x83050069,0x9718003f,0x82e50064,0x12f7b818, +0x86f70109,0x82feff74,0x02e7b86f,0x9af74000, +0x01ffb817,0x96f7bfff,0x01ffb817,0x83050081, +0x82a5009a,0x96b50001,0xb0150001,0xb4200014, +0x82a70000,0x02bfb17e,0x96b41840,0xb0150800, +0xb420000c,0x96b40008,0x5aa9b815,0x96d46000, +0x5ec3b816,0x82f3000f,0x9af7c00f,0x1718b817, +0x1ab5b818,0x1ab5b816,0x9ab50340,0x82a60081, +0xb500014c,0x9b180180,0x83060081,0xb5000149, +0x82a5009a,0x96b50002,0xb0150002,0xb420001b, +0x82a70000,0x02bfb17e,0x96b41800,0xb0151800, +0xb4000013,0x96b40040,0xb0150040,0xb4200004, +0xa3180c00,0x9b180340,0x83060081,0xb5000139, +0x96b40008,0x5aa9b815,0x96d46000,0x5ec3b816, +0x82f3000f,0x9af7c00f,0x1718b817,0x1ab5b818, +0x1ab5b816,0x9ab50340,0x82a60081,0xb500012d, +0x9b180180,0x83060081,0xb500012a,0x82a500c1, +0x96b5000f,0xb015000b,0xb420000e,0x96b40020, +0xb0150020,0xb400000b,0x96b40200,0xb0150200, +0xb4000008,0x82c50086,0x82e50094,0x3016b817, +0xb4400004,0x06f7b816,0xb017ff00,0xb4400001, +0xb5000118,0x96b46000,0xb0156000,0xb4000011, +0x96b41820,0xb0150820,0xb4200004,0x9b391000, +0x82a5009a,0x96b5feff,0x82a6009a,0x96b40040, +0xb0150040,0xb4200001,0x9739efff,0x96b91000, +0xb0151000,0xb4200003,0x82a5009a,0x9ab50100, +0x82a6009a,0x96b40040,0xb0150040,0xb4200019, +0x96b41800,0xb0151800,0xb4200006,0x96b98000, +0xb0158000,0xb4200003,0x9b180180,0x83060081, +0xb50000f8,0x96d80c00,0x82b300ff,0x9ab5f3ff, +0x1718b815,0xb0160c00,0xb4000007,0x82e50098, +0x96f70400,0xb0170400,0xb4200002,0x82c70c00, +0xb5000001,0xa2d60c00,0x1b18b816,0x9b180340, +0xb50000c4,0x96b40220,0xb0150000,0xb4e00021, +0x82a5009d,0x82f3ffff,0x16b5b817,0x82f33800, +0x3015b817,0xb420001b,0x96f98000,0xb0178000, +0xb4000018,0x82a70000,0x02bfb17e,0x82c5009d, +0x96d6ffff,0x82b3c800,0x9ab58001,0x82e500c1, +0x96f7000f,0xb017000b,0xb4000002,0x82b38800, +0x9ab58001,0x1ab5b816,0x82c5009a,0x96d60020, +0xb0160020,0xb4200002,0x82b3c800,0x9ab58001, +0x82a6009d,0x02ff917e,0x00000000,0xb0170040, +0xb4800000,0x5eb5b814,0x96b500f0,0x96f46000, +0x5eedb817,0x1ab5b817,0xb0170003,0xb4000004, +0x96b500ef,0x96f70001,0x5ae4b817,0x1ab5b817, +0x96d41800,0xb0161800,0xb400000a,0x96f900ff, +0x96b500ff,0x9739ff00,0x1b39b815,0x02a7b817, +0x96b500f3,0x96d40008,0x5ec1b816,0x1ab5b816, +0xb500000c,0x96f98000,0xb0178000,0xb4200007, +0x5efeb814,0x96f70001,0xb0170001,0xb4000003, +0x9b180180,0x83060081,0xb50000a2,0x96b500f3, +0x9ab50008,0x9739fff3,0x96d40020,0xb0160020, +0xb4200019,0x82c7001f,0x82c600c9,0x9b398000, +0x82c70000,0x02dfb17e,0x96d40010,0x5ac8b816, +0x82f300ff,0x9af7cfff,0x1718b817,0x1b18b816, +0x9b180340,0x82c5009d,0x96d6ffff,0x82f33800, +0x9af78001,0x1af7b816,0x82c5009a,0x96d60020, +0xb0160020,0xb4200002,0x82f3c800,0x9af78001, +0x82e6009d,0xb500005f,0x97397fff,0x96b500ff, +0x5aaab815,0x82f300fc,0x9af703ff,0x1718b817, +0x1b18b815,0x9b180340,0x82c5009a,0x96d60010, +0xb0160010,0xb4200027,0x82c70000,0x02dfb17e, +0x82c50086,0x92d60e10,0x82c60086,0x82c50094, +0x5eefb818,0x96f70003,0xb0170003,0xb4200002, +0x82e70e10,0xb5000001,0x82e70e10,0x12d6b817, +0x82e50081,0x9af70020,0x82e60081,0x82c60094, +0xa2f70020,0x82e60081,0x82f30001,0x16f7b818, +0x5ef0b817,0xb0170001,0xb4000004,0x96f84000, +0x5ee4b817,0x9718f3ff,0x1b18b817,0x82f32800, +0x9af78000,0x82e6009d,0x83060081,0x83070001, +0x8306009f,0x8305009c,0xb0180001,0xb4e0fffb, +0xb50000f5,0x82c5009d,0x82f33800,0x9af78001, +0x3016b817,0xb420000f,0x82b3c800,0x9ab58001, +0x82e500c1,0x96f7000f,0xb017000b,0xb4000002, +0x82b38800,0x9ab58001,0x82c5009a,0x96d60020, +0xb0160020,0xb4200002,0x82b3c800,0x9ab58001, +0x82a6009d,0x82c5009a,0x96d60080,0xb0160080, +0xb4000013,0x02df917e,0x00000000,0xb0160010, +0xb480000f,0x82c500c1,0x96d6000f,0xb016000b, +0xb400000b,0x82c50087,0x96d60080,0x5ac7b816, +0x82c50098,0x96d60800,0x5ac3b816,0x96f84000, +0x3017b816,0xb4200002,0x033f4046,0x9b394000, +0x9739bfff,0x82e50061,0x96f70008,0xb0170008, +0xb4000005,0x5eefb818,0x96f70003,0xb0170003, +0xb4000001,0x9718ffff,0x96b41800,0xb0151800, +0xb4000008,0x5eb9b814,0x96b5000f,0x82c50099, +0x5ed0b816,0x96f6000f,0x5ab0b815,0x82a60099, +0xb5000002,0x5ef9b814,0x96f7000f,0x5aecb817, +0x82c5009a,0x96d60fff,0x1ad6b817,0x82c6009a, +0x96b46000,0xb0156000,0xb4200005,0x5ae2b817, +0x82d30ffc,0x9ad63fff,0x1718b816,0x1b18b817, +0x83060081,0x83070001,0x8306009f,0x8305009c, +0xb0180001,0xb4e0fffb,0x00000000,0xb500009e, +0x82850083,0x96b400ff,0xb015003c,0xb4200019, +0x96b92000,0xb0152000,0xb4000002,0x9b392000, +0xb5000014,0x9739d3ff,0x82870000,0x82860087, +0x82870008,0x82860083,0x829bff78,0x82a7001f, +0xb0140400,0xb4000001,0x82a70010,0x82a600c9, +0x829bff78,0x00000000,0x828600cb,0x8285009d, +0x82b3ffff,0x9ab5fffd,0x1694b815,0x8286009d, +0xb5000000,0x83070002,0x8306009f,0x00000000, +0xb500007d,0x83078000,0x8306009f,0x00000000, +0xb5000079,0x82850094,0x82a50086,0x06b5b814, +0x02b6b815,0xb0151700,0xb440004b,0x8285006c, +0x969400ff,0xb0140024,0xb4000019,0xb0140012, +0xb4000017,0x8285009a,0x5eedb814,0x96f70003, +0xb0170003,0xb4000009,0x82a50083,0x5ea8b815, +0x96b500ff,0xb0150020,0xb4400002,0x82c70bbc, +0xb5000001,0x82c70bb8,0xb5000008,0x82a50083, +0x5ea8b815,0x96b500ff,0xb0150020,0xb4400002, +0x82c71199,0xb5000001,0x82c71197,0xb5000016, +0x8285009a,0x5eedb814,0x96f70003,0xb0170003, +0xb4000009,0x82a50083,0x5ea8b815,0x96b500ff, +0xb0150020,0xb4400002,0x82c70e18,0xb5000001, +0x82c70e04,0xb5000008,0x82a50083,0x5ea8b815, +0x96b500ff,0xb0150020,0xb4400002,0x82c70e18, +0xb5000001,0x82c70e04,0x82e50086,0x12f7b816, +0x02bf917e,0xb0150020,0xb480000b,0x82a5009a, +0x96b56000,0xb0156000,0xb4000007,0x82a50098, +0x96d50a00,0xb0160a00,0xb4000002,0xb0160000, +0xb4200001,0x92f70704,0x82850081,0x9ab40020, +0x82a60081,0x82c50094,0x82e60094,0x82860081, +0x86b70704,0x82a6009b,0x83070008,0x8306009f, +0x00000000,0xb5000024,0x83070100,0x8306009f, +0x00000000,0xb5000020,0x83070000,0x83050081, +0x9b180180,0x83060081,0x83070400,0x8306009f, +0x00000000,0xb5000018,0x82870000,0x82850082, +0x5eb7b814,0x96b500fc,0x96d40006,0x5ec1b816, +0x1ab5b816,0x5aacb815,0x83050081,0x82d3001c, +0x9ad600ff,0x1718b816,0x1b18b815,0x9b180e00, +0x83060081,0x83074000,0x8306009f,0x8305009d, +0x82d3ffff,0x9ad6bfff,0x1718b816,0x8306009d, +0x00000000,0xb5000000,0x029f902a,0x01ffb814, +0x033f6046,0x029f9024,0x02bf9025,0x02df9026, +0x02ff9027,0x031f9028,0x033f9029,0x00ffb81e, +0x02ff917d,0x92f7092f,0x031f0084,0xb0180001, +0xb4200002,0x02ff917d,0x92f70870,0x02ffb17d, +0x02ff917c,0x82bbffdc,0x829bffd8,0x93150004, +0x3014b815,0xb4000017,0x02dbb818,0x029bb815, +0x3017b816,0xb4800013,0x5a81b814,0x029fb17d, +0x82def200,0x82fef204,0x82e50086,0x06f7b814, +0x02f6b817,0x82fef208,0x82860095,0x82870001, +0x829ef220,0x8293001f,0x9294fe00,0x92b50008, +0x3015b814,0xb4800002,0x82b3001f,0x92b5fa00, +0x82beffdc,0x82850086,0x83250094,0x06d4b819, +0x02d6b816,0xb016ffff,0xb4a00009,0x82c50081, +0x9ab60020,0x82a60081,0x82a50086,0x92b50e10, +0x82a60094,0x82c60081,0x86b50704,0x82a6009b, +0x00ffb81c,0x00000000,0x00000000,0x00000000, +0x001f9012,0x001fb200,0x001f004c,0x001f2804, +0x801bfef0,0x8058fef4,0x803bff68,0x8078ff6c, +0x2000b801,0x2042b803,0x001fb204,0x005f2814, +0x82e70001,0x83640048,0x029fb014,0x829efef0, +0x8286000f,0x02bf2054,0x82bcfef4,0x82a6000e, +0x00ffb81a,0x80e70001,0x801336e3,0x9800eb76, +0x001fb200,0x800700ab,0x001f2804,0x801bc3e8, +0x8058c3ec,0x83640024,0x82e70000,0x83640036, +0x029fb3c0,0x029fb200,0x02bf2f04,0x02bf2804, +0x801bc000,0x8058c004,0x8364001b,0x82e70000, +0x8364002d,0x001f93c0,0x3000b814,0xb420000a, +0x001f0f04,0x3000b815,0xb4200007,0x829efef0, +0x82bcfef4,0x029fb012,0x02bf204c,0x82870001, +0x829cfef5,0x00ffb81a,0xb0070000,0xb4000007, +0x80e70000,0x801399fa,0x9800c92e,0x001fb200, +0x800700af,0x001f2804,0xb500ffdc,0x82870000, +0x829cfef5,0x00ffb81a,0x80c700ff,0x803bff68, +0x8078ff6c,0x14a0b806,0x2063b805,0x007f2814, +0x2021b802,0x58c8b806,0x14a0b806,0x58b0b805, +0x2021b805,0x58c8b806,0x14a0b806,0x2021b805, +0x58c8b806,0x14a0b806,0x5cb0b805,0x2021b805, +0x003fb204,0x00ffb81b,0x82c70000,0x83070800, +0x83270005,0x8197080c,0x81d7ffff,0x83840126, +0x83840001,0x00ffb81b,0x808f0000,0x806f001f, +0x80af001f,0x80270240,0x81e77c08,0x5de2b80f, +0xb6000208,0x00cfb801,0x01ffb178,0x59e2b80f, +0x01cfb80f,0x01ff9178,0xb520ffff,0x91ef0020, +0x90210020,0x80270280,0x81e77b00,0x5de2b80f, +0xb6000208,0x00cfb801,0x01ffb178,0x59e2b80f, +0x01cfb80f,0x01ff9178,0xb520ffff,0x91ef0020, +0x90210020,0x8057ffff,0x80170830,0x80070810, +0x80270808,0xb6000509,0x005ff000,0x90420900, +0x007ff001,0x90630a00,0x009ff002,0x00bff003, +0x2004a025,0x90000001,0x90210001,0x80070814, +0x80d7ffff,0x8097085c,0x8017083c,0xb6000404, +0x005ff000,0x007f87e0,0x84000001,0x2082a7e3, +0x80970860,0x80170840,0x2082b803,0x007f8000, +0x2083a004,0x80170830,0x80970850,0x80270808, +0xb6000508,0x005f8024,0x90420900,0x007ff001, +0x90630a00,0x009ff002,0x00bff003,0x2004a025, +0x90210001,0x80170840,0x00000000,0x02bf87e0, +0x80970860,0x82870000,0xb6000404,0x005f87e4, +0x5a88b814,0x204287e0,0x1a94b802,0x00ffb81c, +0x001f0e49,0x001f2b09,0x001f0e41,0x001f2b08, +0x001f0e46,0x001f2b07,0x001f0e48,0x001f2b06, +0x001f0e42,0x001f2b05,0x001f0e47,0x001f2b04, +0x001f0e45,0x001f2b03,0x001f0e43,0x001f2b02, +0x001f0e40,0x001f2b01,0x001f0e44,0x001f2b00, +0x001f0f25,0xa020000c,0x94400001,0x94600002, +0x94810004,0x94a10008,0x94c00010,0x5943b802, +0x5861b803,0x5882b804,0x5ca2b805,0x5cc4b806, +0x194ab803,0x194ab804,0x194ab805,0x194ab806, +0x015f2b38,0x801b7c00,0x003f92c1,0x5c28b801, +0x005f92c2,0x5858b802,0x1821b802,0x2000b801, +0x001fb2c4,0x80187c04,0x003f0b09,0x2000b801, +0x001f2b14,0x82c70001,0x82e70001,0x83070b10, +0x8327001e,0x81970b35,0x8384009f,0x02df0b38, +0x82170e30,0x838400f1,0x819efef0,0x817cfef4, +0x819eff68,0x817cff6c,0x00ffb81b,0x820f001f, +0x8018fef8,0x8057ffff,0x001f2b09,0x8018fef6, +0x80d7ffff,0x001f2b08,0x8018fefa,0x8157ffff, +0x001f2b07,0x8018fefd,0x81d7ffff,0x001f2b06, +0x8018fefb,0x802f001f,0x001f2b05,0x8018fefe, +0x00000000,0x001f2b04,0x8018fef9,0x00000000, +0x001f2b03,0x8018feff,0x00000000,0x001f2b02, +0x8018fef7,0x00000000,0x001f2b01,0x8018fefc, +0x00000000,0x001f2b00,0x001f0f25,0xa0200011, +0x94410001,0x94600002,0x94800004,0x94a00008, +0x94c10010,0x5941b802,0x5861b803,0x5c82b804, +0x58a1b805,0x5cc1b806,0x194ab803,0x194ab804, +0x194ab805,0x194ab806,0x015f2b38,0x801b7c00, +0x003f92c1,0x5c28b801,0x005f92c2,0x5858b802, +0x1821b802,0x2000b801,0x001fb2c4,0x80187c04, +0x003f0b09,0x2000b801,0x001f2b14,0x82c70001, +0x82e70001,0x83070b10,0x8327001e,0x81970b35, +0x83840055,0x02df0b38,0x82170e20,0x838400a7, +0x819efef0,0x817cfef4,0x5ac8b80c,0x02ff0e44, +0x1ad6b817,0x02dfb391,0x5ed8b80c,0x5968b80b, +0x1ad6b80b,0x02df6724,0x00ffb81b,0x820f001f, +0x8018fefe,0x8057ffff,0x001f2b09,0x8018fefa, +0x80d7ffff,0x001f2b08,0x8018fefc,0x8157ffff, +0x001f2b07,0x8018feff,0x81d7ffff,0x001f2b06, +0x8018fef8,0x802f001f,0x001f2b05,0x8018fefb, +0x00000000,0x001f2b04,0x8018fefd,0x00000000, +0x001f2b03,0x8018fef6,0x00000000,0x001f2b02, +0x8018fef9,0x00000000,0x001f2b01,0x8018fef7, +0x00000000,0x001f2b00,0x801b7c00,0x003f92c1, +0x5c28b801,0x005f92c2,0x5858b802,0x1821b802, +0x2000b801,0x001fb2c4,0x80187c04,0x003f0b09, +0x2000b801,0x001f2b14,0x82c70001,0x82e70001, +0x83070b10,0x8327001e,0x81970b35,0x83840016, +0x83270000,0x831bfef0,0x82f8fef4,0x02c7b819, +0x82170e28,0x83840065,0x300cb818,0xb4200002, +0x300bb817,0xb4000006,0x93390001,0xb0190020, +0xb480fff6,0x83270000,0x833cfef5,0x00ffb81b, +0x019fb390,0x017f2e44,0x033f2f25,0x83270001, +0x833cfef5,0x00ffb81b,0x0007b818,0x90000003, +0x00000000,0x015ff000,0x90000001,0x5949b80a, +0x013ff000,0x194ab809,0x84000002,0x994a0100, +0x017ff000,0x958b00f8,0x5981b80c,0x956b0007, +0x198cb80b,0x84000002,0x998c0008,0x017ff000, +0x90000001,0x5971b80b,0x198cb80b,0x017ff000, +0x5969b80b,0x198cb80b,0x81a70000,0x94d90003, +0x82a70000,0xb6260019,0xb6000818,0x5df0b80a, +0x5e02b80a,0x21efb810,0x95ef0001,0x5941b80a, +0x194ab80f,0x21efb816,0x5e18b80c,0x5e35b80c, +0x5e54b80c,0x5e6cb80c,0x2210b811,0x2252b813, +0x2210b812,0x96100001,0x5981b80c,0x198cb810, +0x2210b817,0x10afb810,0x10a5b80d,0x5da1b805, +0x94a50001,0x5aa1b815,0x1ab5b805,0x019fa7f5, +0x5cc2b819,0xb626001c,0x82870000,0xb6000419, +0xb6000818,0x5df0b80a,0x5e02b80a,0x21efb810, +0x95ef0001,0x5941b80a,0x194ab80f,0x21efb816, +0x5e18b80c,0x5e35b80c,0x5e54b80c,0x5e6cb80c, +0x2210b811,0x2252b813,0x2210b812,0x96100001, +0x5981b80c,0x198cb810,0x2210b817,0x10afb810, +0x10a5b80d,0x5da1b805,0x94a50001,0x5a81b814, +0x1a94b805,0x019fa7f4,0x00ffb81c,0x8257ffff, +0x808f0000,0x806f001f,0x80af001f,0x80270300, +0x81e778e0,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x80270340, +0x81e779e0,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x80270280, +0x81e77b00,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x806f0007, +0x80af0007,0x80270380,0x81e77ae0,0x5de2b80f, +0x00cfb801,0x01ffb178,0x59e2b80f,0x01cfb80f, +0x01ff9178,0xb520ffff,0x91ef0020,0x90210020, +0x80170b60,0x001f0b00,0x001fa020,0x001f0b01, +0x001fa020,0x001f0b02,0x001fa020,0x001f0b03, +0x001fa020,0x001f0b04,0x001fa000,0x80970b50, +0x81170b70,0x82a70b35,0x83a40060,0x001f87e4, +0xb6000405,0x86b50001,0x83a4005c,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b70,0x80170b50, +0x81170b50,0x81970b40,0x82a70b30,0x001f800c, +0x003f8008,0x2100a001,0x83a40050,0x001f87e4, +0xb6000405,0x86b50001,0x83a4004c,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b50,0x80170b70, +0x81170b70,0x81970b60,0x82a70b2b,0x001f800c, +0x003f8008,0x2100a001,0x83a40040,0x83a4004e, +0xb6000407,0x86b50001,0x83a4003c,0x001f8004, +0x003f87e8,0x2080a001,0x83a40047,0x00000000, +0x80970b70,0x80170b50,0x81170b50,0x81970b40, +0x82a70b26,0x001f800c,0x003f8008,0x2100a001, +0x83a4002e,0x83a4003c,0xb6000407,0x86b50001, +0x83a4002a,0x001f8004,0x003f87e8,0x2080a001, +0x83a40035,0x00000000,0x80970b50,0x80170b70, +0x81170b70,0x81970b60,0x82a70b21,0x001f800c, +0x003f8008,0x2100a001,0x83a4001c,0x001f87e4, +0xb6000405,0x86b50001,0x83a40018,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b70,0x80170b50, +0x81170b50,0x81970b40,0x82a70b1c,0x001f800c, +0x003f8008,0x2100a001,0x83a4000c,0x017f87e4, +0x81870000,0xb6000406,0x86b50001,0x83a40007, +0x001f87e4,0x200087e8,0x5988b80c,0x198cb800, +0x021fa02c,0x021fa00b,0x00ffb81c,0x005ff015, +0x90420a00,0x003f87e0,0x001ff002,0x2060b801, +0x90630c00,0x90960e00,0x001ff003,0x003ff004, +0x20a0b801,0x90a50d00,0x00000000,0x001ff005, +0x009fa000,0x00ffb81d,0x001f8004,0x5c21b800, +0x5847b800,0x1821b802,0x942100ff,0x2080a7e1, +0x00ffb81d,0x00000000,0x00000000,0x00000000, + +}; + +static u32 MPG240Ucode1f5c00[] = { +0x00000000,0xfffff8c0,0x00003540,0xffff8d40, +0x0001fd40,0xfffaf7c0,0x00066b80,0xffdb63c0, +0x00494780,0x00249c40,0x00066b80,0x00050840, +0x0001fd40,0x000072c0,0x00003540,0x00000740, +0xffffffc0,0xfffff840,0x00003680,0xffff7e40, +0x0001f400,0xfffa9cc0,0x0005d1c0,0xffd99600, +0x00493c00,0x0022ce00,0x0006f780,0x0004ad00, +0x000203c0,0x00006440,0x00003400,0x00000680, +0xffffffc0,0xfffff740,0x00003780,0xffff6ec0, +0x0001e800,0xfffa4240,0x00052a00,0xffd7ca00, +0x00491a00,0x0020ffc0,0x00077600,0x00045240, +0x00020800,0x000056c0,0x00003280,0x00000600, +0xffffffc0,0xfffff680,0x00003840,0xffff5ec0, +0x0001d940,0xfff9e8c0,0x00047440,0xffd60080, +0x0048e180,0x001f32c0,0x0007e700,0x0003f7c0, +0x000209c0,0x00004980,0x00003100,0x00000540, +0xffffffc0,0xfffff5c0,0x000038c0,0xffff4e40, +0x0001c780,0xfff990c0,0x0003b000,0xffd43ac0, +0x00489240,0x001d6800,0x00084b00,0x00039e40, +0x00020940,0x00003d00,0x00002f80,0x000004c0, +0xffffffc0,0xfffff4c0,0x00003900,0xffff3d40, +0x0001b2c0,0xfff93a40,0x0002ddc0,0xffd279c0, +0x00482d00,0x001ba040,0x0008a200,0x000345c0, +0x000206c0,0x00003140,0x00002dc0,0x00000440, +0xffffffc0,0xfffff3c0,0x00003900,0xffff2c00, +0x00019b00,0xfff8e640,0x0001fd40,0xffd0be80, +0x0047b1c0,0x0019dc80,0x0008ecc0,0x0002ef00, +0x00020240,0x00002640,0x00002c00,0x00000400, +0xffffff80,0xfffff2c0,0x000038c0,0xffff1a40, +0x00017fc0,0xfff894c0,0x00010e80,0xffcf09c0, +0x004720c0,0x00181d80,0x00092b40,0x000299c0, +0x0001fc00,0x00001bc0,0x00002a40,0x00000380, +0xffffff80,0xfffff180,0x00003800,0xffff0840, +0x00016180,0xfff84680,0x00001180,0xffcd5cc0, +0x00467a40,0x00166440,0x00095e00,0x00024680, +0x0001f440,0x00001200,0x00002840,0x00000340, +0xffffff80,0xfffff040,0x00003740,0xfffef600, +0x00014000,0xfff7fbc0,0xffff0680,0xffcbb880, +0x0045bf00,0x0014b140,0x00098580,0x0001f580, +0x0001ea80,0x00000900,0x00002680,0x000002c0, +0xffffff80,0xffffef00,0x000035c0,0xfffee3c0, +0x00011ac0,0xfff7b540,0xfffded80,0xffca1d80, +0x0044ef80,0x00130580,0x0009a1c0,0x0001a700, +0x0001dfc0,0x00000080,0x000024c0,0x00000280, +0xffffff40,0xffffedc0,0x00003400,0xfffed180, +0x0000f280,0xfff77340,0xfffcc700,0xffc88d80, +0x00440bc0,0x001161c0,0x0009b3c0,0x00015b00, +0x0001d380,0xfffff8c0,0x000022c0,0x00000240, +0xffffff40,0xffffec40,0x00003200,0xfffebf40, +0x0000c680,0xfff73680,0xfffb92c0,0xffc708c0, +0x00431500,0x000fc6c0,0x0009bb80,0x000111c0, +0x0001c640,0xfffff1c0,0x00002100,0x00000200, +0xffffff00,0xffffeac0,0x00002f40,0xfffead00, +0x00009740,0xfff6ff40,0xfffa5180,0xffc59080, +0x00420b40,0x000e3500,0x0009b9c0,0x0000cb80, +0x0001b7c0,0xffffeb40,0x00001f40,0x000001c0, +0xffffff00,0xffffe940,0x00002c40,0xfffe9b00, +0x00006480,0xfff6ce00,0xfff90380,0xffc425c0, +0x0040ef80,0x000cad00,0x0009af00,0x00008840, +0x0001a880,0xffffe580,0x00001d40,0x000001c0, +0xfffffec0,0xffffe7c0,0x000028c0,0xfffe8980, +0x00002e40,0xfff6a3c0,0xfff7a900,0xffc2c900, +0x003fc280,0x000b2fc0,0x00099b80,0x00004800, +0x00019880,0xffffe040,0x00001bc0,0x00000180, +0xfffffec0,0xffffe600,0x00002480,0xfffe7840, +0xfffff4c0,0xfff68040,0xfff64240,0xffc17b40, +0x003e84c0,0x0009bdc0,0x00097fc0,0x00000b40, +0x000187c0,0xffffdb80,0x00001a00,0x00000140, +0xfffffe80,0xffffe440,0x00001fc0,0xfffe6780, +0xffffb800,0xfff66480,0xfff4d040,0xffc03d80, +0x003d3700,0x00085700,0x00095c40,0xffffd1c0, +0x00017680,0xffffd740,0x00001840,0x00000140, +0xfffffe40,0xffffe2c0,0x00001a80,0xfffe5780, +0xffff77c0,0xfff65100,0xfff35300,0xffbf1080, +0x003bda40,0x0006fc80,0x00093200,0xffff9b80, +0x00016500,0xffffd3c0,0x000016c0,0x00000100, +0xfffffe40,0xffffe0c0,0x000014c0,0xfffe4840, +0xffff3480,0xfff64640,0xfff1cb00,0xffbdf4c0, +0x003a6f80,0x0005ae80,0x000900c0,0xffff68c0, +0x00015300,0xffffd0c0,0x00001540,0x00000100, +0xfffffe00,0xffffdf00,0x00000e40,0xfffe39c0, +0xfffeee40,0xfff64480,0xfff03940,0xffbceb00, +0x0038f740,0x00046d40,0x0008c980,0xffff3980, +0x000140c0,0xffffce00,0x000013c0,0x000000c0, +0xfffffdc0,0xffffdd40,0x00000740,0xfffe2c80, +0xfffea500,0xfff64c40,0xffee9e40,0xffbbf440, +0x00377280,0x00033900,0x00088cc0,0xffff0d80, +0x00012e80,0xffffcc00,0x00001240,0x000000c0, +0xfffffd80,0xffffdb40,0xffffff80,0xfffe2040, +0xfffe5900,0xfff65e40,0xffecfa80,0xffbb1080, +0x0035e280,0x00021280,0x00084ac0,0xfffee540, +0x00011c40,0xffffca40,0x00001100,0x00000080, +0xfffffd40,0xffffd980,0xfffff700,0xfffe1580, +0xfffe0a80,0xfff67a80,0xffeb4ec0,0xffba4100, +0x00344780,0x0000f980,0x00080440,0xfffec000, +0x00010a00,0xffffc8c0,0x00000fc0,0x00000080, +0xfffffcc0,0xffffd7c0,0xffffee00,0xfffe0bc0, +0xfffdb980,0xfff6a200,0xffe99bc0,0xffb985c0, +0x0032a340,0xffffee80,0x0007b980,0xfffe9e80, +0x0000f7c0,0xffffc800,0x00000e80,0x00000080, +0xfffffc80,0xffffd5c0,0xffffe440,0xfffe0400, +0xfffd6640,0xfff6d4c0,0xffe7e280,0xffb8df40, +0x0030f640,0xfffef180,0x00076b40,0xfffe8040, +0x0000e5c0,0xffffc740,0x00000d40,0x00000080, +0xfffffc00,0xffffd400,0xffffd9c0,0xfffdfdc0, +0xfffd1100,0xfff71340,0xffe62380,0xffb84e40, +0x002f4180,0xfffe02c0,0x000719c0,0xfffe6500, +0x0000d400,0xffffc700,0x00000c40,0x00000040, +0xfffffbc0,0xffffd240,0xffffcec0,0xfffdf940, +0xfffcba40,0xfff75e00,0xffe45fc0,0xffb7d300, +0x002d8640,0xfffd2240,0x0006c5c0,0xfffe4d40, +0x0000c2c0,0xffffc700,0x00000b40,0x00000040, +0xfffffb40,0xffffd080,0xffffc300,0xfffdf6c0, +0xfffc61c0,0xfff7b500,0xffe29800,0xffb76dc0, +0x002bc540,0xfffc5000,0x00066f40,0xfffe3880, +0x0000b1c0,0xffffc740,0x00000a40,0x00000040, +0xfffffac0,0xffffcf00,0xffffb680,0xfffdf640, +0xfffc0840,0xfff81900,0xffe0cd40,0xffb71e80, +0x0029ff80,0xfffb8bc0,0x00061740,0xfffe26c0, +0x0000a140,0xffffc7c0,0x00000980,0x00000040, +0xfffffa00,0xffffcd80,0xffffa940,0xfffdf800, +0xfffbadc0,0xfff88a00,0xffdf0040,0xffb6e600, +0x00283600,0xfffad600,0x0005bdc0,0xfffe1800, +0x00009140,0xffffc880,0x000008c0,0x00000040, +0xfffff980,0xffffcc00,0xffff9bc0,0xfffdfc40, +0xfffb5300,0xfff90880,0xffdd3200,0xffb6c400, +0x00266a00,0xfffa2e40,0x00056340,0xfffe0c00, +0x000081c0,0xffffc980,0x000007c0,0x00000040, +0x004013c2,0x0040b346,0x0041fa2d,0x0043f934, +0x0046cc1c,0x004a9d9d,0x004fae37,0x0056601f, +0x005f4cf7,0x006b6fcf,0x007c7d1e,0x0115b035, +0x013df91b,0x0207655e,0x03342c83,0x0a185230, +0x00404f46,0x0042e13c,0x0048919f,0x0052cb0e, +0x0064e240,0x0107c449,0x015c7926,0x050cf270, +0x004140fb,0x004cf8df,0x0073326c,0x02480d9d, +0x004545ea,0x01273d75,0x005a827a,0x007fffff, +0x006597fb,0x0050a28c,0x00400000,0x0032cbfd, +0x00285146,0x00200000,0x001965ff,0x001428a3, +0x00100000,0x000cb2ff,0x000a1451,0x00080000, +0x00065980,0x00050a29,0x00040000,0x00032cc0, +0x00028514,0x00020000,0x00019660,0x0001428a, +0x00010000,0x0000cb30,0x0000a145,0x00008000, +0x00006598,0x000050a3,0x00004000,0x000032cc, +0x00002851,0x00002000,0x00001966,0x00001429, +0x00001000,0x00000cb3,0x00000a14,0x00000800, +0x00000659,0x0000050a,0x00000400,0x0000032d, +0x00000285,0x00000200,0x00000196,0x00000143, +0x00000100,0x000000cb,0x000000a1,0x00000080, +0x00000066,0x00000051,0x00000040,0x00000033, +0x00000028,0x00000020,0x00000019,0x00000014, +0x00000010,0x0000000d,0x0000000a,0x00000008, +0x00000006,0x00000005,0x00000000,0x00555555, +0x00666666,0x00492492,0x0071c71c,0x00444444, +0x00421084,0x00410410,0x00408102,0x00404040, +0x00402010,0x00401004,0x00400801,0x00400400, +0x00400200,0x00400100,0x00400080,0x00400040, +0x00400000,0x00400000,0x00200000,0x00400000, +0x00100000,0x00080000,0x00040000,0x00020000, +0x00010000,0x00008000,0x00004000,0x00002000, +0x00001000,0x00000800,0x00000400,0x00000200, +0x00000100,0x0003588d,0x0002b15e,0x0002056d, +0x00015600,0x0000a329,0xffffeed9,0xffff3960, +0xfffe8423,0xfffdd11c,0xfffd2048,0xfffc7353, +0xfffbcb6f,0xfffb29a6,0xfffa8f15,0x000494ae, +0x0003f991,0x00032dd1,0xfffd2d8f,0x0001eb47, +0xfffe9968,0x00009af6,0x000011de,0xffff4335, +0x00018d69,0xfffdecd4,0x000302f8,0xfffca0d7, +0x0004683d,0xfffb67f8,0x0005b36d,0x00045963, +0xfffbd51e,0x00030062,0xfffd0dee,0x0001d046, +0xfffe8a0a,0x00009258,0x000012b1,0xffff4d9e, +0x00019ec3,0xfffe0a44,0x0003245a,0xfffcd082, +0x000498f0,0xfffba919,0x0005f304,0x00041bf4, +0xfffba72a,0x0002d19e,0xfffcf060,0x0001b407, +0xfffe7c08,0x0000894a,0x0000138d,0xffff58ac, +0x0001afaf,0xfffe28fe,0x000343bf,0xfffd026f, +0x0004c6f6,0xfffbed06,0x00062e61,0x0003dc0e, +0xfffb7bf1,0x0002a17f,0xfffcd522,0x000196a0, +0xfffe6e70,0x00007ff6,0x00001439,0xffff63f6, +0x0001beb3,0xfffe4882,0x0003616d,0xfffd361b, +0x0004f1cf,0xfffc332a,0x0006658f,0x00039943, +0xfffb52c0,0x00026ec7,0xfffcbb94,0x0001789f, +0xfffe6160,0x00007677,0x000014d4,0xffff6f74, +0x0001cc9b,0xfffe694f,0x00037cbf,0xfffd6b41, +0x000519c2,0xfffc7baf,0x00069971,0x00035486, +0xfffb2d0c,0x00023ad8,0xfffca3ee,0x00015989, +0xfffe55af,0x00006ca7,0x00001570,0xffff7b71, +0x0001d9cb,0xfffe8b46,0x0003959e,0xfffda1fe, +0x00053ee6,0xfffcc6b4,0x0006c950,0x00030e08, +0xfffb0a7a,0x0002061e,0xfffc8ec0,0x00013911, +0xfffe4b1d,0x00006278,0x000015e8,0xffff87b6, +0x0001e577,0xfffeadd6,0x0003acc2,0xfffdda34, +0x00056059,0xfffd136d,0x0006f4b5,0x0002c562, +0xfffaea7c,0x0001cfa6,0xfffc7b14,0x0001182b, +0xfffe4159,0x00005817,0x0000165c,0xffff9417, +0x0001f00f,0xfffed14c,0x0003c199,0xfffe13f6, +0x00057e83,0xfffd61cd,0x00071ba1,0x00027ab5, +0xfffacdc3,0x00019833,0xfffc6989,0x0000f6ca, +0xfffe38da,0x00004d9d,0x000016ef,0xffffa103, +0x0001f98f,0xfffef5c0,0x0003d3d1,0xfffe4f00, +0x0005998c,0xfffdb21e,0x00073e77,0x00022e75, +0xfffab482,0x00015fd1,0xfffc5b13,0x0000d45d, +0xfffe318f,0x000042ed,0x0000176b,0xffffae8f, +0x0002018f,0xffff1a91,0x0003e40c,0xfffe8af2, +0x0005b0ca,0xfffe03b8,0x00075d14,0x0001e141, +0xfffa9e9b,0x0001262a,0xfffc4e31,0x0000b1af, +0xfffe2b26,0x00003805,0x000017b1,0xffffbc21, +0x000208b8,0xffff3fb6,0x0003f1d7,0xfffec7af, +0x0005c4c5,0xfffe5654,0x0007768a,0x000192fe, +0xfffa8bb0,0x0000ec3f,0xfffc4365,0x00008ec9, +0xfffe25f0,0x00002d05,0x000017ec,0xffffc984, +0x00020ec6,0xffff658d,0x0003fcba,0xffff0500, +0x0005d576,0xfffeaa37,0x00078bc6,0x00014367, +0xfffa7bec,0x0000b1f4,0xfffc3b82,0x00006b06, +0xfffe2201,0x000021eb,0x00001823,0xffffd704, +0x0002132a,0xffff8be7,0x00040534,0xffff4315, +0x0005e22e,0xfffeff0a,0x00079ce3,0x0000f33f, +0xfffa6fc9,0x000076ca,0xfffc3558,0x00004762, +0xfffe1ef3,0x000016a1,0x0000183f,0xffffe4a6, +0x00021664,0xffffb27d,0x00040b7b,0xffff81e5, +0x0005eb4e,0xffff5475,0x0007a857,0x0000a2cb, +0xfffa671b,0x00003b64,0xfffc31e2,0x00002416, +0xfffe1ce1,0x00000b46,0x00001850,0xfffff24d, +0x00021855,0xffffd93a,0x00040f75,0xffffc0e6, +0x0005f0e3,0xffffaa3e,0x0007af45,0x0000519f, +0xfffa6218,0x0003f991,0x0003588d,0x0002b15e, +0x0002056d,0x00015600,0x0000a329,0xffffeed9, +0xffff3960,0xfffe8423,0xfffdd11c,0xfffd2048, +0xfffc7353,0xfffbcb6f,0xfffb29a6,0xfffa8f15, +0x000494ae,0x0003c6b0,0xfffc7e8b,0x00028ef6, +0xfffde181,0x000144eb,0xffff5500,0xffffefb9, +0x0000d01d,0xfffe9755,0x000249a4,0xfffd453c, +0x0003b80e,0xfffc01aa,0x000511d6,0xfffad527, +0xfffb334e,0x0003916c,0xfffc5778,0x00026a92, +0xfffdc9f5,0x00013314,0xffff4d99,0xfffff0b6, +0x0000d911,0xfffeab80,0x00026369,0xfffd6c0a, +0x0003e17f,0xfffc39d8,0x000549df,0xfffb1eb2, +0xfffafe6c,0x00035929,0xfffc3321,0x000244a6, +0xfffdb402,0x00012035,0xffff46ac,0xfffff192, +0x0000e16a,0xfffebfe0,0x00027b3d,0xfffd9433, +0x0004087b,0xfffc74b7,0x00057e8d,0xfffb6a81, +0xfffacc1c,0x00031fbe,0xfffc10df,0x00021e0c, +0xfffd9f6d,0x00010cb7,0xffff402e,0xfffff279, +0x0000e965,0xfffed574,0x00029159,0xfffdbdc4, +0x00042c4c,0xfffcb1e7,0x0005b02d,0xfffbb942, +0xfffa9d38,0x0002e44a,0xfffbf0fd,0x0001f5b4, +0xfffd8c38,0x0000f8b1,0xffff3a21,0xfffff391, +0x0000f0e6,0xfffeec44,0x0002a642,0xfffde90e, +0x00044e32,0xfffcf0fb,0x0005de46,0xfffc0b18, +0xfffa71d1,0x0002a659,0xfffbd3de,0x0001cb90, +0xfffd7a97,0x0000e403,0xffff3490,0xfffff49c, +0x0000f7a8,0xffff0340,0x0002b95f,0xfffe1573, +0x00046dbe,0xfffd3284,0x00060888,0xfffc5f51, +0xfffa4996,0x00026786,0xfffbb8df,0x0001a0e1, +0xfffd6a4e,0x0000ced2,0xffff2f75,0xfffff593, +0x0000fdbe,0xffff1a53,0x0002ca87,0xfffe42f5, +0x0004898a,0xfffd7563,0x00062f0b,0xfffcb5de, +0xfffa2508,0x00022713,0xfffba0bf,0x0001754a, +0xfffd5b5f,0x0000b92c,0xffff2acd,0xfffff6b0, +0x0001034f,0xffff3241,0x0002da5c,0xfffe71c6, +0x0004a341,0xfffdb946,0x000651e8,0xfffd0e37, +0xfffa0402,0x0001e4d4,0xfffb8b9c,0x00014898, +0xfffd4e7d,0x0000a304,0xffff26b7,0xfffff7e1, +0x00010846,0xffff4b34,0x0002e897,0xfffea13f, +0x0004ba63,0xfffdff2d,0x00067115,0xfffd6839, +0xfff9e680,0x0001a1fa,0xfffb789e,0x00011b2e, +0xfffd43a4,0x00008c6e,0xffff2341,0xfffff8fd, +0x00010c9c,0xffff6469,0x0002f48f,0xfffed1a4, +0x0004cd6a,0xfffe4608,0x00068c1b,0xfffdc409, +0xfff9cd15,0x00015dfe,0xfffb68a0,0x0000ecee, +0xfffd3a2e,0x0000757d,0xffff204b,0xfffffa1e, +0x00011054,0xffff7da1,0x0002fe9c,0xffff033e, +0x0004de57,0xfffe8dc6,0x0006a2d5,0xfffe213e, +0xfff9b77d,0x000118d3,0xfffb5bde,0x0000be25, +0xfffd3224,0x00005e52,0xffff1dc1,0xfffffb4b, +0x00011353,0xffff9740,0x00030748,0xffff351c, +0x0004ec95,0xfffed755,0x0006b5b4,0xfffe7fc6, +0xfff9a599,0x0000d334,0xfffb519f,0x00008f08, +0xfffd2bbf,0x00004704,0xffff1bc1,0xfffffc71, +0x00011598,0xffffb135,0x00030e43,0xffff6720, +0x0004f6f3,0xffff2119,0x0006c46e,0xfffedf38, +0xfff997c7,0x00008d13,0xfffb4a55,0x00005fa5, +0xfffd273b,0x00002f76,0xffff1a63,0xfffffda0, +0x00011744,0xffffcb67,0x000312ff,0xffff99cf, +0x0004ff0c,0xffff6a9c,0x0006cebd,0xffff3f0a, +0xfff98dbe,0x00004691,0xfffb4620,0x00003010, +0xfffd24fc,0x000017b5,0xffff199d,0xfffffed8, +0x0001185a,0xffffe5c6,0x0003157e,0xffffcce3, +0x000503ae,0xffffb515,0x0006d537,0xffff9f5a, +0xfff98767,0xfffb44b0,0xfffc3131,0xfffd2475, +0xfffe1c28,0xffff195d,0x00001859,0x000118bd, +0x000218df,0x0003163a,0x000410e0,0x000504a7, +0x0005f2b3,0x0006d796,0x0007b1fe,0xfff98537, +0xfffa609b,0xfffc7e8b,0x00028ef6,0xfffde181, +0x000144eb,0xffff5500,0xffffefb9,0x0000d01d, +0xfffe9755,0x000249a4,0xfffd453c,0x0003b80e, +0xfffc01aa,0x000511d6,0xfffad527,0xfffb334e, +0x0003c6b0,0xfffc5778,0x00026a92,0xfffdc9f5, +0x00013314,0xffff4d99,0xfffff0b6,0x0000d911, +0xfffeab80,0x00026369,0xfffd6c0a,0x0003e17f, +0xfffc39d8,0x000549df,0xfffb1eb2,0xfffafe6c, +0x0003916c,0xfffc3321,0x000244a6,0xfffdb402, +0x00012035,0xffff46ac,0xfffff192,0x0000e16a, +0xfffebfe0,0x00027b3d,0xfffd9433,0x0004087b, +0xfffc74b7,0x00057e8d,0xfffb6a81,0xfffacc1c, +0x00035929,0xfffc10df,0x00021e0c,0xfffd9f6d, +0x00010cb7,0xffff402e,0xfffff279,0x0000e965, +0xfffed574,0x00029159,0xfffdbdc4,0x00042c4c, +0xfffcb1e7,0x0005b02d,0xfffbb942,0xfffa9d38, +0x00031fbe,0xfffbf0fd,0x0001f5b4,0xfffd8c38, +0x0000f8b1,0xffff3a21,0xfffff391,0x0000f0e6, +0xfffeec44,0x0002a642,0xfffde90e,0x00044e32, +0xfffcf0fb,0x0005de46,0xfffc0b18,0xfffa71d1, +0x0002e44a,0xfffbd3de,0x0001cb90,0xfffd7a97, +0x0000e403,0xffff3490,0xfffff49c,0x0000f7a8, +0xffff0340,0x0002b95f,0xfffe1573,0x00046dbe, +0xfffd3284,0x00060888,0xfffc5f51,0xfffa4996, +0x0002a659,0xfffbb8df,0x0001a0e1,0xfffd6a4e, +0x0000ced2,0xffff2f75,0xfffff593,0x0000fdbe, +0xffff1a53,0x0002ca87,0xfffe42f5,0x0004898a, +0xfffd7563,0x00062f0b,0xfffcb5de,0xfffa2508, +0x00026786,0xfffba0bf,0x0001754a,0xfffd5b5f, +0x0000b92c,0xffff2acd,0xfffff6b0,0x0001034f, +0xffff3241,0x0002da5c,0xfffe71c6,0x0004a341, +0xfffdb946,0x000651e8,0xfffd0e37,0xfffa0402, +0x00022713,0xfffb8b9c,0x00014898,0xfffd4e7d, +0x0000a304,0xffff26b7,0xfffff7e1,0x00010846, +0xffff4b34,0x0002e897,0xfffea13f,0x0004ba63, +0xfffdff2d,0x00067115,0xfffd6839,0xfff9e680, +0x0001e4d4,0xfffb789e,0x00011b2e,0xfffd43a4, +0x00008c6e,0xffff2341,0xfffff8fd,0x00010c9c, +0xffff6469,0x0002f48f,0xfffed1a4,0x0004cd6a, +0xfffe4608,0x00068c1b,0xfffdc409,0xfff9cd15, +0x0001a1fa,0xfffb68a0,0x0000ecee,0xfffd3a2e, +0x0000757d,0xffff204b,0xfffffa1e,0x00011054, +0xffff7da1,0x0002fe9c,0xffff033e,0x0004de57, +0xfffe8dc6,0x0006a2d5,0xfffe213e,0xfff9b77d, +0x00015dfe,0xfffb5bde,0x0000be25,0xfffd3224, +0x00005e52,0xffff1dc1,0xfffffb4b,0x00011353, +0xffff9740,0x00030748,0xffff351c,0x0004ec95, +0xfffed755,0x0006b5b4,0xfffe7fc6,0xfff9a599, +0x000118d3,0xfffb519f,0x00008f08,0xfffd2bbf, +0x00004704,0xffff1bc1,0xfffffc71,0x00011598, +0xffffb135,0x00030e43,0xffff6720,0x0004f6f3, +0xffff2119,0x0006c46e,0xfffedf38,0xfff997c7, +0x0000d334,0xfffb4a55,0x00005fa5,0xfffd273b, +0x00002f76,0xffff1a63,0xfffffda0,0x00011744, +0xffffcb67,0x000312ff,0xffff99cf,0x0004ff0c, +0xffff6a9c,0x0006cebd,0xffff3f0a,0xfff98dbe, +0x00008d13,0xfffb4620,0x00003010,0xfffd24fc, +0x000017b5,0xffff199d,0xfffffed8,0x0001185a, +0xffffe5c6,0x0003157e,0xffffcce3,0x000503ae, +0xffffb515,0x0006d537,0xffff9f5a,0xfff98767, +0x00004691,0xfffa609b,0xfffb44b0,0xfffc3131, +0xfffd2475,0xfffe1c28,0xffff195d,0x00001859, +0x000118bd,0x000218df,0x0003163a,0x000410e0, +0x000504a7,0x0005f2b3,0x0006d796,0x0007b1fe, +0xfff98537,0xfffbd51e,0x00032dd1,0xfffd2d8f, +0x0001eb47,0xfffe9968,0x00009af6,0x000011de, +0xffff4335,0x00018d69,0xfffdecd4,0x000302f8, +0xfffca0d7,0x0004683d,0xfffb67f8,0x0005b36d, +0x00045963,0xfffba72a,0x00030062,0xfffd0dee, +0x0001d046,0xfffe8a0a,0x00009258,0x000012b1, +0xffff4d9e,0x00019ec3,0xfffe0a44,0x0003245a, +0xfffcd082,0x000498f0,0xfffba919,0x0005f304, +0x00041bf4,0xfffb7bf1,0x0002d19e,0xfffcf060, +0x0001b407,0xfffe7c08,0x0000894a,0x0000138d, +0xffff58ac,0x0001afaf,0xfffe28fe,0x000343bf, +0xfffd026f,0x0004c6f6,0xfffbed06,0x00062e61, +0x0003dc0e,0xfffb52c0,0x0002a17f,0xfffcd522, +0x000196a0,0xfffe6e70,0x00007ff6,0x00001439, +0xffff63f6,0x0001beb3,0xfffe4882,0x0003616d, +0xfffd361b,0x0004f1cf,0xfffc332a,0x0006658f, +0x00039943,0xfffb2d0c,0x00026ec7,0xfffcbb94, +0x0001789f,0xfffe6160,0x00007677,0x000014d4, +0xffff6f74,0x0001cc9b,0xfffe694f,0x00037cbf, +0xfffd6b41,0x000519c2,0xfffc7baf,0x00069971, +0x00035486,0xfffb0a7a,0x00023ad8,0xfffca3ee, +0x00015989,0xfffe55af,0x00006ca7,0x00001570, +0xffff7b71,0x0001d9cb,0xfffe8b46,0x0003959e, +0xfffda1fe,0x00053ee6,0xfffcc6b4,0x0006c950, +0x00030e08,0xfffaea7c,0x0002061e,0xfffc8ec0, +0x00013911,0xfffe4b1d,0x00006278,0x000015e8, +0xffff87b6,0x0001e577,0xfffeadd6,0x0003acc2, +0xfffdda34,0x00056059,0xfffd136d,0x0006f4b5, +0x0002c562,0xfffacdc3,0x0001cfa6,0xfffc7b14, +0x0001182b,0xfffe4159,0x00005817,0x0000165c, +0xffff9417,0x0001f00f,0xfffed14c,0x0003c199, +0xfffe13f6,0x00057e83,0xfffd61cd,0x00071ba1, +0x00027ab5,0xfffab482,0x00019833,0xfffc6989, +0x0000f6ca,0xfffe38da,0x00004d9d,0x000016ef, +0xffffa103,0x0001f98f,0xfffef5c0,0x0003d3d1, +0xfffe4f00,0x0005998c,0xfffdb21e,0x00073e77, +0x00022e75,0xfffa9e9b,0x00015fd1,0xfffc5b13, +0x0000d45d,0xfffe318f,0x000042ed,0x0000176b, +0xffffae8f,0x0002018f,0xffff1a91,0x0003e40c, +0xfffe8af2,0x0005b0ca,0xfffe03b8,0x00075d14, +0x0001e141,0xfffa8bb0,0x0001262a,0xfffc4e31, +0x0000b1af,0xfffe2b26,0x00003805,0x000017b1, +0xffffbc21,0x000208b8,0xffff3fb6,0x0003f1d7, +0xfffec7af,0x0005c4c5,0xfffe5654,0x0007768a, +0x000192fe,0xfffa7bec,0x0000ec3f,0xfffc4365, +0x00008ec9,0xfffe25f0,0x00002d05,0x000017ec, +0xffffc984,0x00020ec6,0xffff658d,0x0003fcba, +0xffff0500,0x0005d576,0xfffeaa37,0x00078bc6, +0x00014367,0xfffa6fc9,0x0000b1f4,0xfffc3b82, +0x00006b06,0xfffe2201,0x000021eb,0x00001823, +0xffffd704,0x0002132a,0xffff8be7,0x00040534, +0xffff4315,0x0005e22e,0xfffeff0a,0x00079ce3, +0x0000f33f,0xfffa671b,0x000076ca,0xfffc3558, +0x00004762,0xfffe1ef3,0x000016a1,0x0000183f, +0xffffe4a6,0x00021664,0xffffb27d,0x00040b7b, +0xffff81e5,0x0005eb4e,0xffff5475,0x0007a857, +0x0000a2cb,0xfffa6218,0x00003b64,0xfffc31e2, +0x00002416,0xfffe1ce1,0x00000b46,0x00001850, +0xfffff24d,0x00021855,0xffffd93a,0x00040f75, +0xffffc0e6,0x0005f0e3,0xffffaa3e,0x0007af45, +0x0000519f,0x00030000,0x000f0007,0x003f001f, +0x00ff007f,0x03ff01ff,0x0fff07ff,0x3fff1fff, +0xffff7fff,0x00030000,0x00070005,0x000f0009, +0x003f001f,0x00ff007f,0x03ff01ff,0x0fff07ff, +0xffff1fff,0x00030000,0x00070005,0x000f0009, +0xffff001f,0x00030000,0xffff0005,0x04030504, +0x08070605,0x0c0b0a09,0x100f0e0d,0x03070504, +0x0605040a,0x0a090807,0x100d0c0b,0x03070503, +0x1005040a,0x10070502,0x03030100,0x03030303, +0x03030303,0x03030303,0x03010100,0x03030301, +0x03030303,0x03030303,0x03010100,0x03030301, +0x03010100,0x04020000,0x08070605,0x0c0b0a09, +0x100f0e0d,0x02010000,0x06050403,0x0a090807, +0x100d0c0b,0x02010000,0x10050403,0x10010000, +0x00030000,0x00090005,0x001f000f,0x007f003f, +0x01ff00ff,0x07ff03ff,0x1fff0fff,0x7fff3fff, +0x00030000,0x00090005,0x001f000f,0x007f003f, +0x0a070504,0x07060504,0x0b0a0908,0x0f0e0d0c, +0x0a070503,0x07060504,0x01010100,0x03030303, +0x03030303,0x03030303,0x01010100,0x03030303, +0x03010000,0x07060504,0x0b0a0908,0x0f0e0d0c, +0x03010000,0x07060504,0x00555555,0x002aaaab, +0x00249249,0x00124925,0x00111111,0x00088889, +0x00084210,0x00421084,0x00041041,0x00020821, +0x00020408,0x00081020,0x00010101,0x00008081, +0x00008040,0x00100804,0x00004010,0x00020080, +0x00002004,0x00004008,0x00001001,0x00000801, +0x00000800,0x00200100,0x00000400,0x00080020, +0x00000200,0x00020004,0x00200000,0x00600040, +0x00a00080,0x00e000c0,0x01200100,0x01600140, +0x01a00180,0x000001c0,0x00300020,0x00400038, +0x00600050,0x00800070,0x00c000a0,0x010000e0, +0x01800140,0x00200000,0x00300028,0x00400038, +0x00600050,0x00800070,0x00c000a0,0x010000e0, +0x00000140,0x00900000,0x00fc00d8,0x01680120, +0x01f801b0,0x02d00240,0x03f00360,0x05a00480, +0x000006c0,0x00680000,0x00b6009c,0x010500d0, +0x016d0139,0x020a01a1,0x02db0272,0x04140343, +0x000004e5,0x006c0000,0x00bd00a2,0x010e00d8, +0x017a0144,0x006301b0,0x013b00cf,0x00c601a7, +0x0000019e,0x00600000,0x00a80090,0x00f000c0, +0x01500120,0x01e00180,0x02a00240,0x03c00300, +0x00000480,0x10000000,0x10101010,0x20101010, +0x20202020,0x20202020,0x28202020,0x28282828, +0x00002828,0x10100000,0x10101010,0x10101010, +0x00000000,0x00000000,0x00000000,0x00000000, +0xcbcecdc4,0xcfcac9c8,0xc3c6c5cc,0xc7c2c1c0, +0x1b1e1d14,0x1f1a1918,0x1316151c,0x17121110, +0x2b2e2d24,0x2f2a2928,0x2326252c,0x27222120, +0x3b3e3d34,0x3f3a3938,0x3336353c,0x37323130, +0x0b0e0d04,0x0f0a0908,0x0306050c,0x07020100, +0xdbdeddd4,0xdfdad9d8,0xd3d6d5dc,0xd7d2d1d0, +0xebeeede4,0xefeae9e8,0xe3e6e5ec,0xe7e2e1e0, +0xfbfefdf4,0xfffaf9f8,0xf3f6f5fc,0xf7f2f1f0, +0x4b4e4d44,0x4f4a4948,0x4346454c,0x47424140, +0x9b9e9d94,0x9f9a9998,0x9396959c,0x97929190, +0xabaeada4,0xafaaa9a8,0xa3a6a5ac,0xa7a2a1a0, +0xbbbebdb4,0xbfbab9b8,0xb3b6b5bc,0xb7b2b1b0, +0x8b8e8d84,0x8f8a8988,0x8386858c,0x87828180, +0x5b5e5d54,0x5f5a5958,0x5356555c,0x57525150, +0x6b6e6d64,0x6f6a6968,0x6366656c,0x67626160, +0x7b7e7d74,0x7f7a7978,0x7376757c,0x77727170, +0x341424c4,0x3e1e2ece,0x3d1d2dcd,0x3b1b2bcb, +0xb494a444,0xbe9eae4e,0xbd9dad4d,0xbb9bab4b, +0xf4d4e404,0xfedeee0e,0xfddded0d,0xfbdbeb0b, +0x74546484,0x7e5e6e8e,0x7d5d6d8d,0x7b5b6b8b, +0x3c1c2ccc,0x361626c6,0x351525c5,0x331323c3, +0xbc9cac4c,0xb696a646,0xb595a545,0xb393a343, +0xfcdcec0c,0xf6d6e606,0xf5d5e505,0xf3d3e303, +0x7c5c6c8c,0x76566686,0x75556585,0x73536383, +0x381828c8,0x3a1a2aca,0x391929c9,0x3f1f2fcf, +0xb898a848,0xba9aaa4a,0xb999a949,0xbf9faf4f, +0xf8d8e808,0xfadaea0a,0xf9d9e909,0xffdfef0f, +0x78586888,0x7a5a6a8a,0x79596989,0x7f5f6f8f, +0x301020c0,0x321222c2,0x311121c1,0x371727c7, +0xb090a040,0xb292a242,0xb191a141,0xb797a747, +0xf0d0e000,0xf2d2e202,0xf1d1e101,0xf7d7e707, +0x70506080,0x72526282,0x71516181,0x77576787, +0x05040100,0x15141110,0x25242120,0x35343130, +0x85848180,0x95949190,0xa5a4a1a0,0xb5b4b1b0, +0xc0408000,0xe060a020,0xd0509010,0xf070b030, +0xc8488808,0xe868a828,0xd8589818,0xf878b838, +0xc4448404,0xe464a424,0xd4549414,0xf474b434, +0xcc4c8c0c,0xec6cac2c,0xdc5c9c1c,0xfc7cbc3c, +0xc2428202,0xe262a222,0xd2529212,0xf272b232, +0xca4a8a0a,0xea6aaa2a,0xda5a9a1a,0xfa7aba3a, +0xc6468606,0xe666a626,0xd6569616,0xf676b636, +0xce4e8e0e,0xee6eae2e,0xde5e9e1e,0xfe7ebe3e, +0xc1418101,0xe161a121,0xd1519111,0xf171b131, +0xc9498909,0xe969a929,0xd9599919,0xf979b939, +0xc5458505,0xe565a525,0xd5559515,0xf575b535, +0xcd4d8d0d,0xed6dad2d,0xdd5d9d1d,0xfd7dbd3d, +0xc3438303,0xe363a323,0xd3539313,0xf373b333, +0xcb4b8b0b,0xeb6bab2b,0xdb5b9b1b,0xfb7bbb3b, +0xc7478707,0xe767a727,0xd7579717,0xf777b737, +0xcf4f8f0f,0xef6faf2f,0xdf5f9f1f,0xff7fbf3f, +0x1045a3e2,0x000000f4,0x263b7333,0x766b2363, +0x2b367e3e,0x7b662e6e,0x06db93d3,0x964b0343, +0x0bd69ede,0x9b460e4e,0x825f1757,0x12cf87c7, +0x8f521a5a,0x1fc28aca,0x00d199d9,0x90410949, +0x01d098d8,0x91400848,0x24357d3d,0x74652d6d, +0x25347c3c,0x75642c6c,0x04d59ddd,0x94450d4d, +0x05d49cdc,0x95440c4c,0x80511959,0x10c189c9, +0x81501858,0x11c088c8,0x02df97d7,0x924f0747, +0x0fd29ada,0x9f420a4a,0x865b1353,0x16cb83c3, +0x8b561e5e,0x1bc68ece,0xa6bbf3b3,0xf6eba3e3, +0xabb6febe,0xfbe6aeee,0x223f7737,0x726f2767, +0x2f327a3a,0x7f622a6a,0xa0b1f9b9,0xf0e1a9e9, +0xa1b0f8b8,0xf1e0a8e8,0x84551d5d,0x14c58dcd, +0x85541c5c,0x15c48ccc,0xa4b5fdbd,0xf4e5aded, +0xa5b4fcbc,0xf5e4acec,0x20317939,0x70612969, +0x21307838,0x71602868,0xa2bff7b7,0xf2efa7e7, +0xafb2faba,0xffe2aaea,0x00000000,0x00000000, + +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/mpg.h linux.20pre2-ac1/drivers/media/video/ls220/mpg.h --- linux.20pre2/drivers/media/video/ls220/mpg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/mpg.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1612 @@ +static u32 MPGUcode1f1800[] = { +0x820f001f,0x802f001f,0x81df0000,0xb500000c, +0x00ffb81e,0x00000000,0x00000000,0x00000000, +0x00ffb81e,0x00000000,0x00000000,0x00000000, +0xb5000c13,0x00000000,0x00000000,0x00000000, +0x80070800,0x001f6047,0x8013001f,0x90208000, +0x003fb174,0x803effe8,0x803effec,0x9020fa00, +0x803effd0,0x803effdc,0x803effd8,0x9020fe00, +0x803effd4,0x805bff7c,0x802500d4,0x94020080, +0xb0000000,0xb4200023,0x8013ffcf,0x9800cfff, +0x80730030,0x98631000,0x94420007,0xb0020002, +0xb4200005,0x8013ffc7,0x9800c7ff,0x80730038, +0x98631000,0xb5000006,0xb0020001,0xb4200004, +0x8013ffcf,0x9800cfff,0x80730030,0x98631000, +0x1421b800,0x1821b803,0x802600d4,0x8033001f, +0x98210000,0x802600a2,0x8033001f,0x98210300, +0x802600a3,0x80270225,0x80530001,0x98420100, +0x1821b802,0x80530200,0x98420000,0x804600a6, +0xb500001d,0x805bff7c,0x8013ffcf,0x9800cfff, +0x80730030,0x98631000,0x94420007,0xb0020002, +0xb4200005,0x8013ffc7,0x9800c7ff,0x80730038, +0x98631000,0xb5000006,0xb0020001,0xb4200004, +0x8013ffcf,0x9800cfff,0x80730030,0x98631000, +0x1421b800,0x1821b803,0x802600d4,0x8033001f, +0x98210000,0x802600a2,0x8033001f,0x98210300, +0x802600a3,0x80270c25,0x802600a1,0x80270002, +0x803eff84,0x80070000,0x801effc0,0x801effc4, +0x801effc8,0x801effcc,0x801eff88,0x80770000, +0x8057ffff,0x80170080,0x80070000,0xb6003f02, +0xb6002001,0x001fa020,0x8007ffff,0x801eff84, +0x80070001,0x001f25dc,0x001f20b1,0x80070000, +0x001f6046,0x001fb17c,0x001fb17d,0x80070000, +0x801e78d0,0x98004000,0x001f62ea,0x80070100, +0x801efff0,0x81df0004,0x00000000,0x00000000, +0x801bfff0,0x00000000,0x940000ff,0xb0000000, +0xb420005b,0x003f42ea,0x94010010,0xb0000000, +0xb400fff7,0x003f05dc,0xb0010001,0xb4200034, +0x803bffe8,0x801bffec,0x00000000,0x3001b800, +0xb4600001,0x90214000,0x0421b800,0xb0010800, +0xb460000d,0x80050086,0x005f902e,0xb0020000, +0xb4200002,0x001fb02e,0xb5000006,0x0420b802, +0xb0010930,0xb4a0ffe2,0x80070000,0x001fb02e, +0x83e40162,0xb500ffde,0x83e40129,0x80070000, +0x001fb02e,0x001f42ea,0x9400000f,0xb0000000, +0xb4000010,0x9400fff0,0x001f62ea,0x003f9174, +0x9421ffff,0x90210004,0xb001c000,0xb4800002, +0x8421c000,0x90218000,0x8013001f,0x1821b800, +0x003fb174,0x003f917c,0x90210004,0x003fb17c, +0x83e4014a,0x8013001f,0x83e71b0c,0x1bffb800, +0x003f9179,0x1821b800,0x00ffb801,0xb5000008, +0x80270000,0x003f25dc,0x8013001f,0x83e71b30, +0x1bffb800,0x003f917a,0x1821b800,0x00ffb801, +0x80070000,0x001f20b1,0x001f42ea,0x9420000f, +0xb0010000,0xb4200003,0x98000800,0x001f62ea, +0xb500ffaf,0x9400fff0,0x001f62ea,0x80270000, +0x8057ffff,0x80770000,0x80171800,0x81df0000, +0x00000000,0x00000000,0xb6000302,0xb6002001, +0x001fa021,0x81df0004,0xb500ffa1,0xb500ffa0, +0x803bffc0,0x805bffc4,0x807bffc8,0x809bffcc, +0x5828b801,0x5cb8b802,0x1821b805,0x5848b802, +0x5cb8b803,0x1842b805,0x5868b803,0x5cb8b804, +0x1863b805,0x5888b804,0x1884b800,0x803effc0, +0x805effc4,0x807effc8,0x809effcc,0x003f42ea, +0xb0000086,0xb4400079,0xb0000084,0xb4000049, +0xb0000085,0xb4000063,0xb0000086,0xb400006c, +0xb0000081,0xb4000005,0xb0000082,0xb4000003, +0xb0000080,0xb4000001,0xb5000069,0x8013007f, +0x9800ffff,0x001fb02d,0x80070000,0x001fb17c, +0x8013001f,0x9040fa00,0x805effd0,0x805effdc, +0x805effd8,0x9040fe00,0x805effd4,0x9040c000, +0x805effe4,0x90008000,0x801effe0,0x001fb174, +0x801effe8,0x801effec,0x80078000,0x801e78d4, +0x80070000,0x001fb17c,0x001fb17d,0x001fb02e, +0x83e400e6,0x8013001f,0x98000000,0x800600a2, +0x8013001f,0x98000300,0x800600a3,0x805bff7c, +0x80070c25,0x94420080,0xb0020080,0xb420000d, +0x8013001f,0x98000000,0x800600a2,0x8013001f, +0x98000300,0x800600a3,0x80070225,0x80530001, +0x98420100,0x1800b802,0x80530200,0x98420000, +0x804600a6,0x800600a1,0x80050080,0x98000022, +0x80060080,0x80072080,0x001fb179,0x80074618, +0x001fb17a,0x80070001,0x001f25dc,0x98214000, +0xb5000029,0x8047ffff,0x805eff84,0x805bff88, +0x00000000,0xb0020001,0xb4200002,0x80470000, +0x805eff88,0x805bff7c,0x80070c25,0x94420080, +0xb0020080,0xb4200007,0x80070225,0x80530001, +0x98420100,0x1800b802,0x80530200,0x98420000, +0x804600a6,0x800600a1,0x80070001,0x800600a0, +0x9421efff,0x98210010,0xb500000f,0x80070000, +0x001fb17c,0x80070001,0x001f25dc,0x83e400a3, +0x80050081,0x80330008,0x98210000,0x1800b801, +0x80060081,0x003f42ea,0x9421ffef,0xb5000002, +0x98211000,0x9421ffef,0x83e40098,0x003f62ea, +0x80070100,0x801efff0,0xb500ff11,0xb000008b, +0xb400001c,0xb0000087,0xb400ffe8,0xb0000088, +0xb4000023,0xb000008a,0xb4000024,0xb000008c, +0xb4000019,0xb000008e,0xb4000014,0xb000008d, +0xb400001d,0xb0000089,0xb400001f,0xb00000a0, +0xb4000021,0xb00000a1,0xb4000022,0xb00000a2, +0xb400002f,0xb00000a3,0xb4000027,0xb00000a4, +0xb4000031,0xb00000a5,0xb4000035,0xb00000a6, +0xb4000039,0x803efff8,0xb500ffdd,0x80070000, +0x001fb17e,0xb500ffda,0x803bffb0,0x00000000, +0x003fb02d,0xb500ffd6,0x98210020,0xb500ffd2, +0x9421ffdf,0xb500ffd0,0xb500ffd1,0x80270341, +0x803efff8,0xb500ffce,0x803bff80,0x00000000, +0x003f62ef,0xb500ffca,0x003f917b,0x803efff8, +0xb500ffc7,0x80270000,0x8047fef0,0x003eb802, +0x90420004,0x003eb802,0x90420004,0x003eb802, +0x90420004,0x003eb802,0x81df0000,0x00000000, +0x00000000,0x83640dbd,0x81df0004,0xb500ffb8, +0x81df0000,0x00000000,0x00000000,0x83640d67, +0x81df0004,0xb500ffb2,0x81df0000,0x00000000, +0x00000000,0x83640d22,0x81df0004,0xb500ffac, +0x81df0000,0x00000000,0x00000000,0x83440c85, +0x81df0004,0xb500ffa6,0x81df0000,0x00000000, +0x00000000,0x83440c6a,0x81df0004,0xb500ffa0, +0x817bffe8,0x815b78d4,0x00000000,0x956bffff, +0x300bb80a,0xb4600001,0x916b4000,0x056bb80a, +0xb00b0080,0xb4a0002a,0x80af001f,0x808f0000, +0x806f0000,0x81b300ff,0x8057ffff,0x5d67b80b, +0x5d42b80a,0x81df0000,0x00000000,0x00000000, +0xb62b001c,0xb00a3000,0xb4800001,0x854a1000, +0x80cf0400,0x015fb178,0x5942b80a,0x01cfb80a, +0x015f9178,0xb520ffff,0x80171000,0xb600200a, +0x01ff8000,0x5a18b80f,0x5a28b80f,0x1631b80d, +0x5e48b80f,0x9652ff00,0x5e78b80f,0x1a73b810, +0x1a73b811,0x1813a032,0x80cf0400,0x015fb178, +0x5942b80a,0x01afb80a,0x015f9178,0xb520ffff, +0x914a0020,0x81df0004,0x5942b80a,0x815e78d4, +0x00000000,0x00000000,0x00ffb81f,0x81df0000, +0x80070000,0x80470000,0x81171800,0xb6002003, +0xb6003002,0x001eb802,0x90420004,0xb6002003, +0x011fa020,0x011fa020,0x011fa020,0x81df0004, +0x00ffb81f,0x80070000,0x80478000,0x81df0000, +0x00000000,0x00000000,0xb6002003,0xb6008002, +0x001eb802,0x90420004,0x81df0004,0x00ffb81f, +0x015f42ea,0x944a4000,0xb0024000,0xb4200081, +0x954abfff,0x015f62ea,0x808f0000,0x80ef007c, +0x80171000,0x80971400,0x80270000,0xb6001003, +0xb6002002,0x001fa021,0x009fa021,0x80a76604, +0x80271400,0x81df0000,0x00000000,0x00000000, +0xb6001004,0x01efb801,0x01afb805,0xb520ffff, +0x90a50080,0x81df0004,0x80a76e04,0x80271400, +0x81df0000,0x00000000,0x00000000,0xb6001004, +0x01efb801,0x01afb805,0xb520ffff,0x90a50080, +0x81df0004,0x806f001f,0x80af001f,0x80276400, +0x5c22b801,0x806701e1,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x80275c00,0x5c22b801, +0x80670200,0x81df0000,0x00000000,0x00000000, +0xb600100a,0x00cfb803,0x003fb178,0x5822b801, +0x01cfb801,0x003f9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x90210020,0x90630020,0x81df0004, +0x808f0000,0x806f001f,0x80af001f,0x8027647c, +0x5c22b801,0x8067017e,0x81df0000,0x00000000, +0x00000000,0xb600020a,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90210020,0x90630020, +0x81df0004,0x806f0010,0x80af0010,0x8027657c, +0x5c22b801,0x806701be,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x802765c0,0x5c22b801, +0x806701cf,0x00cfb803,0x003fb178,0x5822b801, +0x01cfb801,0x003f9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x80276000,0x005fb801,0x8033001f, +0x98218000,0x803effe0,0x90214000,0x803effe4, +0x8193001f,0x998c8000,0x019fb174,0x83270000, +0x003fb819,0x003f9174,0x5823b801,0x83338000, +0x1b39b801,0x003fb819,0x00000000,0x00000000, +0x81550000,0x0187b860,0x858c0040,0x81b380fc, +0x99ad0000,0x300cb80d,0xb4600003,0x81b30002, +0x99ad0000,0x118cb80d,0x003fb80c,0x00000000, +0x00000000,0x81550000,0x8257ffff,0x82d7ffff, +0x8357ffff,0x81672000,0x83440191,0xb00a0001, +0xb4000141,0x0187b860,0x858c0010,0x5988b80c, +0x5d8bb80c,0x958cffff,0xb00cc000,0xb4800002, +0x858cc000,0x918c8000,0x81b3001f,0x198cb80d, +0x801bffec,0x00000000,0x819effec,0x819e78d8, +0x019fb174,0x05acb800,0x300cb800,0xb4600001, +0x91ad4000,0x001f917c,0x1000b80d,0x001fb17c, +0x8344019c,0xb00a0000,0xb4200127,0x015f0081, +0xb00a0002,0xb4200124,0x037f0082,0xb01b0000, +0xb400001e,0x0367b860,0x5b68b81b,0x5f68b81b, +0x017f4047,0x916b0010,0x5963b80b,0x83440168, +0x801bff84,0xb00a0001,0xb400000b,0xb00b00c0, +0xb460fffa,0x803f0000,0x80138000,0x1b7bb800, +0x003fb81b,0x00000000,0x00000000,0x80150000, +0x801bff84,0xb5000009,0x803f0000,0x80138000, +0x1b7bb800,0x003fb81b,0x00000000,0x00000000, +0x80150000,0x801bff84,0xb5000103,0x801bff84, +0x003f0084,0x3000b801,0x803eff84,0xb4000073, +0x801bff7c,0x00000000,0x94800080,0xb0040080, +0xb4200036,0x94800007,0x80730200,0xb0010002, +0xb420000e,0x80270265,0xb0040001,0xb4200003, +0x80130030,0x98000000,0xb5000006,0x80130030, +0x98000000,0xb0040000,0xb4000002,0x80130038, +0x98000000,0x98630060,0xb500001f,0xb0010000, +0xb420000e,0x80270225,0xb0040001,0xb4200003, +0x80130030,0x98001000,0xb5000006,0x80130030, +0x98001000,0xb0040000,0xb4000002,0x80130038, +0x98001000,0x98630000,0xb500000f,0xb0010001, +0xb420004a,0x80270225,0xb0040001,0xb4200003, +0x80130030,0x98002000,0xb5000006,0x80130030, +0x98000000,0xb0040000,0xb4000002,0x80130038, +0x98000000,0x98630040,0x806600a6,0x80530001, +0x98420100,0x1821b802,0xb500002d,0x94800007, +0xb0010002,0xb420000d,0x80270c65,0xb0040001, +0xb4200003,0x80130030,0x98000000,0xb5000006, +0x80130030,0x98000000,0xb0040000,0xb4000002, +0x80130038,0x98000000,0xb500001d,0xb0010000, +0xb420000d,0x80270c25,0xb0040001,0xb4200003, +0x80130030,0x98001000,0xb5000006,0x80130030, +0x98001000,0xb0040000,0xb4000002,0x80130038, +0x98001000,0xb500000e,0xb0010001,0xb4200017, +0x80270c25,0xb0040001,0xb4200003,0x80130030, +0x98002000,0xb5000006,0x80130030,0x98000000, +0xb0040000,0xb4000002,0x80130038,0x98000000, +0x806500d4,0x8053ffcf,0x9842cfff,0xb0040002, +0xb4200002,0x8053ffc7,0x9842c7ff,0x802600a1, +0x1463b802,0x1863b800,0x806600d4,0x807bff7c, +0x00000000,0x94630080,0xb0030080,0xb420000b, +0x807bff88,0x00000000,0xb0030001,0xb4000007, +0x802500a1,0x80670001,0x807eff88,0x80530001, +0x98420100,0x1821b802,0x802600a1,0x81070000, +0x011f62e2,0x011f62e3,0x011f0082,0xb0080000, +0xb4200004,0x81150010,0x00000000,0x00000000, +0x011f62de,0x011f0081,0xb0080001,0xb4200026, +0x81070020,0x011f25c1,0x81070180,0x011f62e1, +0x8344023e,0x8344026a,0x011f0082,0xb0080000, +0xb4200004,0x834401bd,0x834401aa,0xb00a0000, +0xb4200061,0x80c70000,0x00df25cb,0x83440281, +0x8344064f,0x02ff05b9,0x82a70000,0x82870000, +0x83440407,0x92940001,0x3014b817,0xb480fffc, +0x834406ef,0x80270000,0x003f25dc,0x834407de, +0x003f05dc,0xb0010001,0xb4000003,0x80272694, +0x003fb17a,0x00ffb81f,0x80d3001f,0x8347266c, +0x1b5ab806,0xb500002d,0xb0080002,0x81470004, +0xb4200045,0x81070008,0x011f25c1,0x81070480, +0x011f62e1,0x8344029e,0x834402dc,0x011f0082, +0xb0080000,0xb4200004,0x834401aa,0x83440181, +0xb00a0000,0xb4200038,0x80c70000,0x00df25cb, +0x83440368,0x02df05cb,0x5ec2b816,0x8344066b, +0x02ff05b9,0x82a70000,0x82870000,0x834403dc, +0x92940001,0x3014b817,0xb480fffc,0x92b50001, +0xb0150003,0xb480fff8,0x834406c1,0x80270000, +0x003f25dc,0x834407b0,0x003f05dc,0xb0010001, +0xb4000003,0x8027274c,0x003fb17a,0x00ffb81f, +0x80d3001f,0x83472710,0x1b5ab806,0x80db78d8, +0x80fbffec,0x00000000,0x3006b807,0xb4200007, +0x00df05cb,0x90c60001,0x00df25cb,0xb006000c, +0xb4000002,0x035fb179,0x00ffb81f,0x80c70000, +0x00df25cb,0x80fb78dc,0x00000000,0x90e70001, +0xb00701b9,0xb4a00001,0x80e70001,0x80fe78dc, +0xb500feb0,0x802500a5,0x8153001f,0x3001b80a, +0xb420fffc,0x00ffb81f,0x001f42ea,0x1800b80a, +0x001f62ea,0x017f4047,0x5963b80b,0x0187b860, +0x118cb80b,0x81b380fe,0x99ad0000,0x300cb80d, +0xb4800003,0x81b30002,0x99ad0000,0x058cb80d, +0x003fb80c,0x00000000,0x00000000,0x81550000, +0x0187b860,0x5988b80c,0x5d8bb80c,0x958cffff, +0xb00cc000,0xb4800002,0x858cc000,0x918c8000, +0x81b3001f,0x198cb80d,0x801bffec,0x00000000, +0x819effec,0x019fb174,0x05acb800,0x300cb800, +0xb4600001,0x91ad4000,0x001f917c,0x1000b80d, +0x001fb17c,0x80171000,0x80971400,0x80270000, +0xb6001003,0xb6002002,0x001fa021,0x009fa021, +0x80171800,0xb6000602,0xb6002001,0x001fa021, +0x806f001f,0x80af001f,0x80a76604,0x80271400, +0x81df0000,0x00000000,0x00000000,0xb6001004, +0x01efb801,0x01afb805,0xb520ffff,0x90a50080, +0x81df0004,0x80a76e04,0x80271400,0x81df0000, +0x00000000,0x00000000,0xb6001004,0x01efb801, +0x01afb805,0xb520ffff,0x90a50080,0x81df0004, +0x81472080,0x015fb179,0x00ffb81f,0x00000000, +0x811be024,0x0107b860,0x95080007,0xb0080000, +0xb4000004,0xa5080008,0x00000000,0x0155b808, +0x00000000,0x8115000c,0x856b000c,0xb0080fff, +0xb400000b,0x81550004,0x856b0004,0x5904b808, +0x1908b80a,0x95080fff,0xb0080fff,0xb4000004, +0x81470001,0xb00b0020,0xb440fff6,0xb500000c, +0x81d50004,0x856b0004,0x00000000,0xb00e000f, +0xb400fffb,0x940b0007,0xb0000000,0xb420ffed, +0x001f42ea,0x9400fffe,0x81470000,0x001f62ea, +0x00ffb81a,0x950e0008,0x5d03b808,0x00000000, +0xb0080000,0xb40000cd,0x011f2080,0x950e0006, +0x5d01b808,0x81270004,0x0529b808,0x950e0001, +0x013f2081,0x011f2082,0x81150004,0x00000000, +0xb0080000,0xb40000c1,0xb008000f,0xb40000bf, +0x011f2083,0x81150002,0x00000000,0x81670004, +0xb0080002,0xb46000b9,0x011f2084,0x013f0081, +0xb0090002,0xb4200011,0x013f0083,0xb0080000, +0xb4200002,0x81077844,0xb5000005,0xb0080001, +0xb4200002,0x81077884,0xb5000001,0x81077824, +0x013f0083,0x5921b809,0x1129b808,0x0119b809, +0x00000000,0x00000000,0x011f6047,0x81150001, +0x00000000,0x011f2085,0x81150001,0x00000000, +0x011f2086,0x81350002,0x00000000,0x013f2087, +0x81150002,0x00000000,0x011f2088,0x81150001, +0x00000000,0x011f2089,0x81150001,0x00000000, +0x011f208a,0x81150002,0x00000000,0x011f208b, +0x81070001,0xb0090003,0xb4000001,0x81070002, +0x011f25b9,0x81070020,0x013f0081,0xb0090002, +0xb4200069,0x85290001,0xad29000f,0x00000000, +0x011f0083,0x1108b809,0x5901b808,0x910877c8, +0x0139b808,0x011f05b9,0x85080001,0x6928b809, +0x011f0084,0xb0090038,0xb4800007,0xb0080001, +0xb4000002,0xb0090050,0xb4400003,0x81270000, +0x8107001b,0xb5000010,0xb0080001,0xb4000005, +0xb0090060,0xb4800003,0x81270001,0x8107001e, +0xb5000009,0xb0080002,0xb4000005,0xb0090030, +0xb4400003,0x81270002,0x81070008,0xb5000002, +0x81270003,0x8107000c,0x011f25bb,0x013f25c0, +0xb0090002,0xb460001b,0x80477604,0x5c42b802, +0x814fffc0,0x80cf0037,0x005fb178,0x5842b802, +0x01cfb802,0x005f9178,0xb520ffff,0x90420020, +0x814fb580,0x80cf0057,0x005fb178,0x5842b802, +0x01cfb802,0x005f9178,0xb520ffff,0x804778a4, +0x5c42b802,0x814f39c0,0x80cf002f,0x005fb178, +0x5842b802,0x01cfb802,0x005f9178,0xb520ffff, +0xb5000025,0x804776e0,0x5c42b802,0x814fef40, +0x80cf0037,0x005fb178,0x5842b802,0x01cfb802, +0x005f9178,0xb520ffff,0x8297013c,0x8317018c, +0x81df0000,0x00000000,0x00000000,0xb6000602, +0x005f8034,0x031fa022,0x82970124,0x83170160, +0xb6000602,0x005f8034,0x031fa022,0x8297010c, +0x83170134,0xb6000602,0x005f8034,0x031fa022, +0x81df0004,0x804778c4,0x5c42b802,0x814f1080, +0x80cf002f,0x005fb178,0x5842b802,0x01cfb802, +0x005f9178,0xb520ffff,0x013f0081,0xb0090001, +0xb420000e,0x808f0000,0x806f001b,0x80af001b, +0x80277758,0x5c22b801,0x80670037,0x00cfb803, +0x003fb178,0x5822b801,0x01cfb801,0x003f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x011f25bb, +0x011f0087,0xb0080001,0xb4000002,0x011f05bb, +0xb5000003,0x011f0088,0x91080001,0x5902b808, +0x011f25ba,0x81470000,0x00ffb81a,0x81470008, +0x00ffb81a,0x81270000,0x81470000,0x300842de, +0xb400000b,0x013f42e2,0x91290001,0x013f62e2, +0x013f42e3,0x91290001,0x013f62e3,0x83640006, +0x00000000,0x00000000,0x013f42e2,0x81470002, +0x013f62e2,0x00ffb81a,0x00ffb81b,0x83640049, +0x80c70004,0x80270000,0x81df0000,0x00000000, +0x00000000,0xb600200d,0x00ff05b9,0x5c42b801, +0x300205ba,0xb4800001,0x80e70001,0x80470000, +0xb6270005,0x1062b801,0x914301b8,0x00fff00a, +0x83840055,0x90420080,0x90210004,0x81df0004, +0x00ffb81a,0x83640033,0x017f05bb,0x800700bc, +0x80270000,0x81df0000,0xb00b0000,0xb4000015, +0xb62b0014,0x00ff05b9,0x5c42b801,0x300205ba, +0xb4800001,0x80e70001,0x80470000,0xb0070000, +0xb400000b,0xb627000a,0x1062b801,0x914301b8, +0x00fff00a,0x5c62b801,0x1063b800,0x00bff003, +0x90650134,0x00dff003,0x83840037,0x90420080, +0x90210004,0x81df0004,0x019f05b9,0x80c70002, +0x80270000,0x81df0000,0xb00b0000,0xb400000f, +0xb62b000e,0x80470000,0xb00c0000,0xb400000a, +0xb62c0009,0x1062b801,0x914301b8,0x00fff00a, +0xb0070000,0xb4000003,0x906302b8,0x00fff003, +0x83840021,0x90420080,0x90210004,0x81df0004, +0x00ffb81a,0x8107ffff,0x80c70004,0x00ff0083, +0x83840019,0x80c70002,0x00ff0084,0x83840016, +0x80c70001,0x00ff0085,0x83840013,0x80c70001, +0x00ff0086,0x83840010,0x80c70002,0x00ff0087, +0x8384000d,0x80c70002,0x00ff0088,0x8384000a, +0x80c70001,0x00ff0089,0x83840007,0x80c70001, +0x00ff008a,0x83840004,0x80c70002,0x00ff008b, +0x83840001,0x00ffb81b,0x80a70001,0x64a6b805, +0x5ca1b805,0xb0050000,0xb400000e,0x95288000, +0xb0090000,0xb4000001,0x81270001,0x5901b808, +0x1547b805,0xb00a0000,0xb4000001,0x81470001, +0x2129b80a,0xb0090000,0xb4000001,0xa1088005, +0xb500ffef,0x9508ffff,0x00ffb81c,0x015f05ba, +0x013f05b9,0x800700bc,0xb0090000,0xb4000012, +0xb00a0000,0xb4000010,0x80270000,0x81df0000, +0x00000000,0x00000000,0xb62a000b,0x80470000, +0xb6290008,0x80950004,0x5865b802,0x1063b801, +0x5862b803,0x906301b8,0x0217b803,0x90420001, +0x021fa004,0x90210001,0x81df0004,0xa54a0020, +0xb4c00011,0xb0090000,0xb400000f,0x81df0000, +0x00000000,0x00000000,0xb62a000b,0x80950004, +0x80470000,0xb6290007,0x5865b802,0x1063b801, +0x5862b803,0x906301b8,0x0217b803,0x90420001, +0x021fa004,0x90210001,0x81df0004,0x00ffb81a, +0x013f05b9,0xb0090000,0xb400001c,0x80270000, +0x81df0000,0x00000000,0x00000000,0xb6002017, +0x80470000,0xb6290014,0x5865b802,0x1063b801, +0x5862b803,0x914301b8,0x009ff00a,0xad420060, +0x00000000,0x114ab801,0x5942b80a,0x914a1c80, +0x0217b80a,0xb0040000,0xb4000004,0x80950006, +0x00000000,0x021fa004,0xb5000002,0x8087003f, +0x021fa004,0x90420001,0x90210001,0x81df0004, +0x00ffb81a,0x8257ffff,0x82d7ffff,0x011f05ba, +0x013f05b9,0x80270000,0xb0090000,0xb4000033, +0x81df0000,0x00000000,0x00000000,0xb6280015, +0x80470000,0xb6290012,0x5865b802,0x1063b801, +0x5862b803,0x914301b8,0xaca20060,0x009ff00a, +0x10a5b801,0x58a2b805,0x90a502b8,0x0217b805, +0x80670000,0xb0040000,0xb4000003,0x90840001, +0x0075b804,0x00000000,0x021fa003,0x90420001, +0x90210001,0x81df0004,0xa5480020,0xb4000017, +0x5822b801,0x81df0000,0x00000000,0x00000000, +0xb62a0011,0x914101b8,0x90a102b8,0x0217b805, +0x009ff00a,0xb0040000,0x80670000,0xb4000002, +0x90840001,0x0075b804,0xb6290006,0x021fa203, +0x009f8210,0x009f8210,0x009f8210,0x009f8210, +0x009f8210,0x90210004,0x81df0004,0x00ffb81a, +0x015f05ba,0x013f05b9,0x800700bc,0xb0090000, +0xb4000016,0xb00a0000,0xb4000014,0x80270000, +0x81df0000,0x00000000,0x00000000,0xb62a000f, +0x80470000,0xb629000c,0x1080b801,0x007ff004, +0x90830134,0x007ff004,0x0095b803,0x5865b802, +0x1063b801,0x5862b803,0x906301b8,0x0217b803, +0x90420001,0x021fa004,0x90210001,0x011f05bb, +0x254ab808,0xb4c0000d,0xb62a000c,0x1080b801, +0x007ff004,0x90830134,0x007ff004,0x0095b803, +0x5862b801,0x906301b8,0x0217b803,0x90210001, +0x021fa204,0x007f8210,0x021fa004,0xa5480020, +0xb4c0000e,0xb0090000,0xb400000c,0x80870000, +0xb62a000a,0x80470000,0xb6290007,0x5865b802, +0x1063b801,0x5862b803,0x906301b8,0x0217b803, +0x90420001,0x021fa004,0x90210001,0x81df0004, +0x00000000,0x00000000,0x00ffb81a,0x011f05bb, +0x013f05b9,0xb0080000,0xb4000016,0xb0090000, +0xb4000014,0x81df0000,0x00000000,0x80270000, +0xb6280010,0x80470000,0xb629000d,0x5865b802, +0x1063b801,0x5862b803,0x914301b8,0x009ff00a, +0xb0040000,0xb4000005,0x80950002,0x906302b8, +0x0217b803,0x00000000,0x021fa004,0x90420001, +0x90210001,0x81df0004,0xa5480020,0xb00a0000, +0xb4000011,0xb0090000,0xb400000f,0x81df0000, +0x00000000,0x80870000,0xb62a000b,0x80470000, +0xb6290008,0x5865b802,0x1063b801,0x5862b803, +0x906302b8,0x0217b803,0x00000000,0x021fa004, +0x90420001,0x90210001,0x81df0004,0xb0080000, +0xb400004d,0xb0090000,0xb400004b,0x81df0000, +0x00000000,0x80270000,0xb6280047,0x80470000, +0xb6290044,0x5865b802,0x1063b801,0x5862b803, +0x914301b8,0x009ff00a,0xad420060,0x00000000, +0x00000000,0x00000000,0x114ab801,0x5942b80a, +0x914a1c80,0x0217b80a,0xb0040000,0xb400002e, +0x906302b8,0x009ff003,0xb0040000,0xb420000a, +0x80950006,0x00000000,0x021fa204,0x80950006, +0x015f8210,0x021fa204,0x80950006,0x015f8210, +0x021fa004,0xb5000026,0xb0040001,0xb4200009, +0x80950006,0x00000000,0x021fa204,0x015f8210, +0x021fa204,0x80950006,0x015f8210,0x021fa004, +0xb500001b,0xb0040003,0xb4200009,0x80950006, +0x00000000,0x021fa204,0x80950006,0x015f8210, +0x021fa204,0x015f8210,0x021fa004,0xb5000010, +0xb0040002,0xb420000e,0x80950006,0x00000000, +0x021fa204,0x015f8210,0x021fa204,0x015f8210, +0x021fa004,0xb5000006,0x8087003f,0x021fa204, +0x015f8210,0x021fa204,0x015f8210,0x021fa004, +0x90420001,0x90210001,0x81df0004,0xa5480020, +0xb4c00012,0xb0090000,0xb4000010,0x8087003f, +0x81df0000,0x5862b801,0x90631afc,0xb62a000b, +0x90630004,0x0047b803,0xb6290008,0x90420180, +0x0217b802,0x00000000,0x021fa204,0x003f8210, +0x021fa204,0x003f8210,0x021fa004,0x81df0004, +0x00ffb81a,0x8257ffff,0x82d7ffff,0x011f05bb, +0x013f05b9,0x80270000,0x00e7b809,0x300105ba, +0xb4800001,0x80e70001,0x800700bc,0x80470000, +0x81df0000,0xb0070000,0xb400004c,0xb627004b, +0x5865b802,0x1063b801,0x5862b803,0x914301b8, +0xaca20060,0x009ff00a,0x10a5b801,0x58a2b805, +0x90a502b8,0x0217b805,0xb0040000,0xb400002b, +0x1060b801,0x00bff003,0x10a5b804,0x90650160, +0x00dff003,0xb0060003,0xb4200007,0x90650134, +0x00dff003,0xb6000303,0x0075b806,0x021fa203, +0x007f8210,0xb5000021,0x5861b805,0x906300dc, +0x009fd803,0x90650134,0x00dff003,0xaca20060, +0x00000000,0x00000000,0x00000000,0x0075b806, +0x10a5b801,0x58a2b805,0x90a502b8,0x0217b805, +0x588fb804,0xb600030c,0xb6001007,0x04a3b804, +0xb4600002,0x58a1b803,0xb5000002,0x58a1b805, +0x90a50001,0x0067b805,0x9465ffff,0x5d50b805, +0x021fa20a,0x015f8210,0xb5000004,0x81470000, +0xb6000302,0x021fa20a,0x009f8210,0x009f05b9, +0xb0040002,0xb420000c,0x300105ba,0xb480000a, +0x58a2b801,0x90a502b8,0x0217b805,0x90a50180, +0x0297b805,0xb6000304,0x00bf8210,0x009f8210, +0x029fa205,0x009f8214,0x90420001,0x81df0004, +0x90210001,0x3001b808,0xb480ffa7,0xa5480020, +0xb00a0000,0xb4000019,0xb0090000,0xb4000017, +0x58a2b801,0x90a502b8,0x81df0000,0x00000000, +0x00000000,0xb62a0010,0x80470000,0xb629000d, +0xaca20060,0x00000000,0x00000000,0x00000000, +0x80670000,0x10a5b801,0x58a2b805,0x90a502b8, +0x0217b805,0xb6000302,0x021fa203,0x00bf8210, +0x90420001,0x90210001,0x81df0004,0x00ffb81a, +0x80770000,0x8057ffff,0x80f70000,0x80d7ffff, +0x81770000,0x8157ffff,0x81f70000,0x81d7ffff, +0xac140060,0xac350020,0x00000000,0x00000000, +0x12c0b801,0x5ac2b816,0x92d61980,0x83a400bd, +0xad940400,0x009f9173,0x013f05ca,0x914c6604, +0x114ab804,0x001f97e0,0x001eb80a,0xb0090000, +0xb4000003,0x80a76e44,0x80c76644,0xb5000002, +0x80a76644,0x80c76e44,0x808f000f,0x806f0000, +0x80af000e,0x80cf07e1,0x11e5b80c,0x11efb804, +0x5de2b80f,0x01ffb178,0x59e2b80f,0x01afb80f, +0x01ff9178,0x0047b86f,0xb0020001,0xb4c0fffd, +0x80cf07f0,0x1206b80c,0x1210b804,0x5e02b810, +0x021fb178,0x5a02b810,0x01afb810,0x021f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x916c6e04, +0x116bb804,0x001f97ff,0x001eb80b,0x808f0000, +0x806f001f,0x80af001f,0x90ac6604,0x5ca2b805, +0x80270400,0x81df0000,0x00000000,0x00000000, +0xb600080a,0x00cfb801,0x00bfb178,0x58a2b805, +0x01cfb805,0x00bf9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x90210020,0x90a50020,0x81df0004, +0x90ac6e04,0x5ca2b805,0x80270500,0x81df0000, +0x00000000,0x00000000,0xb600080a,0x00cfb801, +0x00bfb178,0x58a2b805,0x01cfb805,0x00bf9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x90210020, +0x90a50020,0x81df0004,0x81530020,0xac140060, +0xac350020,0x80170800,0x80d7003c,0x12c0b801, +0x5ac2b816,0x92d602b8,0x0117b816,0x90241000, +0x0097b801,0x80470000,0x4002b803,0x81df0000, +0x00000000,0x00000000,0xb6000804,0x005f8020, +0x480287e4,0x005f8020,0x500287e4,0x81df0004, +0x00000000,0x00000000,0x00000000,0x1021b80a, +0x5c36b801,0x5801b800,0x18c0b801,0xb0090000, +0xb4000002,0x90641440,0xb5000001,0x90641040, +0x81df0000,0x00000000,0x00000000,0xb6000f0d, +0x0097b803,0x80470000,0x4002b803,0xb6001002, +0x005f8020,0x480287e4,0x0108a026,0x90630040, +0x00000000,0x1021b80a,0x5c36b801,0x5801b800, +0x18c0b801,0x81df0004,0x90641400,0x0097b803, +0x80470000,0x4002b803,0x005f8020,0x005f87e4, +0x81df0000,0x00000000,0x00000000,0xb6000802, +0x005f8040,0x480287c4,0x81df0004,0x005f87e0, +0x0108a026,0x00000000,0x1021b80a,0x5c36b801, +0x5801b800,0x18c0b801,0xb0090000,0xb4000002, +0x906417c0,0xb5000001,0x906413c0,0x81df0000, +0x00000000,0x00000000,0xb6000f0f,0x0097b803, +0x80470000,0x4002b803,0xb6000804,0x005f8020, +0x500287e4,0x005f8020,0x480287e4,0x0108a026, +0x84630040,0x00000000,0x1021b80a,0x5c36b801, +0x5801b800,0x18c0b801,0x81df0004,0xb0140000, +0xb4200005,0x90840004,0x9484003f,0x009fb173, +0xa1290001,0x013f25ca,0x80d7ffff,0x0108a026, +0x00ffb81a,0x81330004,0x8093007f,0x9884ffff, +0x80b3ff80,0x0017b816,0x90360040,0x0097b801, +0x81530010,0x81df0000,0x00000000,0x00000000, +0xb6001004,0x400a8000,0x404a8004,0x0008a020, +0x0088a022,0x81df0004,0x0017b816,0x9036007c, +0x0097b801,0x81171000,0x81df0000,0x00000000, +0x00000000,0xb6001004,0x40048020,0x480487e4, +0x00000000,0x0108a020,0x81df0004,0x81470000, +0x81670001,0x81870008,0x81a70040,0x81c707c4, +0x81e70040,0x81df0000,0x00000000,0x00000000, +0xb6000432,0xb00a0001,0xb4e00004,0x80c71000, +0x80e71000,0x81171040,0xb5000003,0x80c71040, +0x80e71040,0x81171000,0x844d0004,0x10e7b802, +0xb62b001f,0x0017b806,0x0097b807,0xb62c0004, +0x40048020,0x480487e4,0x00000000,0x0108a020, +0x0017b806,0x0097b807,0x0197b80e,0x00000000, +0x001f8020,0x042087e4,0xb62c000f,0x4041800c, +0x001f8020,0x0048b802,0x5e38802c,0x2e11b801, +0x042087e4,0x1042b810,0x0462b804,0xb4a00002, +0x0047b804,0xb5000003,0x0462b805,0xb4600001, +0x0047b805,0x011fa022,0x10c6b80f,0x10e7b80f, +0x5961b80b,0x5d81b80c,0x5da1b80d,0x5de1b80f, +0x914a0001,0x954a0001,0x11ceb80f,0x81df0004, +0x80171018,0x81171fcc,0x80470000,0x41448020, +0x494487c0,0x00000000,0x0188b80a,0x494487e0, +0x00000000,0x0148b80a,0x0502a10a,0x4145b80c, +0x494580e0,0x00000000,0x0108a5ea,0x41448080, +0x494487c0,0x00000000,0x0108a78a,0x49448020, +0x00000000,0x0108a2ea,0x41448020,0x49448720, +0x00000000,0x0188b80a,0x4145b80c,0x49458080, +0x494587a0,0x00000000,0x0108a68a,0x4145b80c, +0x49458080,0x494587a0,0x00000000,0x0108a08a, +0x4145b80c,0x49458020,0x49458040,0x00000000, +0x0188b80a,0x494587e0,0x00000000,0x0108a08a, +0x4144b80c,0x494587a0,0x00000000,0x0108a52a, +0x41448080,0x49448040,0x494486c0,0x00000000, +0x0108a04a,0x41448040,0x49448720,0x00000000, +0x0108a36a,0x04028020,0x011fa420,0x001f8040, +0x011fa100,0x001f8080,0x011fa080,0x001f8100, +0x011fa040,0x001f8660,0x011fa120,0x41458020, +0x49458000,0x00000000,0x0108a00a,0x0017b816, +0x9036007c,0x0097b801,0x81171000,0x81970784, +0x00000000,0x001f8020,0x042087e4,0x81df0000, +0x00000000,0x00000000,0xb600100f,0x4041800c, +0x001f8020,0x0048b802,0x5e38802c,0x2e11b801, +0x042087e4,0x1042b810,0x0462b804,0xb4a00002, +0x0047b804,0xb5000003,0x0462b805,0xb4600001, +0x0047b805,0x011fa022,0x81df0004,0x81470000, +0x81670001,0x81870008,0x81a70040,0x81c707c4, +0x81e70040,0x81df0000,0x00000000,0x00000000, +0xb6000432,0xb00a0001,0xb4e00004,0x80c71000, +0x80e71000,0x81171040,0xb5000003,0x80c71040, +0x80e71040,0x81171000,0x844d0004,0x10e7b802, +0xb62b001f,0x0017b806,0x0097b807,0xb62c0004, +0x40048020,0x480487e4,0x00000000,0x0108a020, +0x0017b806,0x0097b807,0x0197b80e,0x00000000, +0x001f8020,0x042087e4,0xb62c000f,0x4041800c, +0x001f8020,0x0048b802,0x5e38802c,0x2e11b801, +0x042087e4,0x1042b810,0x0462b804,0xb4a00002, +0x0047b804,0xb5000003,0x0462b805,0xb4600001, +0x0047b805,0x011fa022,0x10c6b80f,0x10e7b80f, +0x5961b80b,0x5d81b80c,0x5da1b80d,0x5de1b80f, +0x914a0001,0x954a0001,0x11ceb80f,0x81df0004, +0x80171034,0x81171f84,0x80470000,0x41448040, +0x49448640,0x00000000,0x0188b80a,0x49448100, +0x49448780,0x00000000,0x0108a08a,0x4144b80c, +0x49448040,0x49448080,0x494487c0,0x00000000, +0x0108a16a,0x4145b80c,0x49458700,0x00000000, +0x0188b80a,0x494581a0,0x494586e0,0x00000000, +0x0108a66a,0x4145b80c,0x49448040,0x494487e0, +0x00000000,0x0188b80a,0x011fa1ec,0x4145b80c, +0x49458100,0x49458780,0x00000000,0x0108a08a, +0x41458720,0x49458100,0x494586e0,0x49458160, +0x49458020,0x49458020,0x49458760,0x00000000, +0x0108a08a,0x414587a0,0x49458080,0x49458760, +0x494580c0,0x49458700,0x49458140,0x49458020, +0x49458760,0x00000000,0x0108a74a,0x414587a0, +0x49458080,0x49458760,0x494580e0,0x49458700, +0x49458120,0x49458020,0x49458760,0x00000000, +0x0108a08a,0x41458720,0x49458100,0x494586e0, +0x49458140,0x49458040,0x49458020,0x49458720, +0x00000000,0x0108a0ca,0x41458080,0x49458040, +0x49458020,0x49458620,0x00000000,0x0188b80a, +0x49458080,0x00000000,0x0108a7ca,0x4144b80c, +0x49458040,0x49458020,0x49458080,0x00000000, +0x0108a5ea,0x41448080,0x49448700,0x00000000, +0x0188b80a,0x49448780,0x00000000,0x0108a7ca, +0x4144b80c,0x49448140,0x00000000,0x0108a7ca, +0x49448040,0x00000000,0x0108a0ca,0x41448700, +0x00000000,0x0188b80a,0x49448000,0x00000000, +0x0108a04a,0x011fa00c,0x80171f80,0x81df0000, +0x00000000,0x00000000,0xb6002006,0x40048000, +0x48048000,0x48048000,0x48048000,0x00000000, +0x0008a020,0x81df0004,0x00ffb81d,0x00000000, +0x80770000,0x8057ffff,0x015f05b9,0x017f05bb, +0x8293ffff,0x9a94ffff,0x81a70000,0x81df0000, +0x00000000,0x00000000,0xb62a003a,0xaded0180, +0xae0d0180,0xadcd0080,0x902f1980,0x0017b801, +0xb6002033,0x904e01b8,0x00000000,0x013ff002, +0xb0090000,0xb400001f,0x904f02b8,0x80c70000, +0x011fd802,0x6829b808,0x94210001,0xb0010001, +0xb4e00001,0x00c7b814,0x6429b806,0x80470001, +0x6449b802,0x84420001,0x1442b808,0x84690001, +0x5863b803,0x906300dc,0x1042b801,0x003f9803, +0x90420001,0x4082b801,0x90630004,0x003f9803, +0x00000000,0x5897b804,0x1804b805,0x4082b801, +0x00000000,0x00000000,0x00000000,0x10a4b800, +0xb5000001,0x80a70000,0x90501c80,0x00000000, +0x007ff002,0x5842b803,0x904205f8,0x0097b802, +0x00000000,0x40058004,0x48058004,0x00000000, +0x0008a020,0x91ce0004,0x91ef0004,0x92100004, +0x91ad0001,0x81df0004,0x00ffb81a,0x80770000, +0x8057ffff,0x80d7ffff,0x015f05b9,0x017f05bb, +0x8293ff80,0x9a940000,0x82a70020,0x81a70000, +0x81e702b8,0x80171980,0x81df0000,0x00000000, +0x00000000,0xb62a004f,0xb600034d,0xac0d0080, +0xac4d0180,0xac960080,0x822700bc,0x91c001b8, +0x00000000,0x1042b804,0x92021c80,0xb62b003a, +0x013ff00e,0x00fff011,0xb0090000,0xb4000027, +0x10e7b809,0x5821b807,0x902100dc,0x00000000, +0x001fd801,0x82470000,0x80270001,0x6452b801, +0x3002b800,0xb4600002,0x92520001,0xb500fffb, +0x86520001,0x80c70000,0x011fd80f,0x6832b808, +0xb0010001,0xb4e00001,0x00c7b814,0x84520017, +0x0056b802,0x80270001,0x6432b801,0x84210001, +0x1408b801,0x6402b800,0x10c6b800,0x9027018c, +0x00000000,0x001ff001,0x5802b800,0x9020073c, +0x904006f8,0x007f9801,0x0097b802,0x10c6b803, +0x40868004,0x48868004,0xb5000003,0x80c70000, +0x40868004,0x00000000,0x0088b804,0x003ff010, +0x5822b801,0x902105f8,0x0097b801,0x91ce0004, +0x91ef0004,0x40448004,0x48448004,0x92100004, +0x0008a022,0x92310001,0x0435b80b,0xb4000007, +0x80870000,0xb6210005,0x001fa024,0x91ce0004, +0x91ef0004,0x92100004,0x92310001,0x00000000, +0x91ad0001,0x81df0004,0x00ffb81a,0x00000000, +0x007f05b9,0x001f0081,0xb0000001,0xb440002d, +0x001f05d8,0xac400080,0x801702b8,0x80970438, +0x90421800,0x0117b802,0x8087ffff,0x80b3ffff, +0x80d3007f,0x98c6ff00,0x80f3ff80,0x81070080, +0x81df0000,0x00000000,0x00000000,0xb6002018, +0x10088020,0x0056b800,0x0442b806,0xb4a00004, +0xb0000000,0x0007b806,0xb4400001,0x0007b807, +0x0027b800,0x5c08b800,0x1400b804,0xb0030001, +0xb4000008,0x10288024,0x0056b801,0x0442b806, +0xb4a00004,0xb0010000,0x0027b806,0xb4400001, +0x0027b807,0x5828b801,0x1421b805,0x1900a021, +0x81df0004,0x001f05d8,0x90000001,0x001f25d8, +0x00ffb81a,0x801702b8,0x80970438,0x81171800, +0x8087ffff,0x80b3ffff,0x80d3007f,0x98c6ff00, +0x80f3ff80,0x81070080,0x81df0000,0x00000000, +0x00000000,0xb6006018,0x10088020,0x0056b800, +0x0442b806,0xb4a00004,0xb0000000,0x0007b806, +0xb4400001,0x0007b807,0x0027b800,0x5c08b800, +0x1400b804,0xb0030001,0xb4000008,0x10288024, +0x0056b801,0x0442b806,0xb4a00004,0xb0010000, +0x0027b806,0xb4400001,0x0027b807,0x5828b801, +0x1421b805,0x1900a021,0x81df0004,0x00ffb81a, +0x001f0081,0xb0000001,0xb4400006,0x001f05d8, +0xb0000003,0xb4000003,0x80270001,0x003f25dc, +0x00ffb81a,0x003f05d9,0x009f05cb,0xb0010000, +0xb400000e,0x015f42ed,0x81070000,0x8127017c, +0xb00a0000,0xb4000002,0x81070180,0x812702fc, +0x802500a5,0x9421ffff,0x3001b808,0xb4800011, +0x3001b809,0xb4a0007f,0xb500000e,0x001f0081, +0xb0000001,0xb4400003,0xb0040002,0xb4200006, +0xb5000002,0xb0040000,0xb4200003,0x802702ff, +0x81470000,0xb5000003,0x80270001,0x003f25d9, +0x81470180,0xb0040000,0xb4200001,0x838402ea, +0x80070000,0x001f25d8,0x009f902d,0x80af001f, +0x808f0000,0x806f0000,0x8007ffff,0x8033ffff, +0x80171800,0x81df0000,0x807bff8c,0x94630003, +0xb0030003,0xb4000016,0xb0030002,0xb4000035, +0xb0030001,0xb4000024,0xb6006010,0x14618000, +0x6068b803,0x40c4b803,0x14608000,0x00c8b806, +0x5870b803,0x6068b803,0x4104b803,0x58c8b806, +0x0108b808,0x14c6b801,0x00000000,0x00000000, +0x5d08b808,0x1508b800,0x1806a028,0xb5000030, +0xb6006010,0x14618000,0x6068b803,0x40c4b803, +0x14608000,0x00c8b806,0x5870b803,0x6068b803, +0x4104b803,0x5cc8b806,0x0108b808,0x14c6b800, +0x00000000,0x00000000,0x5908b808,0x1508b801, +0x1806a028,0xb500001e,0xb600600d,0x14618000, +0x6068b803,0x40c4b803,0x00000000,0x00c8b806, +0x00000000,0x00000000,0x00000000,0x5d08b806, +0x1508b800,0x58c8b806,0x14c6b801,0x1806a028, +0xb500000f,0xb600600e,0x14608000,0x5868b803, +0x6068b803,0x40c4b803,0x00000000,0x00c8b806, +0x00000000,0x00000000,0x00000000,0x5d08b806, +0x1508b800,0x58c8b806,0x14c6b801,0x1806a028, +0x81df0004,0x80670600,0x5d22b80a,0x81df0000, +0x00000000,0x00000000,0xb600030a,0x00cfb803, +0x013fb178,0x5922b809,0x01afb809,0x013f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x90630020, +0x91290020,0x81df0004,0x81270180,0xb00a0000, +0xb4000001,0x81270000,0x013f62ed,0x80270001, +0x003f25dc,0x00ffb81a,0x001f0081,0xb0000001, +0xb4400006,0x001f05d8,0xb0000003,0xb4000003, +0x80270001,0x003f25dc,0x00ffb81a,0x003f05d9, +0x009f05cb,0xb0010000,0xb400000e,0x015f42ed, +0x81070000,0x8127017c,0xb00a0000,0xb4000002, +0x81070180,0x812702fc,0x802500a5,0x9421ffff, +0x3001b808,0xb4800011,0x3001b809,0xb4a0007f, +0xb500000e,0x001f0081,0xb0000001,0xb4400003, +0xb0040002,0xb4200006,0xb5000002,0xb0040000, +0xb4200003,0x802702ff,0x81470000,0xb5000003, +0x80270001,0x003f25d9,0x81470180,0xb0040000, +0xb4200001,0x83840250,0x80070000,0x001f25d8, +0x009f902d,0x80af001f,0x808f0000,0x806f0000, +0x8007ffff,0x8033ffff,0x80171800,0x807bff8c, +0x81df0000,0x94630003,0xb0030003,0xb4000016, +0xb0030002,0xb4000035,0xb0030001,0xb4000024, +0xb6006010,0x14618000,0x6068b803,0x40c4b803, +0x14608000,0x00c8b806,0x5870b803,0x6068b803, +0x4104b803,0x58c8b806,0x0108b808,0x14c6b801, +0x00000000,0x00000000,0x5d08b808,0x1508b800, +0x1806a028,0xb5000030,0xb6006010,0x14618000, +0x6068b803,0x40c4b803,0x14608000,0x00c8b806, +0x5870b803,0x6068b803,0x4104b803,0x5cc8b806, +0x0108b808,0x14c6b800,0x00000000,0x00000000, +0x5908b808,0x1508b801,0x1806a028,0xb500001e, +0xb600600d,0x14618000,0x6068b803,0x40c4b803, +0x00000000,0x00c8b806,0x00000000,0x00000000, +0x00000000,0x5908b806,0x1508b801,0x5cc8b806, +0x14c6b800,0x1806a028,0xb500000f,0xb600600e, +0x14608000,0x5870b803,0x6068b803,0x40c4b803, +0x00000000,0x00c8b806,0x00000000,0x00000000, +0x00000000,0x5908b806,0x1508b801,0x5cc8b806, +0x14c6b800,0x1806a028,0x81df0004,0x80670600, +0x5d22b80a,0x81df0000,0x00000000,0x00000000, +0xb600030a,0x00cfb803,0x013fb178,0x5922b809, +0x01afb809,0x013f9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x90630020,0x91290020,0x81df0004, +0x81270180,0xb00a0000,0xb4000001,0x81270000, +0x013f62ed,0x80270001,0x003f25dc,0x00ffb81a, +0x029fb024,0x02bfb025,0x02dfb026,0x02ffb027, +0x031fb028,0x033fb029,0x033f4046,0x0287b86f, +0x029fb02a,0x8285009c,0x96b48000,0xb0158000, +0xb400018e,0x96b40100,0xb0150100,0xb40001a4, +0x96b40400,0xb0150400,0xb40001a5,0x96b40001, +0xb0150001,0xb400000c,0x96b40008,0xb0150008, +0xb4000197,0x96b44000,0xb0154000,0xb40001a4, +0x96b40002,0xb0150002,0xb400015b,0x00000000, +0x00000000,0xb50001b6,0x02bf917e,0x92b50001, +0x02bfb17e,0x82850082,0x5efdb814,0x96f70001, +0xb0170001,0xb420000b,0x83050069,0x9718003f, +0x82e50064,0x12f7b818,0x86f70109,0x82feff74, +0x02e7b86f,0x9af74000,0x01ffb817,0x96f7bfff, +0x01ffb817,0x83050081,0x82a5009a,0x96b50001, +0xb0150001,0xb4200014,0x82a70000,0x02bfb17e, +0x96b41840,0xb0150800,0xb420000c,0x96b40008, +0x5aa9b815,0x96d46000,0x5ec3b816,0x82f3000f, +0x9af7c00f,0x1718b817,0x1ab5b818,0x1ab5b816, +0x9ab50340,0x82a60081,0xb500012b,0x9b180180, +0x83060081,0xb5000128,0x82a5009a,0x96b50002, +0xb0150002,0xb420001b,0x82a70000,0x02bfb17e, +0x96b41800,0xb0151800,0xb4000013,0x96b40040, +0xb0150040,0xb4200004,0xa3180c00,0x9b180340, +0x83060081,0xb5000118,0x96b40008,0x5aa9b815, +0x96d46000,0x5ec3b816,0x82f3000f,0x9af7c00f, +0x1718b817,0x1ab5b818,0x1ab5b816,0x9ab50340, +0x82a60081,0xb500010c,0x9b180180,0x83060081, +0xb5000109,0x82a500c1,0x96b5000f,0xb015000b, +0xb420000e,0x96b40020,0xb0150020,0xb400000b, +0x96b40200,0xb0150200,0xb4000008,0x82c50086, +0x82e50094,0x3016b817,0xb4400004,0x06f7b816, +0xb017ff00,0xb4400001,0xb50000f7,0x96b46000, +0xb0156000,0xb4000011,0x96b41820,0xb0150820, +0xb4200004,0x9b391000,0x82a5009a,0x96b5feff, +0x82a6009a,0x96b40040,0xb0150040,0xb4200001, +0x9739efff,0x96b91000,0xb0151000,0xb4200003, +0x82a5009a,0x9ab50100,0x82a6009a,0x96b40040, +0xb0150040,0xb4200019,0x96b41800,0xb0151800, +0xb4200006,0x96b98000,0xb0158000,0xb4200003, +0x9b180180,0x83060081,0xb50000d7,0x96d80c00, +0x82b300ff,0x9ab5f3ff,0x1718b815,0xb0160c00, +0xb4000007,0x82e50098,0x96f70400,0xb0170400, +0xb4200002,0x82c70c00,0xb5000001,0xa2d60c00, +0x1b18b816,0x9b180340,0xb50000bd,0x96b40220, +0xb0150000,0xb4e00021,0x82a5009d,0x82f3ffff, +0x16b5b817,0x82f3000e,0x3015b817,0xb420001b, +0x96f98000,0xb0178000,0xb4000018,0x82a70000, +0x02bfb17e,0x82c5009d,0x96d6ffff,0x82b30032, +0x9ab58001,0x82e500c1,0x96f7000f,0xb017000b, +0xb4000002,0x82b30022,0x9ab58001,0x1ab5b816, +0x82c5009a,0x96d60020,0xb0160020,0xb4200002, +0x82b30032,0x9ab58001,0x82a6009d,0x02ff917e, +0x00000000,0xb0170040,0xb4800000,0x5eb5b814, +0x96b500f0,0x96f46000,0x5eedb817,0x1ab5b817, +0xb0170003,0xb4000004,0x96b500ef,0x96f70001, +0x5ae4b817,0x1ab5b817,0x96d41800,0xb0161800, +0xb400000a,0x96f900ff,0x96b500ff,0x9739ff00, +0x1b39b815,0x02a7b817,0x96b500f3,0x96d40008, +0x5ec1b816,0x1ab5b816,0xb500000c,0x96f98000, +0xb0178000,0xb4200007,0x5efeb814,0x96f70001, +0xb0170001,0xb4000003,0x9b180180,0x83060081, +0xb5000081,0x96b500f3,0x9ab50008,0x9739fff3, +0x96d40020,0xb0160020,0xb4200017,0x9b398000, +0x82c70000,0x02dfb17e,0x96d40010,0x5ac8b816, +0x82f300ff,0x9af7cfff,0x1718b817,0x1b18b816, +0x9b180340,0x82c5009d,0x96d6ffff,0x82f3000e, +0x9af78001,0x1af7b816,0x82c5009a,0x96d60020, +0xb0160020,0xb4200002,0x82f30032,0x9af78001, +0x82e6009d,0xb500005a,0x97397fff,0x96b500ff, +0x5aaab815,0x82f300fc,0x9af703ff,0x1718b817, +0x1b18b815,0x9b180340,0x82c5009a,0x96d60010, +0xb0160010,0xb4200024,0x82c70000,0x02dfb17e, +0x82c50086,0x92d60e10,0x82c60086,0x82c50094, +0x5eefb818,0x96f70003,0xb0170003,0xb4200002, +0x82e70e10,0xb5000001,0x82e70e10,0x12d6b817, +0x82e50081,0x9af70020,0x82e60081,0x82c60094, +0xa2f70020,0x82e60081,0x82f30001,0x16f7b818, +0x5ef0b817,0xb0170001,0xb4000004,0x96f84000, +0x5ee4b817,0x9718f3ff,0x1b18b817,0x82f3000a, +0x9af78000,0x82e6009d,0x83060081,0x83070001, +0x8306009f,0xb5000096,0x82c5009d,0x82f3000e, +0x9af78001,0x3016b817,0xb420000f,0x82b30032, +0x9ab58001,0x82e500c1,0x96f7000f,0xb017000b, +0xb4000002,0x82b30022,0x9ab58001,0x82c5009a, +0x96d60020,0xb0160020,0xb4200002,0x82b30032, +0x9ab58001,0x82a6009d,0x82c5009a,0x96d60080, +0xb0160080,0xb4000011,0x02df917e,0x00000000, +0xb0160010,0xb480000d,0x82c500c1,0x96d6000f, +0xb016000b,0xb4000009,0x82c50087,0x96d60080, +0x5ac7b816,0x96f84000,0x3017b816,0xb4200003, +0x033f4046,0x9b394000,0xb500000b,0x9739bfff, +0x82e50061,0x96f70008,0xb0170008,0xb4000005, +0x5eefb818,0x96f70003,0xb0170003,0xb4000001, +0x9718ffff,0x83060081,0x83070001,0x8306009f, +0x00000000,0xb500005e,0x82850083,0x96b400ff, +0xb015003c,0xb4200019,0x96b92000,0xb0152000, +0xb4000002,0x9b392000,0xb5000014,0x9739d3ff, +0x82870000,0x82860087,0x82870008,0x82860083, +0x829bff78,0x82a7001f,0xb0140400,0xb4000001, +0x82a70010,0x82a600c9,0x829bff78,0x00000000, +0x828600cb,0x8285009d,0x82b3ffff,0x9ab5fffd, +0x1694b815,0x8286009d,0xb5000000,0x83070002, +0x8306009f,0x00000000,0xb500003d,0x96b90800, +0xb0150800,0xb4200009,0x9739f7ff,0x82a703fd, +0x82a600cb,0x82a7003c,0x82a60083,0x8285009d, +0x9a940002,0x8286009d,0xb5000004,0x82850087, +0x5a82b814,0xa2940200,0x82860087,0xb5000000, +0x83078000,0x8306009f,0x00000000,0xb5000028, +0x83070008,0x8306009f,0x00000000,0xb5000024, +0x83070100,0x8306009f,0x00000000,0xb5000020, +0x83070000,0x83050081,0x9b180180,0x83060081, +0x83070400,0x8306009f,0x00000000,0xb5000018, +0x82870000,0x82850082,0x5eb7b814,0x96b500fc, +0x96d40006,0x5ec1b816,0x1ab5b816,0x5aacb815, +0x83050081,0x82d3001c,0x9ad600ff,0x1718b816, +0x1b18b815,0x9b180e00,0x83060081,0x83074000, +0x8306009f,0x8305009d,0x82d300ff,0x9ad6bfff, +0x1718b816,0x8306009d,0x00000000,0xb5000000, +0x029f902a,0x01ffb814,0x033f6046,0x029f9024, +0x02bf9025,0x02df9026,0x02ff9027,0x031f9028, +0x033f9029,0x00ffb81e,0x02ff917d,0x92f7092f, +0x031f0084,0xb0180001,0xb4200002,0x02ff917d, +0x92f70870,0x02ffb17d,0x02ff917c,0x82bbffdc, +0x829bffd8,0x93150004,0x3014b815,0xb4000017, +0x02dbb818,0x029bb815,0x3017b816,0xb4800013, +0x5a81b814,0x029fb17d,0x82def200,0x82fef204, +0x82e50086,0x06f7b814,0x02f6b817,0x82fef208, +0x82860095,0x82870001,0x829ef220,0x8293001f, +0x9294fe00,0x92b50008,0x3015b814,0xb4800002, +0x82b3001f,0x92b5fa00,0x82beffdc,0x82850086, +0x83250094,0x06d4b819,0x02d6b816,0xb016ffff, +0xb4a00009,0x82c50081,0x9ab60020,0x82a60081, +0x82a50086,0x92b50e10,0x82a60094,0x82c60081, +0x86b50704,0x82a6009b,0x00ffb81c,0x00000000, +0x001f9012,0x001fb200,0x001f004c,0x001f2804, +0x801bfef0,0x8058fef4,0x803bff68,0x8078ff6c, +0x2000b801,0x2042b803,0x001fb204,0x005f2814, +0x82e70001,0x83640048,0x029fb014,0x829efef0, +0x8286000f,0x02bf2054,0x82bcfef4,0x82a6000e, +0x00ffb81a,0x80e70001,0x801336e3,0x9800eb76, +0x001fb200,0x800700ab,0x001f2804,0x801bc3e8, +0x8058c3ec,0x83640024,0x82e70000,0x83640036, +0x029fb3c0,0x029fb200,0x02bf2f04,0x02bf2804, +0x801bc000,0x8058c004,0x8364001b,0x82e70000, +0x8364002d,0x001f93c0,0x3000b814,0xb420000a, +0x001f0f04,0x3000b815,0xb4200007,0x829efef0, +0x82bcfef4,0x029fb012,0x02bf204c,0x82870001, +0x829cfef5,0x00ffb81a,0xb0070000,0xb4000007, +0x80e70000,0x801399fa,0x9800c92e,0x001fb200, +0x800700af,0x001f2804,0xb500ffdc,0x82870000, +0x829cfef5,0x00ffb81a,0x80c700ff,0x803bff68, +0x8078ff6c,0x14a0b806,0x2063b805,0x007f2814, +0x2021b802,0x58c8b806,0x14a0b806,0x58b0b805, +0x2021b805,0x58c8b806,0x14a0b806,0x2021b805, +0x58c8b806,0x14a0b806,0x5cb0b805,0x2021b805, +0x003fb204,0x00ffb81b,0x82c70000,0x83070800, +0x83270005,0x8197080c,0x81d7ffff,0x83840126, +0x83840001,0x00ffb81b,0x808f0000,0x806f001f, +0x80af001f,0x80270240,0x81e77c08,0x5de2b80f, +0xb6000208,0x00cfb801,0x01ffb178,0x59e2b80f, +0x01cfb80f,0x01ff9178,0xb520ffff,0x91ef0020, +0x90210020,0x80270280,0x81e77b00,0x5de2b80f, +0xb6000208,0x00cfb801,0x01ffb178,0x59e2b80f, +0x01cfb80f,0x01ff9178,0xb520ffff,0x91ef0020, +0x90210020,0x8057ffff,0x80170830,0x80070810, +0x80270808,0xb6000509,0x005ff000,0x90420900, +0x007ff001,0x90630a00,0x009ff002,0x00bff003, +0x2004a025,0x90000001,0x90210001,0x80070814, +0x80d7ffff,0x8097085c,0x8017083c,0xb6000404, +0x005ff000,0x007f87e0,0x84000001,0x2082a7e3, +0x80970860,0x80170840,0x2082b803,0x007f8000, +0x2083a004,0x80170830,0x80970850,0x80270808, +0xb6000508,0x005f8024,0x90420900,0x007ff001, +0x90630a00,0x009ff002,0x00bff003,0x2004a025, +0x90210001,0x80170840,0x00000000,0x02bf87e0, +0x80970860,0x82870000,0xb6000404,0x005f87e4, +0x5a88b814,0x204287e0,0x1a94b802,0x00ffb81c, +0x001f0e49,0x001f2b09,0x001f0e41,0x001f2b08, +0x001f0e46,0x001f2b07,0x001f0e48,0x001f2b06, +0x001f0e42,0x001f2b05,0x001f0e47,0x001f2b04, +0x001f0e45,0x001f2b03,0x001f0e43,0x001f2b02, +0x001f0e40,0x001f2b01,0x001f0e44,0x001f2b00, +0x001f0f25,0xa020000c,0x94400001,0x94600002, +0x94810004,0x94a10008,0x94c00010,0x5943b802, +0x5861b803,0x5882b804,0x5ca2b805,0x5cc4b806, +0x194ab803,0x194ab804,0x194ab805,0x194ab806, +0x015f2b38,0x801b7c00,0x003f92c1,0x5c28b801, +0x005f92c2,0x5858b802,0x1821b802,0x2000b801, +0x001fb2c4,0x80187c04,0x003f0b09,0x2000b801, +0x001f2b14,0x82c70001,0x82e70001,0x83070b10, +0x8327001e,0x81970b35,0x8384009f,0x02df0b38, +0x82170e30,0x838400f1,0x819efef0,0x817cfef4, +0x819eff68,0x817cff6c,0x00ffb81b,0x820f001f, +0x8018fef8,0x8057ffff,0x001f2b09,0x8018fef6, +0x80d7ffff,0x001f2b08,0x8018fefa,0x8157ffff, +0x001f2b07,0x8018fefd,0x81d7ffff,0x001f2b06, +0x8018fefb,0x802f001f,0x001f2b05,0x8018fefe, +0x00000000,0x001f2b04,0x8018fef9,0x00000000, +0x001f2b03,0x8018feff,0x00000000,0x001f2b02, +0x8018fef7,0x00000000,0x001f2b01,0x8018fefc, +0x00000000,0x001f2b00,0x001f0f25,0xa0200011, +0x94410001,0x94600002,0x94800004,0x94a00008, +0x94c10010,0x5941b802,0x5861b803,0x5c82b804, +0x58a1b805,0x5cc1b806,0x194ab803,0x194ab804, +0x194ab805,0x194ab806,0x015f2b38,0x801b7c00, +0x003f92c1,0x5c28b801,0x005f92c2,0x5858b802, +0x1821b802,0x2000b801,0x001fb2c4,0x80187c04, +0x003f0b09,0x2000b801,0x001f2b14,0x82c70001, +0x82e70001,0x83070b10,0x8327001e,0x81970b35, +0x83840055,0x02df0b38,0x82170e20,0x838400a7, +0x819efef0,0x817cfef4,0x5ac8b80c,0x02ff0e44, +0x1ad6b817,0x02dfb391,0x5ed8b80c,0x5968b80b, +0x1ad6b80b,0x02df6724,0x00ffb81b,0x820f001f, +0x8018fefe,0x8057ffff,0x001f2b09,0x8018fefa, +0x80d7ffff,0x001f2b08,0x8018fefc,0x8157ffff, +0x001f2b07,0x8018feff,0x81d7ffff,0x001f2b06, +0x8018fef8,0x802f001f,0x001f2b05,0x8018fefb, +0x00000000,0x001f2b04,0x8018fefd,0x00000000, +0x001f2b03,0x8018fef6,0x00000000,0x001f2b02, +0x8018fef9,0x00000000,0x001f2b01,0x8018fef7, +0x00000000,0x001f2b00,0x801b7c00,0x003f92c1, +0x5c28b801,0x005f92c2,0x5858b802,0x1821b802, +0x2000b801,0x001fb2c4,0x80187c04,0x003f0b09, +0x2000b801,0x001f2b14,0x82c70001,0x82e70001, +0x83070b10,0x8327001e,0x81970b35,0x83840016, +0x83270000,0x831bfef0,0x82f8fef4,0x02c7b819, +0x82170e28,0x83840065,0x300cb818,0xb4200002, +0x300bb817,0xb4000006,0x93390001,0xb0190020, +0xb480fff6,0x83270000,0x833cfef5,0x00ffb81b, +0x019fb390,0x017f2e44,0x033f2f25,0x83270001, +0x833cfef5,0x00ffb81b,0x0007b818,0x90000003, +0x00000000,0x015ff000,0x90000001,0x5949b80a, +0x013ff000,0x194ab809,0x84000002,0x994a0100, +0x017ff000,0x958b00f8,0x5981b80c,0x956b0007, +0x198cb80b,0x84000002,0x998c0008,0x017ff000, +0x90000001,0x5971b80b,0x198cb80b,0x017ff000, +0x5969b80b,0x198cb80b,0x81a70000,0x94d90003, +0x82a70000,0xb6260019,0xb6000818,0x5df0b80a, +0x5e02b80a,0x21efb810,0x95ef0001,0x5941b80a, +0x194ab80f,0x21efb816,0x5e18b80c,0x5e35b80c, +0x5e54b80c,0x5e6cb80c,0x2210b811,0x2252b813, +0x2210b812,0x96100001,0x5981b80c,0x198cb810, +0x2210b817,0x10afb810,0x10a5b80d,0x5da1b805, +0x94a50001,0x5aa1b815,0x1ab5b805,0x019fa7f5, +0x5cc2b819,0xb626001c,0x82870000,0xb6000419, +0xb6000818,0x5df0b80a,0x5e02b80a,0x21efb810, +0x95ef0001,0x5941b80a,0x194ab80f,0x21efb816, +0x5e18b80c,0x5e35b80c,0x5e54b80c,0x5e6cb80c, +0x2210b811,0x2252b813,0x2210b812,0x96100001, +0x5981b80c,0x198cb810,0x2210b817,0x10afb810, +0x10a5b80d,0x5da1b805,0x94a50001,0x5a81b814, +0x1a94b805,0x019fa7f4,0x00ffb81c,0x8257ffff, +0x808f0000,0x806f001f,0x80af001f,0x80270300, +0x81e778e0,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x80270340, +0x81e779e0,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x80270280, +0x81e77b00,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x806f0007, +0x80af0007,0x80270380,0x81e77ae0,0x5de2b80f, +0x00cfb801,0x01ffb178,0x59e2b80f,0x01cfb80f, +0x01ff9178,0xb520ffff,0x91ef0020,0x90210020, +0x80170b60,0x001f0b00,0x001fa020,0x001f0b01, +0x001fa020,0x001f0b02,0x001fa020,0x001f0b03, +0x001fa020,0x001f0b04,0x001fa000,0x80970b50, +0x81170b70,0x82a70b35,0x83a40060,0x001f87e4, +0xb6000405,0x86b50001,0x83a4005c,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b70,0x80170b50, +0x81170b50,0x81970b40,0x82a70b30,0x001f800c, +0x003f8008,0x2100a001,0x83a40050,0x001f87e4, +0xb6000405,0x86b50001,0x83a4004c,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b50,0x80170b70, +0x81170b70,0x81970b60,0x82a70b2b,0x001f800c, +0x003f8008,0x2100a001,0x83a40040,0x83a4004e, +0xb6000407,0x86b50001,0x83a4003c,0x001f8004, +0x003f87e8,0x2080a001,0x83a40047,0x00000000, +0x80970b70,0x80170b50,0x81170b50,0x81970b40, +0x82a70b26,0x001f800c,0x003f8008,0x2100a001, +0x83a4002e,0x83a4003c,0xb6000407,0x86b50001, +0x83a4002a,0x001f8004,0x003f87e8,0x2080a001, +0x83a40035,0x00000000,0x80970b50,0x80170b70, +0x81170b70,0x81970b60,0x82a70b21,0x001f800c, +0x003f8008,0x2100a001,0x83a4001c,0x001f87e4, +0xb6000405,0x86b50001,0x83a40018,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b70,0x80170b50, +0x81170b50,0x81970b40,0x82a70b1c,0x001f800c, +0x003f8008,0x2100a001,0x83a4000c,0x017f87e4, +0x81870000,0xb6000406,0x86b50001,0x83a40007, +0x001f87e4,0x200087e8,0x5988b80c,0x198cb800, +0x021fa02c,0x021fa00b,0x00ffb81c,0x005ff015, +0x90420a00,0x003f87e0,0x001ff002,0x2060b801, +0x90630c00,0x90960e00,0x001ff003,0x003ff004, +0x20a0b801,0x90a50d00,0x00000000,0x001ff005, +0x009fa000,0x00ffb81d,0x001f8004,0x5c21b800, +0x5847b800,0x1821b802,0x942100ff,0x2080a7e1, +0x00ffb81d,0x00000000,0x00000000,0x00000000, + +}; + +static u32 MPGUcode1f5c00[] = { +0x00000000,0xfffff8c0,0x00003540,0xffff8d40, +0x0001fd40,0xfffaf7c0,0x00066b80,0xffdb63c0, +0x00494780,0x00249c40,0x00066b80,0x00050840, +0x0001fd40,0x000072c0,0x00003540,0x00000740, +0xffffffc0,0xfffff840,0x00003680,0xffff7e40, +0x0001f400,0xfffa9cc0,0x0005d1c0,0xffd99600, +0x00493c00,0x0022ce00,0x0006f780,0x0004ad00, +0x000203c0,0x00006440,0x00003400,0x00000680, +0xffffffc0,0xfffff740,0x00003780,0xffff6ec0, +0x0001e800,0xfffa4240,0x00052a00,0xffd7ca00, +0x00491a00,0x0020ffc0,0x00077600,0x00045240, +0x00020800,0x000056c0,0x00003280,0x00000600, +0xffffffc0,0xfffff680,0x00003840,0xffff5ec0, +0x0001d940,0xfff9e8c0,0x00047440,0xffd60080, +0x0048e180,0x001f32c0,0x0007e700,0x0003f7c0, +0x000209c0,0x00004980,0x00003100,0x00000540, +0xffffffc0,0xfffff5c0,0x000038c0,0xffff4e40, +0x0001c780,0xfff990c0,0x0003b000,0xffd43ac0, +0x00489240,0x001d6800,0x00084b00,0x00039e40, +0x00020940,0x00003d00,0x00002f80,0x000004c0, +0xffffffc0,0xfffff4c0,0x00003900,0xffff3d40, +0x0001b2c0,0xfff93a40,0x0002ddc0,0xffd279c0, +0x00482d00,0x001ba040,0x0008a200,0x000345c0, +0x000206c0,0x00003140,0x00002dc0,0x00000440, +0xffffffc0,0xfffff3c0,0x00003900,0xffff2c00, +0x00019b00,0xfff8e640,0x0001fd40,0xffd0be80, +0x0047b1c0,0x0019dc80,0x0008ecc0,0x0002ef00, +0x00020240,0x00002640,0x00002c00,0x00000400, +0xffffff80,0xfffff2c0,0x000038c0,0xffff1a40, +0x00017fc0,0xfff894c0,0x00010e80,0xffcf09c0, +0x004720c0,0x00181d80,0x00092b40,0x000299c0, +0x0001fc00,0x00001bc0,0x00002a40,0x00000380, +0xffffff80,0xfffff180,0x00003800,0xffff0840, +0x00016180,0xfff84680,0x00001180,0xffcd5cc0, +0x00467a40,0x00166440,0x00095e00,0x00024680, +0x0001f440,0x00001200,0x00002840,0x00000340, +0xffffff80,0xfffff040,0x00003740,0xfffef600, +0x00014000,0xfff7fbc0,0xffff0680,0xffcbb880, +0x0045bf00,0x0014b140,0x00098580,0x0001f580, +0x0001ea80,0x00000900,0x00002680,0x000002c0, +0xffffff80,0xffffef00,0x000035c0,0xfffee3c0, +0x00011ac0,0xfff7b540,0xfffded80,0xffca1d80, +0x0044ef80,0x00130580,0x0009a1c0,0x0001a700, +0x0001dfc0,0x00000080,0x000024c0,0x00000280, +0xffffff40,0xffffedc0,0x00003400,0xfffed180, +0x0000f280,0xfff77340,0xfffcc700,0xffc88d80, +0x00440bc0,0x001161c0,0x0009b3c0,0x00015b00, +0x0001d380,0xfffff8c0,0x000022c0,0x00000240, +0xffffff40,0xffffec40,0x00003200,0xfffebf40, +0x0000c680,0xfff73680,0xfffb92c0,0xffc708c0, +0x00431500,0x000fc6c0,0x0009bb80,0x000111c0, +0x0001c640,0xfffff1c0,0x00002100,0x00000200, +0xffffff00,0xffffeac0,0x00002f40,0xfffead00, +0x00009740,0xfff6ff40,0xfffa5180,0xffc59080, +0x00420b40,0x000e3500,0x0009b9c0,0x0000cb80, +0x0001b7c0,0xffffeb40,0x00001f40,0x000001c0, +0xffffff00,0xffffe940,0x00002c40,0xfffe9b00, +0x00006480,0xfff6ce00,0xfff90380,0xffc425c0, +0x0040ef80,0x000cad00,0x0009af00,0x00008840, +0x0001a880,0xffffe580,0x00001d40,0x000001c0, +0xfffffec0,0xffffe7c0,0x000028c0,0xfffe8980, +0x00002e40,0xfff6a3c0,0xfff7a900,0xffc2c900, +0x003fc280,0x000b2fc0,0x00099b80,0x00004800, +0x00019880,0xffffe040,0x00001bc0,0x00000180, +0xfffffec0,0xffffe600,0x00002480,0xfffe7840, +0xfffff4c0,0xfff68040,0xfff64240,0xffc17b40, +0x003e84c0,0x0009bdc0,0x00097fc0,0x00000b40, +0x000187c0,0xffffdb80,0x00001a00,0x00000140, +0xfffffe80,0xffffe440,0x00001fc0,0xfffe6780, +0xffffb800,0xfff66480,0xfff4d040,0xffc03d80, +0x003d3700,0x00085700,0x00095c40,0xffffd1c0, +0x00017680,0xffffd740,0x00001840,0x00000140, +0xfffffe40,0xffffe2c0,0x00001a80,0xfffe5780, +0xffff77c0,0xfff65100,0xfff35300,0xffbf1080, +0x003bda40,0x0006fc80,0x00093200,0xffff9b80, +0x00016500,0xffffd3c0,0x000016c0,0x00000100, +0xfffffe40,0xffffe0c0,0x000014c0,0xfffe4840, +0xffff3480,0xfff64640,0xfff1cb00,0xffbdf4c0, +0x003a6f80,0x0005ae80,0x000900c0,0xffff68c0, +0x00015300,0xffffd0c0,0x00001540,0x00000100, +0xfffffe00,0xffffdf00,0x00000e40,0xfffe39c0, +0xfffeee40,0xfff64480,0xfff03940,0xffbceb00, +0x0038f740,0x00046d40,0x0008c980,0xffff3980, +0x000140c0,0xffffce00,0x000013c0,0x000000c0, +0xfffffdc0,0xffffdd40,0x00000740,0xfffe2c80, +0xfffea500,0xfff64c40,0xffee9e40,0xffbbf440, +0x00377280,0x00033900,0x00088cc0,0xffff0d80, +0x00012e80,0xffffcc00,0x00001240,0x000000c0, +0xfffffd80,0xffffdb40,0xffffff80,0xfffe2040, +0xfffe5900,0xfff65e40,0xffecfa80,0xffbb1080, +0x0035e280,0x00021280,0x00084ac0,0xfffee540, +0x00011c40,0xffffca40,0x00001100,0x00000080, +0xfffffd40,0xffffd980,0xfffff700,0xfffe1580, +0xfffe0a80,0xfff67a80,0xffeb4ec0,0xffba4100, +0x00344780,0x0000f980,0x00080440,0xfffec000, +0x00010a00,0xffffc8c0,0x00000fc0,0x00000080, +0xfffffcc0,0xffffd7c0,0xffffee00,0xfffe0bc0, +0xfffdb980,0xfff6a200,0xffe99bc0,0xffb985c0, +0x0032a340,0xffffee80,0x0007b980,0xfffe9e80, +0x0000f7c0,0xffffc800,0x00000e80,0x00000080, +0xfffffc80,0xffffd5c0,0xffffe440,0xfffe0400, +0xfffd6640,0xfff6d4c0,0xffe7e280,0xffb8df40, +0x0030f640,0xfffef180,0x00076b40,0xfffe8040, +0x0000e5c0,0xffffc740,0x00000d40,0x00000080, +0xfffffc00,0xffffd400,0xffffd9c0,0xfffdfdc0, +0xfffd1100,0xfff71340,0xffe62380,0xffb84e40, +0x002f4180,0xfffe02c0,0x000719c0,0xfffe6500, +0x0000d400,0xffffc700,0x00000c40,0x00000040, +0xfffffbc0,0xffffd240,0xffffcec0,0xfffdf940, +0xfffcba40,0xfff75e00,0xffe45fc0,0xffb7d300, +0x002d8640,0xfffd2240,0x0006c5c0,0xfffe4d40, +0x0000c2c0,0xffffc700,0x00000b40,0x00000040, +0xfffffb40,0xffffd080,0xffffc300,0xfffdf6c0, +0xfffc61c0,0xfff7b500,0xffe29800,0xffb76dc0, +0x002bc540,0xfffc5000,0x00066f40,0xfffe3880, +0x0000b1c0,0xffffc740,0x00000a40,0x00000040, +0xfffffac0,0xffffcf00,0xffffb680,0xfffdf640, +0xfffc0840,0xfff81900,0xffe0cd40,0xffb71e80, +0x0029ff80,0xfffb8bc0,0x00061740,0xfffe26c0, +0x0000a140,0xffffc7c0,0x00000980,0x00000040, +0xfffffa00,0xffffcd80,0xffffa940,0xfffdf800, +0xfffbadc0,0xfff88a00,0xffdf0040,0xffb6e600, +0x00283600,0xfffad600,0x0005bdc0,0xfffe1800, +0x00009140,0xffffc880,0x000008c0,0x00000040, +0xfffff980,0xffffcc00,0xffff9bc0,0xfffdfc40, +0xfffb5300,0xfff90880,0xffdd3200,0xffb6c400, +0x00266a00,0xfffa2e40,0x00056340,0xfffe0c00, +0x000081c0,0xffffc980,0x000007c0,0x00000040, +0x004013c2,0x0040b346,0x0041fa2d,0x0043f934, +0x0046cc1c,0x004a9d9d,0x004fae37,0x0056601f, +0x005f4cf7,0x006b6fcf,0x007c7d1e,0x0115b035, +0x013df91b,0x0207655e,0x03342c83,0x0a185230, +0x00404f46,0x0042e13c,0x0048919f,0x0052cb0e, +0x0064e240,0x0107c449,0x015c7926,0x050cf270, +0x004140fb,0x004cf8df,0x0073326c,0x02480d9d, +0x004545ea,0x01273d75,0x005a827a,0x007fffff, +0x006597fb,0x0050a28c,0x00400000,0x0032cbfd, +0x00285146,0x00200000,0x001965ff,0x001428a3, +0x00100000,0x000cb2ff,0x000a1451,0x00080000, +0x00065980,0x00050a29,0x00040000,0x00032cc0, +0x00028514,0x00020000,0x00019660,0x0001428a, +0x00010000,0x0000cb30,0x0000a145,0x00008000, +0x00006598,0x000050a3,0x00004000,0x000032cc, +0x00002851,0x00002000,0x00001966,0x00001429, +0x00001000,0x00000cb3,0x00000a14,0x00000800, +0x00000659,0x0000050a,0x00000400,0x0000032d, +0x00000285,0x00000200,0x00000196,0x00000143, +0x00000100,0x000000cb,0x000000a1,0x00000080, +0x00000066,0x00000051,0x00000040,0x00000033, +0x00000028,0x00000020,0x00000019,0x00000014, +0x00000010,0x0000000d,0x0000000a,0x00000008, +0x00000006,0x00000005,0x00000000,0x00555555, +0x00666666,0x00492492,0x0071c71c,0x00444444, +0x00421084,0x00410410,0x00408102,0x00404040, +0x00402010,0x00401004,0x00400801,0x00400400, +0x00400200,0x00400100,0x00400080,0x00400040, +0x00400000,0x00400000,0x00200000,0x00400000, +0x00100000,0x00080000,0x00040000,0x00020000, +0x00010000,0x00008000,0x00004000,0x00002000, +0x00001000,0x00000800,0x00000400,0x00000200, +0x00000100,0x0003588d,0x0002b15e,0x0002056d, +0x00015600,0x0000a329,0xffffeed9,0xffff3960, +0xfffe8423,0xfffdd11c,0xfffd2048,0xfffc7353, +0xfffbcb6f,0xfffb29a6,0xfffa8f15,0x000494ae, +0x0003f991,0x00032dd1,0xfffd2d8f,0x0001eb47, +0xfffe9968,0x00009af6,0x000011de,0xffff4335, +0x00018d69,0xfffdecd4,0x000302f8,0xfffca0d7, +0x0004683d,0xfffb67f8,0x0005b36d,0x00045963, +0xfffbd51e,0x00030062,0xfffd0dee,0x0001d046, +0xfffe8a0a,0x00009258,0x000012b1,0xffff4d9e, +0x00019ec3,0xfffe0a44,0x0003245a,0xfffcd082, +0x000498f0,0xfffba919,0x0005f304,0x00041bf4, +0xfffba72a,0x0002d19e,0xfffcf060,0x0001b407, +0xfffe7c08,0x0000894a,0x0000138d,0xffff58ac, +0x0001afaf,0xfffe28fe,0x000343bf,0xfffd026f, +0x0004c6f6,0xfffbed06,0x00062e61,0x0003dc0e, +0xfffb7bf1,0x0002a17f,0xfffcd522,0x000196a0, +0xfffe6e70,0x00007ff6,0x00001439,0xffff63f6, +0x0001beb3,0xfffe4882,0x0003616d,0xfffd361b, +0x0004f1cf,0xfffc332a,0x0006658f,0x00039943, +0xfffb52c0,0x00026ec7,0xfffcbb94,0x0001789f, +0xfffe6160,0x00007677,0x000014d4,0xffff6f74, +0x0001cc9b,0xfffe694f,0x00037cbf,0xfffd6b41, +0x000519c2,0xfffc7baf,0x00069971,0x00035486, +0xfffb2d0c,0x00023ad8,0xfffca3ee,0x00015989, +0xfffe55af,0x00006ca7,0x00001570,0xffff7b71, +0x0001d9cb,0xfffe8b46,0x0003959e,0xfffda1fe, +0x00053ee6,0xfffcc6b4,0x0006c950,0x00030e08, +0xfffb0a7a,0x0002061e,0xfffc8ec0,0x00013911, +0xfffe4b1d,0x00006278,0x000015e8,0xffff87b6, +0x0001e577,0xfffeadd6,0x0003acc2,0xfffdda34, +0x00056059,0xfffd136d,0x0006f4b5,0x0002c562, +0xfffaea7c,0x0001cfa6,0xfffc7b14,0x0001182b, +0xfffe4159,0x00005817,0x0000165c,0xffff9417, +0x0001f00f,0xfffed14c,0x0003c199,0xfffe13f6, +0x00057e83,0xfffd61cd,0x00071ba1,0x00027ab5, +0xfffacdc3,0x00019833,0xfffc6989,0x0000f6ca, +0xfffe38da,0x00004d9d,0x000016ef,0xffffa103, +0x0001f98f,0xfffef5c0,0x0003d3d1,0xfffe4f00, +0x0005998c,0xfffdb21e,0x00073e77,0x00022e75, +0xfffab482,0x00015fd1,0xfffc5b13,0x0000d45d, +0xfffe318f,0x000042ed,0x0000176b,0xffffae8f, +0x0002018f,0xffff1a91,0x0003e40c,0xfffe8af2, +0x0005b0ca,0xfffe03b8,0x00075d14,0x0001e141, +0xfffa9e9b,0x0001262a,0xfffc4e31,0x0000b1af, +0xfffe2b26,0x00003805,0x000017b1,0xffffbc21, +0x000208b8,0xffff3fb6,0x0003f1d7,0xfffec7af, +0x0005c4c5,0xfffe5654,0x0007768a,0x000192fe, +0xfffa8bb0,0x0000ec3f,0xfffc4365,0x00008ec9, +0xfffe25f0,0x00002d05,0x000017ec,0xffffc984, +0x00020ec6,0xffff658d,0x0003fcba,0xffff0500, +0x0005d576,0xfffeaa37,0x00078bc6,0x00014367, +0xfffa7bec,0x0000b1f4,0xfffc3b82,0x00006b06, +0xfffe2201,0x000021eb,0x00001823,0xffffd704, +0x0002132a,0xffff8be7,0x00040534,0xffff4315, +0x0005e22e,0xfffeff0a,0x00079ce3,0x0000f33f, +0xfffa6fc9,0x000076ca,0xfffc3558,0x00004762, +0xfffe1ef3,0x000016a1,0x0000183f,0xffffe4a6, +0x00021664,0xffffb27d,0x00040b7b,0xffff81e5, +0x0005eb4e,0xffff5475,0x0007a857,0x0000a2cb, +0xfffa671b,0x00003b64,0xfffc31e2,0x00002416, +0xfffe1ce1,0x00000b46,0x00001850,0xfffff24d, +0x00021855,0xffffd93a,0x00040f75,0xffffc0e6, +0x0005f0e3,0xffffaa3e,0x0007af45,0x0000519f, +0xfffa6218,0x0003f991,0x0003588d,0x0002b15e, +0x0002056d,0x00015600,0x0000a329,0xffffeed9, +0xffff3960,0xfffe8423,0xfffdd11c,0xfffd2048, +0xfffc7353,0xfffbcb6f,0xfffb29a6,0xfffa8f15, +0x000494ae,0x0003c6b0,0xfffc7e8b,0x00028ef6, +0xfffde181,0x000144eb,0xffff5500,0xffffefb9, +0x0000d01d,0xfffe9755,0x000249a4,0xfffd453c, +0x0003b80e,0xfffc01aa,0x000511d6,0xfffad527, +0xfffb334e,0x0003916c,0xfffc5778,0x00026a92, +0xfffdc9f5,0x00013314,0xffff4d99,0xfffff0b6, +0x0000d911,0xfffeab80,0x00026369,0xfffd6c0a, +0x0003e17f,0xfffc39d8,0x000549df,0xfffb1eb2, +0xfffafe6c,0x00035929,0xfffc3321,0x000244a6, +0xfffdb402,0x00012035,0xffff46ac,0xfffff192, +0x0000e16a,0xfffebfe0,0x00027b3d,0xfffd9433, +0x0004087b,0xfffc74b7,0x00057e8d,0xfffb6a81, +0xfffacc1c,0x00031fbe,0xfffc10df,0x00021e0c, +0xfffd9f6d,0x00010cb7,0xffff402e,0xfffff279, +0x0000e965,0xfffed574,0x00029159,0xfffdbdc4, +0x00042c4c,0xfffcb1e7,0x0005b02d,0xfffbb942, +0xfffa9d38,0x0002e44a,0xfffbf0fd,0x0001f5b4, +0xfffd8c38,0x0000f8b1,0xffff3a21,0xfffff391, +0x0000f0e6,0xfffeec44,0x0002a642,0xfffde90e, +0x00044e32,0xfffcf0fb,0x0005de46,0xfffc0b18, +0xfffa71d1,0x0002a659,0xfffbd3de,0x0001cb90, +0xfffd7a97,0x0000e403,0xffff3490,0xfffff49c, +0x0000f7a8,0xffff0340,0x0002b95f,0xfffe1573, +0x00046dbe,0xfffd3284,0x00060888,0xfffc5f51, +0xfffa4996,0x00026786,0xfffbb8df,0x0001a0e1, +0xfffd6a4e,0x0000ced2,0xffff2f75,0xfffff593, +0x0000fdbe,0xffff1a53,0x0002ca87,0xfffe42f5, +0x0004898a,0xfffd7563,0x00062f0b,0xfffcb5de, +0xfffa2508,0x00022713,0xfffba0bf,0x0001754a, +0xfffd5b5f,0x0000b92c,0xffff2acd,0xfffff6b0, +0x0001034f,0xffff3241,0x0002da5c,0xfffe71c6, +0x0004a341,0xfffdb946,0x000651e8,0xfffd0e37, +0xfffa0402,0x0001e4d4,0xfffb8b9c,0x00014898, +0xfffd4e7d,0x0000a304,0xffff26b7,0xfffff7e1, +0x00010846,0xffff4b34,0x0002e897,0xfffea13f, +0x0004ba63,0xfffdff2d,0x00067115,0xfffd6839, +0xfff9e680,0x0001a1fa,0xfffb789e,0x00011b2e, +0xfffd43a4,0x00008c6e,0xffff2341,0xfffff8fd, +0x00010c9c,0xffff6469,0x0002f48f,0xfffed1a4, +0x0004cd6a,0xfffe4608,0x00068c1b,0xfffdc409, +0xfff9cd15,0x00015dfe,0xfffb68a0,0x0000ecee, +0xfffd3a2e,0x0000757d,0xffff204b,0xfffffa1e, +0x00011054,0xffff7da1,0x0002fe9c,0xffff033e, +0x0004de57,0xfffe8dc6,0x0006a2d5,0xfffe213e, +0xfff9b77d,0x000118d3,0xfffb5bde,0x0000be25, +0xfffd3224,0x00005e52,0xffff1dc1,0xfffffb4b, +0x00011353,0xffff9740,0x00030748,0xffff351c, +0x0004ec95,0xfffed755,0x0006b5b4,0xfffe7fc6, +0xfff9a599,0x0000d334,0xfffb519f,0x00008f08, +0xfffd2bbf,0x00004704,0xffff1bc1,0xfffffc71, +0x00011598,0xffffb135,0x00030e43,0xffff6720, +0x0004f6f3,0xffff2119,0x0006c46e,0xfffedf38, +0xfff997c7,0x00008d13,0xfffb4a55,0x00005fa5, +0xfffd273b,0x00002f76,0xffff1a63,0xfffffda0, +0x00011744,0xffffcb67,0x000312ff,0xffff99cf, +0x0004ff0c,0xffff6a9c,0x0006cebd,0xffff3f0a, +0xfff98dbe,0x00004691,0xfffb4620,0x00003010, +0xfffd24fc,0x000017b5,0xffff199d,0xfffffed8, +0x0001185a,0xffffe5c6,0x0003157e,0xffffcce3, +0x000503ae,0xffffb515,0x0006d537,0xffff9f5a, +0xfff98767,0xfffb44b0,0xfffc3131,0xfffd2475, +0xfffe1c28,0xffff195d,0x00001859,0x000118bd, +0x000218df,0x0003163a,0x000410e0,0x000504a7, +0x0005f2b3,0x0006d796,0x0007b1fe,0xfff98537, +0xfffa609b,0xfffc7e8b,0x00028ef6,0xfffde181, +0x000144eb,0xffff5500,0xffffefb9,0x0000d01d, +0xfffe9755,0x000249a4,0xfffd453c,0x0003b80e, +0xfffc01aa,0x000511d6,0xfffad527,0xfffb334e, +0x0003c6b0,0xfffc5778,0x00026a92,0xfffdc9f5, +0x00013314,0xffff4d99,0xfffff0b6,0x0000d911, +0xfffeab80,0x00026369,0xfffd6c0a,0x0003e17f, +0xfffc39d8,0x000549df,0xfffb1eb2,0xfffafe6c, +0x0003916c,0xfffc3321,0x000244a6,0xfffdb402, +0x00012035,0xffff46ac,0xfffff192,0x0000e16a, +0xfffebfe0,0x00027b3d,0xfffd9433,0x0004087b, +0xfffc74b7,0x00057e8d,0xfffb6a81,0xfffacc1c, +0x00035929,0xfffc10df,0x00021e0c,0xfffd9f6d, +0x00010cb7,0xffff402e,0xfffff279,0x0000e965, +0xfffed574,0x00029159,0xfffdbdc4,0x00042c4c, +0xfffcb1e7,0x0005b02d,0xfffbb942,0xfffa9d38, +0x00031fbe,0xfffbf0fd,0x0001f5b4,0xfffd8c38, +0x0000f8b1,0xffff3a21,0xfffff391,0x0000f0e6, +0xfffeec44,0x0002a642,0xfffde90e,0x00044e32, +0xfffcf0fb,0x0005de46,0xfffc0b18,0xfffa71d1, +0x0002e44a,0xfffbd3de,0x0001cb90,0xfffd7a97, +0x0000e403,0xffff3490,0xfffff49c,0x0000f7a8, +0xffff0340,0x0002b95f,0xfffe1573,0x00046dbe, +0xfffd3284,0x00060888,0xfffc5f51,0xfffa4996, +0x0002a659,0xfffbb8df,0x0001a0e1,0xfffd6a4e, +0x0000ced2,0xffff2f75,0xfffff593,0x0000fdbe, +0xffff1a53,0x0002ca87,0xfffe42f5,0x0004898a, +0xfffd7563,0x00062f0b,0xfffcb5de,0xfffa2508, +0x00026786,0xfffba0bf,0x0001754a,0xfffd5b5f, +0x0000b92c,0xffff2acd,0xfffff6b0,0x0001034f, +0xffff3241,0x0002da5c,0xfffe71c6,0x0004a341, +0xfffdb946,0x000651e8,0xfffd0e37,0xfffa0402, +0x00022713,0xfffb8b9c,0x00014898,0xfffd4e7d, +0x0000a304,0xffff26b7,0xfffff7e1,0x00010846, +0xffff4b34,0x0002e897,0xfffea13f,0x0004ba63, +0xfffdff2d,0x00067115,0xfffd6839,0xfff9e680, +0x0001e4d4,0xfffb789e,0x00011b2e,0xfffd43a4, +0x00008c6e,0xffff2341,0xfffff8fd,0x00010c9c, +0xffff6469,0x0002f48f,0xfffed1a4,0x0004cd6a, +0xfffe4608,0x00068c1b,0xfffdc409,0xfff9cd15, +0x0001a1fa,0xfffb68a0,0x0000ecee,0xfffd3a2e, +0x0000757d,0xffff204b,0xfffffa1e,0x00011054, +0xffff7da1,0x0002fe9c,0xffff033e,0x0004de57, +0xfffe8dc6,0x0006a2d5,0xfffe213e,0xfff9b77d, +0x00015dfe,0xfffb5bde,0x0000be25,0xfffd3224, +0x00005e52,0xffff1dc1,0xfffffb4b,0x00011353, +0xffff9740,0x00030748,0xffff351c,0x0004ec95, +0xfffed755,0x0006b5b4,0xfffe7fc6,0xfff9a599, +0x000118d3,0xfffb519f,0x00008f08,0xfffd2bbf, +0x00004704,0xffff1bc1,0xfffffc71,0x00011598, +0xffffb135,0x00030e43,0xffff6720,0x0004f6f3, +0xffff2119,0x0006c46e,0xfffedf38,0xfff997c7, +0x0000d334,0xfffb4a55,0x00005fa5,0xfffd273b, +0x00002f76,0xffff1a63,0xfffffda0,0x00011744, +0xffffcb67,0x000312ff,0xffff99cf,0x0004ff0c, +0xffff6a9c,0x0006cebd,0xffff3f0a,0xfff98dbe, +0x00008d13,0xfffb4620,0x00003010,0xfffd24fc, +0x000017b5,0xffff199d,0xfffffed8,0x0001185a, +0xffffe5c6,0x0003157e,0xffffcce3,0x000503ae, +0xffffb515,0x0006d537,0xffff9f5a,0xfff98767, +0x00004691,0xfffa609b,0xfffb44b0,0xfffc3131, +0xfffd2475,0xfffe1c28,0xffff195d,0x00001859, +0x000118bd,0x000218df,0x0003163a,0x000410e0, +0x000504a7,0x0005f2b3,0x0006d796,0x0007b1fe, +0xfff98537,0xfffbd51e,0x00032dd1,0xfffd2d8f, +0x0001eb47,0xfffe9968,0x00009af6,0x000011de, +0xffff4335,0x00018d69,0xfffdecd4,0x000302f8, +0xfffca0d7,0x0004683d,0xfffb67f8,0x0005b36d, +0x00045963,0xfffba72a,0x00030062,0xfffd0dee, +0x0001d046,0xfffe8a0a,0x00009258,0x000012b1, +0xffff4d9e,0x00019ec3,0xfffe0a44,0x0003245a, +0xfffcd082,0x000498f0,0xfffba919,0x0005f304, +0x00041bf4,0xfffb7bf1,0x0002d19e,0xfffcf060, +0x0001b407,0xfffe7c08,0x0000894a,0x0000138d, +0xffff58ac,0x0001afaf,0xfffe28fe,0x000343bf, +0xfffd026f,0x0004c6f6,0xfffbed06,0x00062e61, +0x0003dc0e,0xfffb52c0,0x0002a17f,0xfffcd522, +0x000196a0,0xfffe6e70,0x00007ff6,0x00001439, +0xffff63f6,0x0001beb3,0xfffe4882,0x0003616d, +0xfffd361b,0x0004f1cf,0xfffc332a,0x0006658f, +0x00039943,0xfffb2d0c,0x00026ec7,0xfffcbb94, +0x0001789f,0xfffe6160,0x00007677,0x000014d4, +0xffff6f74,0x0001cc9b,0xfffe694f,0x00037cbf, +0xfffd6b41,0x000519c2,0xfffc7baf,0x00069971, +0x00035486,0xfffb0a7a,0x00023ad8,0xfffca3ee, +0x00015989,0xfffe55af,0x00006ca7,0x00001570, +0xffff7b71,0x0001d9cb,0xfffe8b46,0x0003959e, +0xfffda1fe,0x00053ee6,0xfffcc6b4,0x0006c950, +0x00030e08,0xfffaea7c,0x0002061e,0xfffc8ec0, +0x00013911,0xfffe4b1d,0x00006278,0x000015e8, +0xffff87b6,0x0001e577,0xfffeadd6,0x0003acc2, +0xfffdda34,0x00056059,0xfffd136d,0x0006f4b5, +0x0002c562,0xfffacdc3,0x0001cfa6,0xfffc7b14, +0x0001182b,0xfffe4159,0x00005817,0x0000165c, +0xffff9417,0x0001f00f,0xfffed14c,0x0003c199, +0xfffe13f6,0x00057e83,0xfffd61cd,0x00071ba1, +0x00027ab5,0xfffab482,0x00019833,0xfffc6989, +0x0000f6ca,0xfffe38da,0x00004d9d,0x000016ef, +0xffffa103,0x0001f98f,0xfffef5c0,0x0003d3d1, +0xfffe4f00,0x0005998c,0xfffdb21e,0x00073e77, +0x00022e75,0xfffa9e9b,0x00015fd1,0xfffc5b13, +0x0000d45d,0xfffe318f,0x000042ed,0x0000176b, +0xffffae8f,0x0002018f,0xffff1a91,0x0003e40c, +0xfffe8af2,0x0005b0ca,0xfffe03b8,0x00075d14, +0x0001e141,0xfffa8bb0,0x0001262a,0xfffc4e31, +0x0000b1af,0xfffe2b26,0x00003805,0x000017b1, +0xffffbc21,0x000208b8,0xffff3fb6,0x0003f1d7, +0xfffec7af,0x0005c4c5,0xfffe5654,0x0007768a, +0x000192fe,0xfffa7bec,0x0000ec3f,0xfffc4365, +0x00008ec9,0xfffe25f0,0x00002d05,0x000017ec, +0xffffc984,0x00020ec6,0xffff658d,0x0003fcba, +0xffff0500,0x0005d576,0xfffeaa37,0x00078bc6, +0x00014367,0xfffa6fc9,0x0000b1f4,0xfffc3b82, +0x00006b06,0xfffe2201,0x000021eb,0x00001823, +0xffffd704,0x0002132a,0xffff8be7,0x00040534, +0xffff4315,0x0005e22e,0xfffeff0a,0x00079ce3, +0x0000f33f,0xfffa671b,0x000076ca,0xfffc3558, +0x00004762,0xfffe1ef3,0x000016a1,0x0000183f, +0xffffe4a6,0x00021664,0xffffb27d,0x00040b7b, +0xffff81e5,0x0005eb4e,0xffff5475,0x0007a857, +0x0000a2cb,0xfffa6218,0x00003b64,0xfffc31e2, +0x00002416,0xfffe1ce1,0x00000b46,0x00001850, +0xfffff24d,0x00021855,0xffffd93a,0x00040f75, +0xffffc0e6,0x0005f0e3,0xffffaa3e,0x0007af45, +0x0000519f,0x00030000,0x000f0007,0x003f001f, +0x00ff007f,0x03ff01ff,0x0fff07ff,0x3fff1fff, +0xffff7fff,0x00030000,0x00070005,0x000f0009, +0x003f001f,0x00ff007f,0x03ff01ff,0x0fff07ff, +0xffff1fff,0x00030000,0x00070005,0x000f0009, +0xffff001f,0x00030000,0xffff0005,0x04030504, +0x08070605,0x0c0b0a09,0x100f0e0d,0x03070504, +0x0605040a,0x0a090807,0x100d0c0b,0x03070503, +0x1005040a,0x10070502,0x03030100,0x03030303, +0x03030303,0x03030303,0x03010100,0x03030301, +0x03030303,0x03030303,0x03010100,0x03030301, +0x03010100,0x04020000,0x08070605,0x0c0b0a09, +0x100f0e0d,0x02010000,0x06050403,0x0a090807, +0x100d0c0b,0x02010000,0x10050403,0x10010000, +0x00030000,0x00090005,0x001f000f,0x007f003f, +0x01ff00ff,0x07ff03ff,0x1fff0fff,0x7fff3fff, +0x00030000,0x00090005,0x001f000f,0x007f003f, +0x0a070504,0x07060504,0x0b0a0908,0x0f0e0d0c, +0x0a070503,0x07060504,0x01010100,0x03030303, +0x03030303,0x03030303,0x01010100,0x03030303, +0x03010000,0x07060504,0x0b0a0908,0x0f0e0d0c, +0x03010000,0x07060504,0x00555555,0x002aaaab, +0x00249249,0x00124925,0x00111111,0x00088889, +0x00084210,0x00421084,0x00041041,0x00020821, +0x00020408,0x00081020,0x00010101,0x00008081, +0x00008040,0x00100804,0x00004010,0x00020080, +0x00002004,0x00004008,0x00001001,0x00000801, +0x00000800,0x00200100,0x00000400,0x00080020, +0x00000200,0x00020004,0x00200000,0x00600040, +0x00a00080,0x00e000c0,0x01200100,0x01600140, +0x01a00180,0x000001c0,0x00300020,0x00400038, +0x00600050,0x00800070,0x00c000a0,0x010000e0, +0x01800140,0x00200000,0x00300028,0x00400038, +0x00600050,0x00800070,0x00c000a0,0x010000e0, +0x00000140,0x00900000,0x00fc00d8,0x01680120, +0x01f801b0,0x02d00240,0x03f00360,0x05a00480, +0x000006c0,0x00680000,0x00b6009c,0x010500d0, +0x016d0139,0x020a01a1,0x02db0272,0x04140343, +0x000004e5,0x006c0000,0x00bd00a2,0x010e00d8, +0x017a0144,0x006301b0,0x013b00cf,0x00c601a7, +0x0000019e,0x00600000,0x00a80090,0x00f000c0, +0x01500120,0x01e00180,0x02a00240,0x03c00300, +0x00000480,0x10000000,0x10101010,0x20101010, +0x20202020,0x20202020,0x28202020,0x28282828, +0x00002828,0x10100000,0x10101010,0x10101010, +0x00000000,0x00000000,0x00000000,0x00000000, +0xcbcecdc4,0xcfcac9c8,0xc3c6c5cc,0xc7c2c1c0, +0x1b1e1d14,0x1f1a1918,0x1316151c,0x17121110, +0x2b2e2d24,0x2f2a2928,0x2326252c,0x27222120, +0x3b3e3d34,0x3f3a3938,0x3336353c,0x37323130, +0x0b0e0d04,0x0f0a0908,0x0306050c,0x07020100, +0xdbdeddd4,0xdfdad9d8,0xd3d6d5dc,0xd7d2d1d0, +0xebeeede4,0xefeae9e8,0xe3e6e5ec,0xe7e2e1e0, +0xfbfefdf4,0xfffaf9f8,0xf3f6f5fc,0xf7f2f1f0, +0x4b4e4d44,0x4f4a4948,0x4346454c,0x47424140, +0x9b9e9d94,0x9f9a9998,0x9396959c,0x97929190, +0xabaeada4,0xafaaa9a8,0xa3a6a5ac,0xa7a2a1a0, +0xbbbebdb4,0xbfbab9b8,0xb3b6b5bc,0xb7b2b1b0, +0x8b8e8d84,0x8f8a8988,0x8386858c,0x87828180, +0x5b5e5d54,0x5f5a5958,0x5356555c,0x57525150, +0x6b6e6d64,0x6f6a6968,0x6366656c,0x67626160, +0x7b7e7d74,0x7f7a7978,0x7376757c,0x77727170, +0x341424c4,0x3e1e2ece,0x3d1d2dcd,0x3b1b2bcb, +0xb494a444,0xbe9eae4e,0xbd9dad4d,0xbb9bab4b, +0xf4d4e404,0xfedeee0e,0xfddded0d,0xfbdbeb0b, +0x74546484,0x7e5e6e8e,0x7d5d6d8d,0x7b5b6b8b, +0x3c1c2ccc,0x361626c6,0x351525c5,0x331323c3, +0xbc9cac4c,0xb696a646,0xb595a545,0xb393a343, +0xfcdcec0c,0xf6d6e606,0xf5d5e505,0xf3d3e303, +0x7c5c6c8c,0x76566686,0x75556585,0x73536383, +0x381828c8,0x3a1a2aca,0x391929c9,0x3f1f2fcf, +0xb898a848,0xba9aaa4a,0xb999a949,0xbf9faf4f, +0xf8d8e808,0xfadaea0a,0xf9d9e909,0xffdfef0f, +0x78586888,0x7a5a6a8a,0x79596989,0x7f5f6f8f, +0x301020c0,0x321222c2,0x311121c1,0x371727c7, +0xb090a040,0xb292a242,0xb191a141,0xb797a747, +0xf0d0e000,0xf2d2e202,0xf1d1e101,0xf7d7e707, +0x70506080,0x72526282,0x71516181,0x77576787, +0x05040100,0x15141110,0x25242120,0x35343130, +0x85848180,0x95949190,0xa5a4a1a0,0xb5b4b1b0, +0xc0408000,0xe060a020,0xd0509010,0xf070b030, +0xc8488808,0xe868a828,0xd8589818,0xf878b838, +0xc4448404,0xe464a424,0xd4549414,0xf474b434, +0xcc4c8c0c,0xec6cac2c,0xdc5c9c1c,0xfc7cbc3c, +0xc2428202,0xe262a222,0xd2529212,0xf272b232, +0xca4a8a0a,0xea6aaa2a,0xda5a9a1a,0xfa7aba3a, +0xc6468606,0xe666a626,0xd6569616,0xf676b636, +0xce4e8e0e,0xee6eae2e,0xde5e9e1e,0xfe7ebe3e, +0xc1418101,0xe161a121,0xd1519111,0xf171b131, +0xc9498909,0xe969a929,0xd9599919,0xf979b939, +0xc5458505,0xe565a525,0xd5559515,0xf575b535, +0xcd4d8d0d,0xed6dad2d,0xdd5d9d1d,0xfd7dbd3d, +0xc3438303,0xe363a323,0xd3539313,0xf373b333, +0xcb4b8b0b,0xeb6bab2b,0xdb5b9b1b,0xfb7bbb3b, +0xc7478707,0xe767a727,0xd7579717,0xf777b737, +0xcf4f8f0f,0xef6faf2f,0xdf5f9f1f,0xff7fbf3f, +0x1045a3e2,0x000000f4,0x263b7333,0x766b2363, +0x2b367e3e,0x7b662e6e,0x06db93d3,0x964b0343, +0x0bd69ede,0x9b460e4e,0x825f1757,0x12cf87c7, +0x8f521a5a,0x1fc28aca,0x00d199d9,0x90410949, +0x01d098d8,0x91400848,0x24357d3d,0x74652d6d, +0x25347c3c,0x75642c6c,0x04d59ddd,0x94450d4d, +0x05d49cdc,0x95440c4c,0x80511959,0x10c189c9, +0x81501858,0x11c088c8,0x02df97d7,0x924f0747, +0x0fd29ada,0x9f420a4a,0x865b1353,0x16cb83c3, +0x8b561e5e,0x1bc68ece,0xa6bbf3b3,0xf6eba3e3, +0xabb6febe,0xfbe6aeee,0x223f7737,0x726f2767, +0x2f327a3a,0x7f622a6a,0xa0b1f9b9,0xf0e1a9e9, +0xa1b0f8b8,0xf1e0a8e8,0x84551d5d,0x14c58dcd, +0x85541c5c,0x15c48ccc,0xa4b5fdbd,0xf4e5aded, +0xa5b4fcbc,0xf5e4acec,0x20317939,0x70612969, +0x21307838,0x71602868,0xa2bff7b7,0xf2efa7e7, +0xafb2faba,0xffe2aaea,0x00000000,0x00000000, + +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/mpgi2s_240.h linux.20pre2-ac1/drivers/media/video/ls220/mpgi2s_240.h --- linux.20pre2/drivers/media/video/ls220/mpgi2s_240.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/mpgi2s_240.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1593 @@ +static u32 MPGI2S240Ucode1f1800[] = { +0x820f001f,0x802f001f,0xb500000d,0x00000000, +0x00ffb81e,0x00000000,0x00000000,0x00000000, +0x00ffb81e,0x00000000,0x00000000,0x00000000, +0xb5000b5b,0x00000000,0x00000000,0x00000000, +0x80070800,0x001f6047,0x8013001f,0x90208000, +0x003fb174,0x803effe8,0x803effec,0x9020fa00, +0x803effd0,0x803effdc,0x803effd8,0x9020fe00, +0x803effd4,0x805bff7c,0x802500d4,0x94020080, +0xb0000000,0xb4200023,0x8013ffcf,0x9800cfff, +0x80730030,0x98631000,0x94420007,0xb0020002, +0xb4200005,0x8013ffc7,0x9800c7ff,0x80730038, +0x98631000,0xb5000006,0xb0020001,0xb4200004, +0x8013ffcf,0x9800cfff,0x80730030,0x98631000, +0x1421b800,0x1821b803,0x802600d4,0x8033001f, +0x98210000,0x802600a2,0x8033001f,0x98210300, +0x802600a3,0x80270225,0x80530001,0x98420100, +0x1821b802,0x80530200,0x98420000,0x804600a6, +0xb500001d,0x805bff7c,0x8013ffcf,0x9800cfff, +0x80730030,0x98632000,0x94420007,0xb0020002, +0xb4200005,0x8013ffc7,0x9800c7ff,0x80730038, +0x98632800,0xb5000006,0xb0020001,0xb4200004, +0x8013ffcf,0x9800cfff,0x80730030,0x98632000, +0x1421b800,0x1821b803,0x802600d4,0x8033001f, +0x98210000,0x802600a2,0x8033001f,0x98210600, +0x802600a3,0x80270eff,0x802600a1,0x80270002, +0x803eff84,0x80070000,0x801effc0,0x801effc4, +0x801effc8,0x801effcc,0x801eff88,0x80770000, +0x8057ffff,0x80170080,0x80070000,0xb6003f02, +0xb6002001,0x001fa020,0x8007ffff,0x801eff84, +0x80070001,0x001f25dc,0x001f20b1,0x80070000, +0x001f6046,0x001fb17c,0x001fb17d,0x80070000, +0x801e78d0,0x98004000,0x001f62ea,0x80070100, +0x801efff0,0x81df0004,0x00000000,0x00000000, +0x801bfff0,0x00000000,0x940000ff,0xb0000000, +0xb4200057,0x003f42ea,0x94010010,0xb0000000, +0xb400fff7,0x003f05dc,0xb0010001,0xb4200034, +0x803bffe8,0x801bffec,0x00000000,0x3001b800, +0xb4600001,0x90214000,0x0421b800,0xb0010800, +0xb460000d,0x80050086,0x005f902e,0xb0020000, +0xb4200002,0x001fb02e,0xb5000006,0x0420b802, +0xb0010930,0xb4a0ffe2,0x80070000,0x001fb02e, +0x83e40146,0xb500ffde,0x83e40111,0x80070000, +0x001fb02e,0x001f42ea,0x9400000f,0xb0000000, +0xb4000010,0x9400fff0,0x001f62ea,0x003f9174, +0x9421ffff,0x90210004,0xb001c000,0xb4800002, +0x8421c000,0x90218000,0x8013001f,0x1821b800, +0x003fb174,0x003f917c,0x90210004,0x003fb17c, +0x83e4012e,0x8013001f,0x83e71b0c,0x1bffb800, +0x003f9179,0x1821b800,0x00ffb801,0xb5000008, +0x80270000,0x003f25dc,0x8013001f,0x83e71b30, +0x1bffb800,0x003f917a,0x1821b800,0x00ffb801, +0x80070000,0x001f20b1,0x001f42ea,0x9420000f, +0xb0010000,0xb4200003,0x98000800,0x001f62ea, +0xb500ffaf,0x9400fff0,0x001f62ea,0x80270000, +0x8057ffff,0x80770000,0x80171980,0xb6000602, +0xb6002001,0x001fa021,0xb500ffa5,0xb500ffa4, +0x803bffc0,0x805bffc4,0x807bffc8,0x809bffcc, +0x5828b801,0x5cb8b802,0x1821b805,0x5848b802, +0x5cb8b803,0x1842b805,0x5868b803,0x5cb8b804, +0x1863b805,0x5888b804,0x1884b800,0x803effc0, +0x805effc4,0x807effc8,0x809effcc,0x003f42ea, +0xb0000086,0xb4400079,0xb0000084,0xb4000049, +0xb0000085,0xb4000063,0xb0000086,0xb400006c, +0xb0000081,0xb4000005,0xb0000082,0xb4000003, +0xb0000080,0xb4000001,0xb5000069,0x8013007f, +0x9800ffff,0x001fb02d,0x80070000,0x001fb17c, +0x8013001f,0x9040fa00,0x805effd0,0x805effdc, +0x805effd8,0x9040fe00,0x805effd4,0x9040c000, +0x805effe4,0x90008000,0x801effe0,0x001fb174, +0x801effe8,0x801effec,0x80078000,0x801e78d4, +0x80070000,0x001fb17c,0x001fb17d,0x001fb02e, +0x83e400ce,0x8013001f,0x98000000,0x800600a2, +0x8013001f,0x98000600,0x800600a3,0x805bff7c, +0x80070eff,0x94420080,0xb0020080,0xb420000d, +0x8013001f,0x98000000,0x800600a2,0x8013001f, +0x98000300,0x800600a3,0x80070225,0x80530001, +0x98420100,0x1800b802,0x80530200,0x98420000, +0x804600a6,0x800600a1,0x80050080,0x98000022, +0x80060080,0x80072000,0x001fb179,0x80074360, +0x001fb17a,0x80070001,0x001f25dc,0x98214000, +0xb5000029,0x8047ffff,0x805eff84,0x805bff88, +0x00000000,0xb0020001,0xb4200002,0x80470000, +0x805eff88,0x805bff7c,0x80070eff,0x94420080, +0xb0020080,0xb4200007,0x80070225,0x80530001, +0x98420100,0x1800b802,0x80530200,0x98420000, +0x804600a6,0x800600a1,0x80070001,0x800600a0, +0x9421efff,0x98210010,0xb500000f,0x80070000, +0x001fb17c,0x80070001,0x001f25dc,0x83e4008b, +0x80050081,0x80330008,0x98210000,0x1800b801, +0x80060081,0x003f42ea,0x9421ffef,0xb5000002, +0x98211000,0x9421ffef,0x83e40080,0x003f62ea, +0x80070100,0x801efff0,0xb500ff15,0xb000008b, +0xb400001c,0xb0000087,0xb400ffe8,0xb0000088, +0xb4000023,0xb000008a,0xb4000024,0xb000008c, +0xb4000019,0xb000008e,0xb4000014,0xb000008d, +0xb400001d,0xb0000089,0xb400001f,0xb00000a0, +0xb4000021,0xb00000a1,0xb4000022,0xb00000a2, +0xb400002b,0xb00000a3,0xb4000027,0xb00000a4, +0xb4000029,0xb00000a5,0xb4000029,0xb00000a6, +0xb4000029,0x803efff8,0xb500ffdd,0x80070000, +0x001fb17e,0xb500ffda,0x803bffb0,0x00000000, +0x003fb02d,0xb500ffd6,0x98210020,0xb500ffd2, +0x9421ffdf,0xb500ffd0,0xb500ffd1,0x80270351, +0x803efff8,0xb500ffce,0x803bff80,0x00000000, +0x003f62ef,0xb500ffca,0x003f917b,0x803efff8, +0xb500ffc7,0x80270000,0x8047fef0,0x003eb802, +0x90420004,0x003eb802,0x90420004,0x003eb802, +0x90420004,0x003eb802,0x83640d78,0xb500ffbc, +0x83640d26,0xb500ffba,0x83640ce5,0xb500ffb8, +0x83440c4c,0xb500ffb6,0x83440c35,0xb500ffb4, +0x817bffe8,0x815b78d4,0x00000000,0x956bffff, +0x300bb80a,0xb4600001,0x916b4000,0x056bb80a, +0xb00b0080,0xb4a00026,0x80af001f,0x808f0000, +0x806f0000,0x81b300ff,0x8057ffff,0x5d67b80b, +0x5d42b80a,0xb62b001c,0xb00a3000,0xb4800001, +0x854a1000,0x80cf0400,0x015fb178,0x5942b80a, +0x01cfb80a,0x015f9178,0xb520ffff,0x80171000, +0xb600200a,0x01ff8000,0x5a18b80f,0x5a28b80f, +0x1631b80d,0x5e48b80f,0x9652ff00,0x5e78b80f, +0x1a73b810,0x1a73b811,0x1813a032,0x80cf0400, +0x015fb178,0x5942b80a,0x01afb80a,0x015f9178, +0xb520ffff,0x914a0020,0x5942b80a,0x815e78d4, +0x00000000,0x00000000,0x00ffb81f,0x80070000, +0x80470000,0x81171800,0xb6002003,0xb6003002, +0x001eb802,0x90420004,0xb6002003,0x011fa020, +0x011fa020,0x011fa020,0x00ffb81f,0x80070000, +0x80478000,0xb6002003,0xb6008002,0x001eb802, +0x90420004,0x00ffb81f,0x00000000,0x00000000, +0x015f42ea,0x944a4000,0xb0024000,0xb4200071, +0x954abfff,0x015f62ea,0x808f0000,0x80ef007c, +0x80171000,0x80971400,0x80270000,0xb6001003, +0xb6002002,0x001fa021,0x009fa021,0x80a76604, +0x80271400,0xb6001004,0x01efb801,0x01afb805, +0xb520ffff,0x90a50080,0x80a76e04,0x80271400, +0xb6001004,0x01efb801,0x01afb805,0xb520ffff, +0x90a50080,0x806f001f,0x80af001f,0x80276400, +0x5c22b801,0x806701e1,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x80275c00,0x5c22b801, +0x80670200,0xb600100a,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90210020,0x90630020, +0x808f0000,0x806f001f,0x80af001f,0x8027647c, +0x5c22b801,0x8067017e,0xb600020a,0x00cfb803, +0x003fb178,0x5822b801,0x01cfb801,0x003f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x90210020, +0x90630020,0x806f0010,0x80af0010,0x8027657c, +0x5c22b801,0x806701be,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x802765c0,0x5c22b801, +0x806701cf,0x00cfb803,0x003fb178,0x5822b801, +0x01cfb801,0x003f9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x80276000,0x005fb801,0x8033001f, +0x98218000,0x803effe0,0x90214000,0x803effe4, +0x8193001f,0x998c8000,0x019fb174,0x83270000, +0x003fb819,0x003f9174,0x5823b801,0x83338000, +0x1b39b801,0x003fb819,0x00000000,0x00000000, +0x81550000,0x0187b860,0x858c0040,0x81b380fc, +0x99ad0000,0x300cb80d,0xb4600003,0x81b30002, +0x99ad0000,0x118cb80d,0x003fb80c,0x00000000, +0x00000000,0x81550000,0x8257ffff,0x82d7ffff, +0x8357ffff,0x81672000,0x83440189,0xb00a0001, +0xb4000141,0x0187b860,0x858c0010,0x5988b80c, +0x5d8bb80c,0x958cffff,0xb00cc000,0xb4800002, +0x858cc000,0x918c8000,0x81b3001f,0x198cb80d, +0x801bffec,0x00000000,0x819effec,0x819e78d8, +0x019fb174,0x05acb800,0x300cb800,0xb4600001, +0x91ad4000,0x001f917c,0x1000b80d,0x001fb17c, +0x83440194,0xb00a0000,0xb4200127,0x015f0081, +0xb00a0002,0xb4200124,0x037f0082,0xb01b0000, +0xb400001e,0x0367b860,0x5b68b81b,0x5f68b81b, +0x017f4047,0x916b0010,0x5963b80b,0x83440160, +0x801bff84,0xb00a0001,0xb400000b,0xb00b00c0, +0xb460fffa,0x803f0000,0x80138000,0x1b7bb800, +0x003fb81b,0x00000000,0x00000000,0x80150000, +0x801bff84,0xb5000009,0x803f0000,0x80138000, +0x1b7bb800,0x003fb81b,0x00000000,0x00000000, +0x80150000,0x801bff84,0xb5000103,0x801bff84, +0x003f0084,0x3000b801,0x803eff84,0xb4000073, +0x801bff7c,0x00000000,0x94800080,0xb0040080, +0xb4200036,0x94800007,0x80730200,0xb0010002, +0xb420000e,0x80270265,0xb0040001,0xb4200003, +0x80130030,0x98000000,0xb5000006,0x80130030, +0x98000000,0xb0040000,0xb4000002,0x80130038, +0x98000000,0x98630060,0xb500001f,0xb0010000, +0xb420000e,0x80270225,0xb0040001,0xb4200003, +0x80130030,0x98001000,0xb5000006,0x80130030, +0x98001000,0xb0040000,0xb4000002,0x80130038, +0x98001000,0x98630000,0xb500000f,0xb0010001, +0xb420004a,0x80270225,0xb0040001,0xb4200003, +0x80130030,0x98002000,0xb5000006,0x80130030, +0x98000000,0xb0040000,0xb4000002,0x80130038, +0x98000000,0x98630040,0x806600a6,0x80530001, +0x98420100,0x1821b802,0xb500002d,0x94800007, +0xb0010002,0xb420000d,0x80270eff,0xb0040001, +0xb4200003,0x80130030,0x98002000,0xb5000006, +0x80130030,0x98000000,0xb0040000,0xb4000002, +0x80130038,0x98000000,0xb500001d,0xb0010000, +0xb420000d,0x80270eff,0xb0040001,0xb4200003, +0x80130030,0x98002000,0xb5000006,0x80130030, +0x98002000,0xb0040000,0xb4000002,0x80130038, +0x98002800,0xb500000e,0xb0010001,0xb4200017, +0x80270eff,0xb0040001,0xb4200003,0x80130030, +0x98002000,0xb5000006,0x80130030,0x98002000, +0xb0040000,0xb4000002,0x80130038,0x98002800, +0x806500d4,0x8053ffcf,0x9842cfff,0xb0040002, +0xb4200002,0x8053ffc7,0x9842c7ff,0x802600a1, +0x1463b802,0x1863b800,0x806600d4,0x807bff7c, +0x00000000,0x94630080,0xb0030080,0xb420000b, +0x807bff88,0x00000000,0xb0030001,0xb4000007, +0x802500a1,0x80670001,0x807eff88,0x80530001, +0x98420100,0x1821b802,0x802600a1,0x81070000, +0x011f62e2,0x011f62e3,0x011f0082,0xb0080000, +0xb4200004,0x81150010,0x00000000,0x00000000, +0x011f62de,0x011f0081,0xb0080001,0xb4200026, +0x81070020,0x011f25c1,0x81070180,0x011f62e1, +0x8344022a,0x8344024e,0x011f0082,0xb0080000, +0xb4200004,0x834401b1,0x8344019e,0xb00a0000, +0xb4200061,0x80c70000,0x00df25cb,0x83440261, +0x834405e7,0x02ff05b9,0x82a70000,0x82870000, +0x834403cf,0x92940001,0x3014b817,0xb480fffc, +0x8344067f,0x80270000,0x003f25dc,0x83440760, +0x003f05dc,0xb0010001,0xb4000003,0x802725d4, +0x003fb17a,0x00ffb81f,0x80d3001f,0x834725ac, +0x1b5ab806,0xb500002d,0xb0080002,0x81470004, +0xb4200045,0x81070008,0x011f25c1,0x81070480, +0x011f62e1,0x83440276,0x834402b0,0x011f0082, +0xb0080000,0xb4200004,0x8344019a,0x83440175, +0xb00a0000,0xb4200038,0x80c70000,0x00df25cb, +0x83440334,0x02df05cb,0x5ec2b816,0x834405ff, +0x02ff05b9,0x82a70000,0x82870000,0x834403a4, +0x92940001,0x3014b817,0xb480fffc,0x92b50001, +0xb0150003,0xb480fff8,0x83440651,0x80270000, +0x003f25dc,0x83440732,0x003f05dc,0xb0010001, +0xb4000003,0x8027268c,0x003fb17a,0x00ffb81f, +0x80d3001f,0x83472650,0x1b5ab806,0x80db78d8, +0x80fbffec,0x00000000,0x3006b807,0xb4200007, +0x00df05cb,0x90c60001,0x00df25cb,0xb006000c, +0xb4000002,0x035fb179,0x00ffb81f,0x80c70000, +0x00df25cb,0x80fb78dc,0x00000000,0x90e70001, +0xb00701b9,0xb4a00001,0x80e70001,0x80fe78dc, +0xb500feb0,0x802500a5,0x8153001f,0x3001b80a, +0xb420fffc,0x00ffb81f,0x001f42ea,0x1800b80a, +0x001f62ea,0x017f4047,0x5963b80b,0x0187b860, +0x118cb80b,0x81b380fe,0x99ad0000,0x300cb80d, +0xb4800003,0x81b30002,0x99ad0000,0x058cb80d, +0x003fb80c,0x00000000,0x00000000,0x81550000, +0x0187b860,0x5988b80c,0x5d8bb80c,0x958cffff, +0xb00cc000,0xb4800002,0x858cc000,0x918c8000, +0x81b3001f,0x198cb80d,0x801bffec,0x00000000, +0x819effec,0x019fb174,0x05acb800,0x300cb800, +0xb4600001,0x91ad4000,0x001f917c,0x1000b80d, +0x001fb17c,0x80171000,0x80971400,0x80270000, +0xb6001003,0xb6002002,0x001fa021,0x009fa021, +0x80171800,0xb6000602,0xb6002001,0x001fa021, +0x806f001f,0x80af001f,0x80a76604,0x80271400, +0xb6001004,0x01efb801,0x01afb805,0xb520ffff, +0x90a50080,0x80a76e04,0x80271400,0xb6001004, +0x01efb801,0x01afb805,0xb520ffff,0x90a50080, +0x81472000,0x015fb179,0x00ffb81f,0x00000000, +0x811be024,0x0107b860,0x95080007,0xb0080000, +0xb4000004,0xa5080008,0x00000000,0x0155b808, +0x00000000,0x8115000c,0x856b000c,0xb0080fff, +0xb400000b,0x81550004,0x856b0004,0x5904b808, +0x1908b80a,0x95080fff,0xb0080fff,0xb4000004, +0x81470001,0xb00b0020,0xb440fff6,0xb500000c, +0x81d50004,0x856b0004,0x00000000,0xb00e000f, +0xb400fffb,0x940b0007,0xb0000000,0xb420ffed, +0x001f42ea,0x9400fffe,0x81470000,0x001f62ea, +0x00ffb81a,0x950e0008,0x5d03b808,0x00000000, +0xb0080000,0xb40000c9,0x011f2080,0x950e0006, +0x5d01b808,0x81270004,0x0529b808,0x950e0001, +0x013f2081,0x011f2082,0x81150004,0x00000000, +0xb0080000,0xb40000bd,0xb008000f,0xb40000bb, +0x011f2083,0x81150002,0x00000000,0x81670004, +0xb0080002,0xb46000b5,0x011f2084,0x013f0081, +0xb0090002,0xb4200011,0x013f0083,0xb0080000, +0xb4200002,0x81077844,0xb5000005,0xb0080001, +0xb4200002,0x81077884,0xb5000001,0x81077824, +0x013f0083,0x5921b809,0x1129b808,0x0119b809, +0x00000000,0x00000000,0x011f6047,0x81150001, +0x00000000,0x011f2085,0x81150001,0x00000000, +0x011f2086,0x81350002,0x00000000,0x013f2087, +0x81150002,0x00000000,0x011f2088,0x81150001, +0x00000000,0x011f2089,0x81150001,0x00000000, +0x011f208a,0x81150002,0x00000000,0x011f208b, +0x81070001,0xb0090003,0xb4000001,0x81070002, +0x011f25b9,0x81070020,0x013f0081,0xb0090002, +0xb4200065,0x85290001,0xad29000f,0x00000000, +0x011f0083,0x1108b809,0x5901b808,0x910877c8, +0x0139b808,0x011f05b9,0x85080001,0x6928b809, +0x011f0084,0xb0090038,0xb4800007,0xb0080001, +0xb4000002,0xb0090050,0xb4400003,0x81270000, +0x8107001b,0xb5000010,0xb0080001,0xb4000005, +0xb0090060,0xb4800003,0x81270001,0x8107001e, +0xb5000009,0xb0080002,0xb4000005,0xb0090030, +0xb4400003,0x81270002,0x81070008,0xb5000002, +0x81270003,0x8107000c,0x011f25bb,0x013f25c0, +0xb0090002,0xb460001b,0x80477604,0x5c42b802, +0x814fffc0,0x80cf0037,0x005fb178,0x5842b802, +0x01cfb802,0x005f9178,0xb520ffff,0x90420020, +0x814fb580,0x80cf0057,0x005fb178,0x5842b802, +0x01cfb802,0x005f9178,0xb520ffff,0x804778a4, +0x5c42b802,0x814f39c0,0x80cf002f,0x005fb178, +0x5842b802,0x01cfb802,0x005f9178,0xb520ffff, +0xb5000021,0x804776e0,0x5c42b802,0x814fef40, +0x80cf0037,0x005fb178,0x5842b802,0x01cfb802, +0x005f9178,0xb520ffff,0x8297013c,0x8317018c, +0xb6000602,0x005f8034,0x031fa022,0x82970124, +0x83170160,0xb6000602,0x005f8034,0x031fa022, +0x8297010c,0x83170134,0xb6000602,0x005f8034, +0x031fa022,0x804778c4,0x5c42b802,0x814f1080, +0x80cf002f,0x005fb178,0x5842b802,0x01cfb802, +0x005f9178,0xb520ffff,0x013f0081,0xb0090001, +0xb420000e,0x808f0000,0x806f001b,0x80af001b, +0x80277758,0x5c22b801,0x80670037,0x00cfb803, +0x003fb178,0x5822b801,0x01cfb801,0x003f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x011f25bb, +0x011f0087,0xb0080001,0xb4000002,0x011f05bb, +0xb5000003,0x011f0088,0x91080001,0x5902b808, +0x011f25ba,0x81470000,0x00ffb81a,0x81470008, +0x00ffb81a,0x81270000,0x81470000,0x300842de, +0xb400000b,0x013f42e2,0x91290001,0x013f62e2, +0x013f42e3,0x91290001,0x013f62e3,0x83640006, +0x00000000,0x00000000,0x013f42e2,0x81470002, +0x013f62e2,0x00ffb81a,0x00ffb81b,0x83640041, +0x80c70004,0x80270000,0xb600200d,0x00ff05b9, +0x5c42b801,0x300205ba,0xb4800001,0x80e70001, +0x80470000,0xb6270005,0x1062b801,0x914301b8, +0x00fff00a,0x83840050,0x90420080,0x90210004, +0x00ffb81a,0x8364002f,0x017f05bb,0x800700bc, +0x80270000,0xb00b0000,0xb4000015,0xb62b0014, +0x00ff05b9,0x5c42b801,0x300205ba,0xb4800001, +0x80e70001,0x80470000,0xb0070000,0xb400000b, +0xb627000a,0x1062b801,0x914301b8,0x00fff00a, +0x5c62b801,0x1063b800,0x00bff003,0x90650134, +0x00dff003,0x83840034,0x90420080,0x90210004, +0x019f05b9,0x80c70002,0x80270000,0xb00b0000, +0xb400000f,0xb62b000e,0x80470000,0xb00c0000, +0xb400000a,0xb62c0009,0x1062b801,0x914301b8, +0x00fff00a,0xb0070000,0xb4000003,0x906302b8, +0x00fff003,0x83840020,0x90420080,0x90210004, +0x00ffb81a,0x8107ffff,0x80c70004,0x00ff0083, +0x83840019,0x80c70002,0x00ff0084,0x83840016, +0x80c70001,0x00ff0085,0x83840013,0x80c70001, +0x00ff0086,0x83840010,0x80c70002,0x00ff0087, +0x8384000d,0x80c70002,0x00ff0088,0x8384000a, +0x80c70001,0x00ff0089,0x83840007,0x80c70001, +0x00ff008a,0x83840004,0x80c70002,0x00ff008b, +0x83840001,0x00ffb81b,0x80a70001,0x64a6b805, +0x5ca1b805,0xb0050000,0xb400000e,0x95288000, +0xb0090000,0xb4000001,0x81270001,0x5901b808, +0x1547b805,0xb00a0000,0xb4000001,0x81470001, +0x2129b80a,0xb0090000,0xb4000001,0xa1088005, +0xb500ffef,0x9508ffff,0x00ffb81c,0x015f05ba, +0x013f05b9,0x800700bc,0xb0090000,0xb400000f, +0xb00a0000,0xb400000d,0x80270000,0xb62a000b, +0x80470000,0xb6290008,0x80950004,0x5865b802, +0x1063b801,0x5862b803,0x906301b8,0x0217b803, +0x90420001,0x021fa004,0x90210001,0xa54a0020, +0xb4c0000e,0xb0090000,0xb400000c,0xb62a000b, +0x80950004,0x80470000,0xb6290007,0x5865b802, +0x1063b801,0x5862b803,0x906301b8,0x0217b803, +0x90420001,0x021fa004,0x90210001,0x00ffb81a, +0x013f05b9,0xb0090000,0xb4000019,0x80270000, +0xb6002017,0x80470000,0xb6290014,0x5865b802, +0x1063b801,0x5862b803,0x914301b8,0x009ff00a, +0xad420060,0x00000000,0x114ab801,0x5942b80a, +0x914a1c80,0x0217b80a,0xb0040000,0xb4000004, +0x80950006,0x00000000,0x021fa004,0xb5000002, +0x8087003f,0x021fa004,0x90420001,0x90210001, +0x00ffb81a,0x8257ffff,0x82d7ffff,0x011f05ba, +0x013f05b9,0x80270000,0xb0090000,0xb400002b, +0xb6280015,0x80470000,0xb6290012,0x5865b802, +0x1063b801,0x5862b803,0x914301b8,0xaca20060, +0x009ff00a,0x10a5b801,0x58a2b805,0x90a502b8, +0x0217b805,0x80670000,0xb0040000,0xb4000003, +0x90840001,0x0075b804,0x00000000,0x021fa003, +0x90420001,0x90210001,0xa5480020,0xb4000013, +0x5822b801,0xb62a0011,0x914101b8,0x90a102b8, +0x0217b805,0x009ff00a,0xb0040000,0x80670000, +0xb4000002,0x90840001,0x0075b804,0xb6290006, +0x021fa203,0x009f8210,0x009f8210,0x009f8210, +0x009f8210,0x009f8210,0x90210004,0x00ffb81a, +0x015f05ba,0x013f05b9,0x800700bc,0xb0090000, +0xb4000013,0xb00a0000,0xb4000011,0x80270000, +0xb62a000f,0x80470000,0xb629000c,0x1080b801, +0x007ff004,0x90830134,0x007ff004,0x0095b803, +0x5865b802,0x1063b801,0x5862b803,0x906301b8, +0x0217b803,0x90420001,0x021fa004,0x90210001, +0x011f05bb,0x254ab808,0xb4c0000d,0xb62a000c, +0x1080b801,0x007ff004,0x90830134,0x007ff004, +0x0095b803,0x5862b801,0x906301b8,0x0217b803, +0x90210001,0x021fa204,0x007f8210,0x021fa004, +0xa5480020,0xb4c0000e,0xb0090000,0xb400000c, +0x80870000,0xb62a000a,0x80470000,0xb6290007, +0x5865b802,0x1063b801,0x5862b803,0x906301b8, +0x0217b803,0x90420001,0x021fa004,0x90210001, +0x00000000,0x00000000,0x00ffb81a,0x011f05bb, +0x013f05b9,0xb0080000,0xb4000015,0xb0090000, +0xb4000013,0x00000000,0x80270000,0xb6280010, +0x80470000,0xb629000d,0x5865b802,0x1063b801, +0x5862b803,0x914301b8,0x009ff00a,0xb0040000, +0xb4000005,0x80950002,0x906302b8,0x0217b803, +0x00000000,0x021fa004,0x90420001,0x90210001, +0xa5480020,0xb00a0000,0xb4000010,0xb0090000, +0xb400000e,0x00000000,0x80870000,0xb62a000b, +0x80470000,0xb6290008,0x5865b802,0x1063b801, +0x5862b803,0x906302b8,0x0217b803,0x00000000, +0x021fa004,0x90420001,0x90210001,0xb0080000, +0xb400004c,0xb0090000,0xb400004a,0x00000000, +0x80270000,0xb6280047,0x80470000,0xb6290044, +0x5865b802,0x1063b801,0x5862b803,0x914301b8, +0x009ff00a,0xad420060,0x00000000,0x00000000, +0x00000000,0x114ab801,0x5942b80a,0x914a1c80, +0x0217b80a,0xb0040000,0xb400002e,0x906302b8, +0x009ff003,0xb0040000,0xb420000a,0x80950006, +0x00000000,0x021fa204,0x80950006,0x015f8210, +0x021fa204,0x80950006,0x015f8210,0x021fa004, +0xb5000026,0xb0040001,0xb4200009,0x80950006, +0x00000000,0x021fa204,0x015f8210,0x021fa204, +0x80950006,0x015f8210,0x021fa004,0xb500001b, +0xb0040003,0xb4200009,0x80950006,0x00000000, +0x021fa204,0x80950006,0x015f8210,0x021fa204, +0x015f8210,0x021fa004,0xb5000010,0xb0040002, +0xb420000e,0x80950006,0x00000000,0x021fa204, +0x015f8210,0x021fa204,0x015f8210,0x021fa004, +0xb5000006,0x8087003f,0x021fa204,0x015f8210, +0x021fa204,0x015f8210,0x021fa004,0x90420001, +0x90210001,0xa5480020,0xb4c00011,0xb0090000, +0xb400000f,0x8087003f,0x5862b801,0x90631afc, +0xb62a000b,0x90630004,0x0047b803,0xb6290008, +0x90420180,0x0217b802,0x00000000,0x021fa204, +0x003f8210,0x021fa204,0x003f8210,0x021fa004, +0x00ffb81a,0x8257ffff,0x82d7ffff,0x011f05bb, +0x013f05b9,0x80270000,0x00e7b809,0x300105ba, +0xb4800001,0x80e70001,0x800700bc,0x80470000, +0xb0070000,0xb400004c,0xb627004b,0x5865b802, +0x1063b801,0x5862b803,0x914301b8,0xaca20060, +0x009ff00a,0x10a5b801,0x58a2b805,0x90a502b8, +0x0217b805,0xb0040000,0xb400002b,0x1060b801, +0x00bff003,0x10a5b804,0x90650160,0x00dff003, +0xb0060003,0xb4200007,0x90650134,0x00dff003, +0xb6000303,0x0075b806,0x021fa203,0x007f8210, +0xb5000021,0x5861b805,0x906300dc,0x009fd803, +0x90650134,0x00dff003,0xaca20060,0x00000000, +0x00000000,0x00000000,0x0075b806,0x10a5b801, +0x58a2b805,0x90a502b8,0x0217b805,0x588fb804, +0xb600030c,0xb6001007,0x04a3b804,0xb4600002, +0x58a1b803,0xb5000002,0x58a1b805,0x90a50001, +0x0067b805,0x9465ffff,0x5d50b805,0x021fa20a, +0x015f8210,0xb5000004,0x81470000,0xb6000302, +0x021fa20a,0x009f8210,0x009f05b9,0xb0040002, +0xb420000c,0x300105ba,0xb480000a,0x58a2b801, +0x90a502b8,0x0217b805,0x90a50180,0x0297b805, +0xb6000304,0x00bf8210,0x009f8210,0x029fa205, +0x009f8214,0x90420001,0x90210001,0x3001b808, +0xb480ffa9,0xa5480020,0xb00a0000,0xb4000015, +0xb0090000,0xb4000013,0x58a2b801,0x90a502b8, +0xb62a0010,0x80470000,0xb629000d,0xaca20060, +0x00000000,0x00000000,0x00000000,0x80670000, +0x10a5b801,0x58a2b805,0x90a502b8,0x0217b805, +0xb6000302,0x021fa203,0x00bf8210,0x90420001, +0x90210001,0x00ffb81a,0x00000000,0x00000000, +0x80770000,0x8057ffff,0x80f70000,0x80d7ffff, +0x81770000,0x8157ffff,0x81f70000,0x81d7ffff, +0xac140060,0xac350020,0x00000000,0x00000000, +0x12c0b801,0x5ac2b816,0x92d61980,0x83a400a5, +0xad940400,0x009f9173,0x013f05ca,0x914c6604, +0x114ab804,0x001f97e0,0x001eb80a,0xb0090000, +0xb4000003,0x80a76e44,0x80c76644,0xb5000002, +0x80a76644,0x80c76e44,0x808f000f,0x806f0000, +0x80af000e,0x80cf07e1,0x11e5b80c,0x11efb804, +0x5de2b80f,0x01ffb178,0x59e2b80f,0x01afb80f, +0x01ff9178,0x0047b86f,0xb0020001,0xb4c0fffd, +0x80cf07f0,0x1206b80c,0x1210b804,0x5e02b810, +0x021fb178,0x5a02b810,0x01afb810,0x021f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x916c6e04, +0x116bb804,0x001f97ff,0x001eb80b,0x808f0000, +0x806f001f,0x80af001f,0x90ac6604,0x5ca2b805, +0x80270400,0xb600080a,0x00cfb801,0x00bfb178, +0x58a2b805,0x01cfb805,0x00bf9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90210020,0x90a50020, +0x90ac6e04,0x5ca2b805,0x80270500,0xb600080a, +0x00cfb801,0x00bfb178,0x58a2b805,0x01cfb805, +0x00bf9178,0x0047b86f,0xb0020001,0xb4c0fffd, +0x90210020,0x90a50020,0x81530020,0xac140060, +0xac350020,0x80170800,0x80d7003c,0x12c0b801, +0x5ac2b816,0x92d602b8,0x0117b816,0x90241000, +0x0097b801,0x80470000,0x4002b803,0xb6000804, +0x005f8020,0x480287e4,0x005f8020,0x500287e4, +0x00000000,0x00000000,0x00000000,0x1021b80a, +0x5c36b801,0x5801b800,0x18c0b801,0xb0090000, +0xb4000002,0x90641440,0xb5000001,0x90641040, +0xb6000f0d,0x0097b803,0x80470000,0x4002b803, +0xb6001002,0x005f8020,0x480287e4,0x0108a026, +0x90630040,0x00000000,0x1021b80a,0x5c36b801, +0x5801b800,0x18c0b801,0x90641400,0x0097b803, +0x80470000,0x4002b803,0x005f8020,0x005f87e4, +0xb6000802,0x005f8040,0x480287c4,0x005f87e0, +0x0108a026,0x00000000,0x1021b80a,0x5c36b801, +0x5801b800,0x18c0b801,0xb0090000,0xb4000002, +0x906417c0,0xb5000001,0x906413c0,0xb6000f0f, +0x0097b803,0x80470000,0x4002b803,0xb6000804, +0x005f8020,0x500287e4,0x005f8020,0x480287e4, +0x0108a026,0x84630040,0x00000000,0x1021b80a, +0x5c36b801,0x5801b800,0x18c0b801,0xb0140000, +0xb4200005,0x90840004,0x9484003f,0x009fb173, +0xa1290001,0x013f25ca,0x80d7ffff,0x0108a026, +0x00ffb81a,0x81330004,0x8093007f,0x9884ffff, +0x80b3ff80,0x0017b816,0x90360040,0x0097b801, +0x81530010,0xb6001004,0x400a8000,0x404a8004, +0x0008a020,0x0088a022,0x0017b816,0x9036007c, +0x0097b801,0x81171000,0xb6001004,0x40048020, +0x480487e4,0x00000000,0x0108a020,0x81470000, +0x81670001,0x81870008,0x81a70040,0x81c707c4, +0x81e70040,0xb6000432,0xb00a0001,0xb4e00004, +0x80c71000,0x80e71000,0x81171040,0xb5000003, +0x80c71040,0x80e71040,0x81171000,0x844d0004, +0x10e7b802,0xb62b001f,0x0017b806,0x0097b807, +0xb62c0004,0x40048020,0x480487e4,0x00000000, +0x0108a020,0x0017b806,0x0097b807,0x0197b80e, +0x00000000,0x001f8020,0x042087e4,0xb62c000f, +0x4041800c,0x001f8020,0x0048b802,0x5e38802c, +0x2e11b801,0x042087e4,0x1042b810,0x0462b804, +0xb4a00002,0x0047b804,0xb5000003,0x0462b805, +0xb4600001,0x0047b805,0x011fa022,0x10c6b80f, +0x10e7b80f,0x5961b80b,0x5d81b80c,0x5da1b80d, +0x5de1b80f,0x914a0001,0x954a0001,0x11ceb80f, +0x80171018,0x81171fcc,0x80470000,0x41448020, +0x494487c0,0x00000000,0x0188b80a,0x494487e0, +0x00000000,0x0148b80a,0x0502a10a,0x4145b80c, +0x494580e0,0x00000000,0x0108a5ea,0x41448080, +0x494487c0,0x00000000,0x0108a78a,0x49448020, +0x00000000,0x0108a2ea,0x41448020,0x49448720, +0x00000000,0x0188b80a,0x4145b80c,0x49458080, +0x494587a0,0x00000000,0x0108a68a,0x4145b80c, +0x49458080,0x494587a0,0x00000000,0x0108a08a, +0x4145b80c,0x49458020,0x49458040,0x00000000, +0x0188b80a,0x494587e0,0x00000000,0x0108a08a, +0x4144b80c,0x494587a0,0x00000000,0x0108a52a, +0x41448080,0x49448040,0x494486c0,0x00000000, +0x0108a04a,0x41448040,0x49448720,0x00000000, +0x0108a36a,0x04028020,0x011fa420,0x001f8040, +0x011fa100,0x001f8080,0x011fa080,0x001f8100, +0x011fa040,0x001f8660,0x011fa120,0x41458020, +0x49458000,0x00000000,0x0108a00a,0x0017b816, +0x9036007c,0x0097b801,0x81171000,0x81970784, +0x00000000,0x001f8020,0x042087e4,0xb600100f, +0x4041800c,0x001f8020,0x0048b802,0x5e38802c, +0x2e11b801,0x042087e4,0x1042b810,0x0462b804, +0xb4a00002,0x0047b804,0xb5000003,0x0462b805, +0xb4600001,0x0047b805,0x011fa022,0x81470000, +0x81670001,0x81870008,0x81a70040,0x81c707c4, +0x81e70040,0xb6000432,0xb00a0001,0xb4e00004, +0x80c71000,0x80e71000,0x81171040,0xb5000003, +0x80c71040,0x80e71040,0x81171000,0x844d0004, +0x10e7b802,0xb62b001f,0x0017b806,0x0097b807, +0xb62c0004,0x40048020,0x480487e4,0x00000000, +0x0108a020,0x0017b806,0x0097b807,0x0197b80e, +0x00000000,0x001f8020,0x042087e4,0xb62c000f, +0x4041800c,0x001f8020,0x0048b802,0x5e38802c, +0x2e11b801,0x042087e4,0x1042b810,0x0462b804, +0xb4a00002,0x0047b804,0xb5000003,0x0462b805, +0xb4600001,0x0047b805,0x011fa022,0x10c6b80f, +0x10e7b80f,0x5961b80b,0x5d81b80c,0x5da1b80d, +0x5de1b80f,0x914a0001,0x954a0001,0x11ceb80f, +0x80171034,0x81171f84,0x80470000,0x41448040, +0x49448640,0x00000000,0x0188b80a,0x49448100, +0x49448780,0x00000000,0x0108a08a,0x4144b80c, +0x49448040,0x49448080,0x494487c0,0x00000000, +0x0108a16a,0x4145b80c,0x49458700,0x00000000, +0x0188b80a,0x494581a0,0x494586e0,0x00000000, +0x0108a66a,0x4145b80c,0x49448040,0x494487e0, +0x00000000,0x0188b80a,0x011fa1ec,0x4145b80c, +0x49458100,0x49458780,0x00000000,0x0108a08a, +0x41458720,0x49458100,0x494586e0,0x49458160, +0x49458020,0x49458020,0x49458760,0x00000000, +0x0108a08a,0x414587a0,0x49458080,0x49458760, +0x494580c0,0x49458700,0x49458140,0x49458020, +0x49458760,0x00000000,0x0108a74a,0x414587a0, +0x49458080,0x49458760,0x494580e0,0x49458700, +0x49458120,0x49458020,0x49458760,0x00000000, +0x0108a08a,0x41458720,0x49458100,0x494586e0, +0x49458140,0x49458040,0x49458020,0x49458720, +0x00000000,0x0108a0ca,0x41458080,0x49458040, +0x49458020,0x49458620,0x00000000,0x0188b80a, +0x49458080,0x00000000,0x0108a7ca,0x4144b80c, +0x49458040,0x49458020,0x49458080,0x00000000, +0x0108a5ea,0x41448080,0x49448700,0x00000000, +0x0188b80a,0x49448780,0x00000000,0x0108a7ca, +0x4144b80c,0x49448140,0x00000000,0x0108a7ca, +0x49448040,0x00000000,0x0108a0ca,0x41448700, +0x00000000,0x0188b80a,0x49448000,0x00000000, +0x0108a04a,0x011fa00c,0x80171f80,0xb6002006, +0x40048000,0x48048000,0x48048000,0x48048000, +0x00000000,0x0008a020,0x00ffb81d,0x00000000, +0x80770000,0x8057ffff,0x015f05b9,0x017f05bb, +0x8293ffff,0x9a94ffff,0x81a70000,0xb62a003a, +0xaded0180,0xae0d0180,0xadcd0080,0x902f1980, +0x0017b801,0xb6002033,0x904e01b8,0x00000000, +0x013ff002,0xb0090000,0xb400001f,0x904f02b8, +0x80c70000,0x011fd802,0x6829b808,0x94210001, +0xb0010001,0xb4e00001,0x00c7b814,0x6429b806, +0x80470001,0x6449b802,0x84420001,0x1442b808, +0x84690001,0x5863b803,0x906300dc,0x1042b801, +0x003f9803,0x90420001,0x4082b801,0x90630004, +0x003f9803,0x00000000,0x5897b804,0x1804b805, +0x4082b801,0x00000000,0x00000000,0x00000000, +0x10a4b800,0xb5000001,0x80a70000,0x90501c80, +0x00000000,0x007ff002,0x5842b803,0x904205f8, +0x0097b802,0x00000000,0x40058004,0x48058004, +0x00000000,0x0008a020,0x91ce0004,0x91ef0004, +0x92100004,0x91ad0001,0x00ffb81a,0x80770000, +0x8057ffff,0x80d7ffff,0x015f05b9,0x017f05bb, +0x8293ff80,0x9a940000,0x82a70020,0x81a70000, +0x81e702b8,0x80171980,0xb62a004f,0xb600034d, +0xac0d0080,0xac4d0180,0xac960080,0x822700bc, +0x91c001b8,0x00000000,0x1042b804,0x92021c80, +0xb62b003a,0x013ff00e,0x00fff011,0xb0090000, +0xb4000027,0x10e7b809,0x5821b807,0x902100dc, +0x00000000,0x001fd801,0x82470000,0x80270001, +0x6452b801,0x3002b800,0xb4600002,0x92520001, +0xb500fffb,0x86520001,0x80c70000,0x011fd80f, +0x6832b808,0xb0010001,0xb4e00001,0x00c7b814, +0x84520017,0x0056b802,0x80270001,0x6432b801, +0x84210001,0x1408b801,0x6402b800,0x10c6b800, +0x9027018c,0x00000000,0x001ff001,0x5802b800, +0x9020073c,0x904006f8,0x007f9801,0x0097b802, +0x10c6b803,0x40868004,0x48868004,0xb5000003, +0x80c70000,0x40868004,0x00000000,0x0088b804, +0x003ff010,0x5822b801,0x902105f8,0x0097b801, +0x91ce0004,0x91ef0004,0x40448004,0x48448004, +0x92100004,0x0008a022,0x92310001,0x0435b80b, +0xb4000007,0x80870000,0xb6210005,0x001fa024, +0x91ce0004,0x91ef0004,0x92100004,0x92310001, +0x00000000,0x91ad0001,0x00ffb81a,0x00000000, +0x007f05b9,0x001f0081,0xb0000001,0xb4400029, +0x001f05d8,0xac400080,0x801702b8,0x80970438, +0x90421800,0x0117b802,0x8087ffff,0x80b3ffff, +0x80d3007f,0x98c6ff00,0x80f3ff80,0x81070080, +0xb6002018,0x10088020,0x0056b800,0x0442b806, +0xb4a00004,0xb0000000,0x0007b806,0xb4400001, +0x0007b807,0x0027b800,0x5c08b800,0x1400b804, +0xb0030001,0xb4000008,0x10288024,0x0056b801, +0x0442b806,0xb4a00004,0xb0010000,0x0027b806, +0xb4400001,0x0027b807,0x5828b801,0x1421b805, +0x1900a021,0x001f05d8,0x90000001,0x001f25d8, +0x00ffb81a,0x801702b8,0x80970438,0x81171800, +0x8087ffff,0x80b3ffff,0x80d3007f,0x98c6ff00, +0x80f3ff80,0x81070080,0xb6006018,0x10088020, +0x0056b800,0x0442b806,0xb4a00004,0xb0000000, +0x0007b806,0xb4400001,0x0007b807,0x0027b800, +0x5c08b800,0x1400b804,0xb0030001,0xb4000008, +0x10288024,0x0056b801,0x0442b806,0xb4a00004, +0xb0010000,0x0027b806,0xb4400001,0x0027b807, +0x5828b801,0x1421b805,0x1900a021,0x00ffb81a, +0x001f0081,0xb0000001,0xb4400006,0x001f05d8, +0xb0000003,0xb4000003,0x80270001,0x003f25dc, +0x00ffb81a,0x003f05d9,0x009f05cb,0xb0010000, +0xb400000e,0x015f42ed,0x81070000,0x8127017c, +0xb00a0000,0xb4000002,0x81070180,0x812702fc, +0x802500a5,0x9421ffff,0x3001b808,0xb4800011, +0x3001b809,0xb4a00079,0xb500000e,0x001f0081, +0xb0000001,0xb4400003,0xb0040002,0xb4200006, +0xb5000002,0xb0040000,0xb4200003,0x802702ff, +0x81470000,0xb5000003,0x80270001,0x003f25d9, +0x81470180,0xb0040000,0xb4200001,0x83840344, +0x80070000,0x001f25d8,0x009f902d,0x80af001f, +0x808f0000,0x806f0000,0x8007ffff,0x8033ffff, +0x80171800,0x807bff8c,0x94630003,0xb0030003, +0xb4000016,0xb0030002,0xb4000035,0xb0030001, +0xb4000024,0xb6006010,0x14618000,0x6068b803, +0x40c4b803,0x14608000,0x00c8b806,0x5870b803, +0x6068b803,0x4104b803,0x58c8b806,0x0108b808, +0x14c6b801,0x00000000,0x00000000,0x5d08b808, +0x1508b800,0x1806a028,0xb5000030,0xb6006010, +0x14618000,0x6068b803,0x40c4b803,0x14608000, +0x00c8b806,0x5870b803,0x6068b803,0x4104b803, +0x5cc8b806,0x0108b808,0x14c6b800,0x00000000, +0x00000000,0x5908b808,0x1508b801,0x1806a028, +0xb500001e,0xb600600d,0x14618000,0x6068b803, +0x40c4b803,0x00000000,0x00c8b806,0x00000000, +0x00000000,0x00000000,0x5d08b806,0x1508b800, +0x58c8b806,0x14c6b801,0x1806a028,0xb500000f, +0xb600600e,0x14608000,0x5868b803,0x6068b803, +0x40c4b803,0x00000000,0x00c8b806,0x00000000, +0x00000000,0x00000000,0x5d08b806,0x1508b800, +0x58c8b806,0x14c6b801,0x1806a028,0x80670600, +0x5d22b80a,0xb600030a,0x00cfb803,0x013fb178, +0x5922b809,0x01afb809,0x013f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90630020,0x91290020, +0x81270180,0xb00a0000,0xb4000001,0x81270000, +0x013f62ed,0x80270001,0x003f25dc,0x00ffb81a, +0x801bff7c,0x00000000,0x94000080,0xb0000080, +0xb400ff67,0x001f0081,0xb0000001,0xb4400006, +0x001f05d8,0xb0000003,0xb4000003,0x80270001, +0x003f25dc,0x00ffb81a,0x003f05d9,0x009f05cb, +0xb0010000,0xb400000e,0x015f42ed,0x81070000, +0x812702fc,0xb00a0000,0xb4000002,0x81070300, +0x812705fc,0x802500a5,0x9421ffff,0x3001b808, +0xb4800011,0x3001b809,0xb4a0006d,0xb500000e, +0x001f0081,0xb0000001,0xb4400003,0xb0040002, +0xb4200006,0xb5000002,0xb0040000,0xb4200003, +0x802705ff,0x81470000,0xb5000003,0x80270001, +0x003f25d9,0x81470300,0xb0040000,0xb4200001, +0x838402ab,0x80070000,0x001f25d8,0x009f902d, +0x80af001f,0x808f0000,0x806f0000,0x8007ffff, +0x8033ffff,0x80171800,0x807bff8c,0x80971980, +0x94630003,0xb0030003,0xb4000013,0xb0030002, +0xb400002c,0xb0030001,0xb400001e,0xb600600d, +0x58708000,0x6068b803,0x40c4b803,0x14618020, +0x00c8b806,0x6068b803,0x4104b803,0x00000000, +0x0108b808,0x5887a026,0x00000000,0x00000000, +0x5887a028,0xb5000026,0xb600600d,0x14618000, +0x6068b803,0x40c4b803,0x58708020,0x00c8b806, +0x6068b803,0x4104b803,0x00000000,0x0108b808, +0x5887a026,0x00000000,0x00000000,0x5887a028, +0xb5000017,0xb600600a,0x14618000,0x6068b803, +0x40c4b803,0x00000000,0x00c8b806,0x00000000, +0x00000000,0x00000000,0x5887a026,0x5887a026, +0xb500000b,0xb600600a,0x58708000,0x6068b803, +0x40c4b803,0x00000000,0x00c8b806,0x00000000, +0x00000000,0x00000000,0x5887a026,0x5887a026, +0x80670660,0x5d22b80a,0xb600060a,0x00cfb803, +0x013fb178,0x5922b809,0x01afb809,0x013f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x90630020, +0x91290020,0x81270300,0xb00a0000,0xb4000001, +0x81270000,0x013f62ed,0x80270001,0x003f25dc, +0x00ffb81a,0x00000000,0x00000000,0x00000000, +0x029fb024,0x02bfb025,0x02dfb026,0x02ffb027, +0x031fb028,0x033fb029,0x033f4046,0x0287b86f, +0x029fb02a,0x8285009d,0x9a940008,0x8286009d, +0x8285009c,0x96b48000,0xb0158000,0xb40001b5, +0x96b40100,0xb0150100,0xb400020b,0x96b40400, +0xb0150400,0xb400020c,0x96b40001,0xb0150001, +0xb400000c,0x96b40008,0xb0150008,0xb40001ad, +0x96b44000,0xb0154000,0xb400020b,0x96b40002, +0xb0150002,0xb4000182,0x00000000,0x00000000, +0xb500021d,0x02bf917e,0x92b50001,0x02bfb17e, +0x82850082,0x96f40001,0xb0170000,0xb4000171, +0x5efdb814,0x96f70001,0xb0170001,0xb420000b, +0x83050069,0x9718003f,0x82e50064,0x12f7b818, +0x86f70109,0x82feff74,0x02e7b86f,0x9af74000, +0x01ffb817,0x96f7bfff,0x01ffb817,0x83050081, +0x82a5009a,0x96b50001,0xb0150001,0xb4200014, +0x82a70000,0x02bfb17e,0x96b41840,0xb0150800, +0xb420000c,0x96b40008,0x5aa9b815,0x96d46000, +0x5ec3b816,0x82f3000f,0x9af7c00f,0x1718b817, +0x1ab5b818,0x1ab5b816,0x9ab50340,0x82a60081, +0xb500014c,0x9b180180,0x83060081,0xb5000149, +0x82a5009a,0x96b50002,0xb0150002,0xb420001b, +0x82a70000,0x02bfb17e,0x96b41800,0xb0151800, +0xb4000013,0x96b40040,0xb0150040,0xb4200004, +0xa3180c00,0x9b180340,0x83060081,0xb5000139, +0x96b40008,0x5aa9b815,0x96d46000,0x5ec3b816, +0x82f3000f,0x9af7c00f,0x1718b817,0x1ab5b818, +0x1ab5b816,0x9ab50340,0x82a60081,0xb500012d, +0x9b180180,0x83060081,0xb500012a,0x82a500c1, +0x96b5000f,0xb015000b,0xb420000e,0x96b40020, +0xb0150020,0xb400000b,0x96b40200,0xb0150200, +0xb4000008,0x82c50086,0x82e50094,0x3016b817, +0xb4400004,0x06f7b816,0xb017ff00,0xb4400001, +0xb5000118,0x96b46000,0xb0156000,0xb4000011, +0x96b41820,0xb0150820,0xb4200004,0x9b391000, +0x82a5009a,0x96b5feff,0x82a6009a,0x96b40040, +0xb0150040,0xb4200001,0x9739efff,0x96b91000, +0xb0151000,0xb4200003,0x82a5009a,0x9ab50100, +0x82a6009a,0x96b40040,0xb0150040,0xb4200019, +0x96b41800,0xb0151800,0xb4200006,0x96b98000, +0xb0158000,0xb4200003,0x9b180180,0x83060081, +0xb50000f8,0x96d80c00,0x82b300ff,0x9ab5f3ff, +0x1718b815,0xb0160c00,0xb4000007,0x82e50098, +0x96f70400,0xb0170400,0xb4200002,0x82c70c00, +0xb5000001,0xa2d60c00,0x1b18b816,0x9b180340, +0xb50000c4,0x96b40220,0xb0150000,0xb4e00021, +0x82a5009d,0x82f3ffff,0x16b5b817,0x82f33800, +0x3015b817,0xb420001b,0x96f98000,0xb0178000, +0xb4000018,0x82a70000,0x02bfb17e,0x82c5009d, +0x96d6ffff,0x82b3c800,0x9ab58001,0x82e500c1, +0x96f7000f,0xb017000b,0xb4000002,0x82b38800, +0x9ab58001,0x1ab5b816,0x82c5009a,0x96d60020, +0xb0160020,0xb4200002,0x82b3c800,0x9ab58001, +0x82a6009d,0x02ff917e,0x00000000,0xb0170040, +0xb4800000,0x5eb5b814,0x96b500f0,0x96f46000, +0x5eedb817,0x1ab5b817,0xb0170003,0xb4000004, +0x96b500ef,0x96f70001,0x5ae4b817,0x1ab5b817, +0x96d41800,0xb0161800,0xb400000a,0x96f900ff, +0x96b500ff,0x9739ff00,0x1b39b815,0x02a7b817, +0x96b500f3,0x96d40008,0x5ec1b816,0x1ab5b816, +0xb500000c,0x96f98000,0xb0178000,0xb4200007, +0x5efeb814,0x96f70001,0xb0170001,0xb4000003, +0x9b180180,0x83060081,0xb50000a2,0x96b500f3, +0x9ab50008,0x9739fff3,0x96d40020,0xb0160020, +0xb4200019,0x82c7001f,0x82c600c9,0x9b398000, +0x82c70000,0x02dfb17e,0x96d40010,0x5ac8b816, +0x82f300ff,0x9af7cfff,0x1718b817,0x1b18b816, +0x9b180340,0x82c5009d,0x96d6ffff,0x82f33800, +0x9af78001,0x1af7b816,0x82c5009a,0x96d60020, +0xb0160020,0xb4200002,0x82f3c800,0x9af78001, +0x82e6009d,0xb500005f,0x97397fff,0x96b500ff, +0x5aaab815,0x82f300fc,0x9af703ff,0x1718b817, +0x1b18b815,0x9b180340,0x82c5009a,0x96d60010, +0xb0160010,0xb4200027,0x82c70000,0x02dfb17e, +0x82c50086,0x92d60e10,0x82c60086,0x82c50094, +0x5eefb818,0x96f70003,0xb0170003,0xb4200002, +0x82e70e10,0xb5000001,0x82e70e10,0x12d6b817, +0x82e50081,0x9af70020,0x82e60081,0x82c60094, +0xa2f70020,0x82e60081,0x82f30001,0x16f7b818, +0x5ef0b817,0xb0170001,0xb4000004,0x96f84000, +0x5ee4b817,0x9718f3ff,0x1b18b817,0x82f32800, +0x9af78000,0x82e6009d,0x83060081,0x83070001, +0x8306009f,0x8305009c,0xb0180001,0xb4e0fffb, +0xb50000f5,0x82c5009d,0x82f33800,0x9af78001, +0x3016b817,0xb420000f,0x82b3c800,0x9ab58001, +0x82e500c1,0x96f7000f,0xb017000b,0xb4000002, +0x82b38800,0x9ab58001,0x82c5009a,0x96d60020, +0xb0160020,0xb4200002,0x82b3c800,0x9ab58001, +0x82a6009d,0x82c5009a,0x96d60080,0xb0160080, +0xb4000013,0x02df917e,0x00000000,0xb0160010, +0xb480000f,0x82c500c1,0x96d6000f,0xb016000b, +0xb400000b,0x82c50087,0x96d60080,0x5ac7b816, +0x82c50098,0x96d60800,0x5ac3b816,0x96f84000, +0x3017b816,0xb4200002,0x033f4046,0x9b394000, +0x9739bfff,0x82e50061,0x96f70008,0xb0170008, +0xb4000005,0x5eefb818,0x96f70003,0xb0170003, +0xb4000001,0x9718ffff,0x96b41800,0xb0151800, +0xb4000008,0x5eb9b814,0x96b5000f,0x82c50099, +0x5ed0b816,0x96f6000f,0x5ab0b815,0x82a60099, +0xb5000002,0x5ef9b814,0x96f7000f,0x5aecb817, +0x82c5009a,0x96d60fff,0x1ad6b817,0x82c6009a, +0x96b46000,0xb0156000,0xb4200005,0x5ae2b817, +0x82d30ffc,0x9ad63fff,0x1718b816,0x1b18b817, +0x83060081,0x83070001,0x8306009f,0x8305009c, +0xb0180001,0xb4e0fffb,0x00000000,0xb500009e, +0x82850083,0x96b400ff,0xb015003c,0xb4200019, +0x96b92000,0xb0152000,0xb4000002,0x9b392000, +0xb5000014,0x9739d3ff,0x82870000,0x82860087, +0x82870008,0x82860083,0x829bff78,0x82a7001f, +0xb0140400,0xb4000001,0x82a70010,0x82a600c9, +0x829bff78,0x00000000,0x828600cb,0x8285009d, +0x82b3ffff,0x9ab5fffd,0x1694b815,0x8286009d, +0xb5000000,0x83070002,0x8306009f,0x00000000, +0xb500007d,0x83078000,0x8306009f,0x00000000, +0xb5000079,0x82850094,0x82a50086,0x06b5b814, +0x02b6b815,0xb0151700,0xb440004b,0x8285006c, +0x969400ff,0xb0140024,0xb4000019,0xb0140012, +0xb4000017,0x8285009a,0x5eedb814,0x96f70003, +0xb0170003,0xb4000009,0x82a50083,0x5ea8b815, +0x96b500ff,0xb0150020,0xb4400002,0x82c70bbc, +0xb5000001,0x82c70bb8,0xb5000008,0x82a50083, +0x5ea8b815,0x96b500ff,0xb0150020,0xb4400002, +0x82c71199,0xb5000001,0x82c71197,0xb5000016, +0x8285009a,0x5eedb814,0x96f70003,0xb0170003, +0xb4000009,0x82a50083,0x5ea8b815,0x96b500ff, +0xb0150020,0xb4400002,0x82c70e18,0xb5000001, +0x82c70e04,0xb5000008,0x82a50083,0x5ea8b815, +0x96b500ff,0xb0150020,0xb4400002,0x82c70e18, +0xb5000001,0x82c70e04,0x82e50086,0x12f7b816, +0x02bf917e,0xb0150020,0xb480000b,0x82a5009a, +0x96b56000,0xb0156000,0xb4000007,0x82a50098, +0x96d50a00,0xb0160a00,0xb4000002,0xb0160000, +0xb4200001,0x92f70704,0x82850081,0x9ab40020, +0x82a60081,0x82c50094,0x82e60094,0x82860081, +0x86b70704,0x82a6009b,0x83070008,0x8306009f, +0x00000000,0xb5000024,0x83070100,0x8306009f, +0x00000000,0xb5000020,0x83070000,0x83050081, +0x9b180180,0x83060081,0x83070400,0x8306009f, +0x00000000,0xb5000018,0x82870000,0x82850082, +0x5eb7b814,0x96b500fc,0x96d40006,0x5ec1b816, +0x1ab5b816,0x5aacb815,0x83050081,0x82d3001c, +0x9ad600ff,0x1718b816,0x1b18b815,0x9b180e00, +0x83060081,0x83074000,0x8306009f,0x8305009d, +0x82d3ffff,0x9ad6bfff,0x1718b816,0x8306009d, +0x00000000,0xb5000000,0x029f902a,0x01ffb814, +0x033f6046,0x029f9024,0x02bf9025,0x02df9026, +0x02ff9027,0x031f9028,0x033f9029,0x00ffb81e, +0x02ff917d,0x92f7092f,0x031f0084,0xb0180001, +0xb4200002,0x02ff917d,0x92f70870,0x02ffb17d, +0x02ff917c,0x82bbffdc,0x829bffd8,0x93150004, +0x3014b815,0xb4000017,0x02dbb818,0x029bb815, +0x3017b816,0xb4800013,0x5a81b814,0x029fb17d, +0x82def200,0x82fef204,0x82e50086,0x06f7b814, +0x02f6b817,0x82fef208,0x82860095,0x82870001, +0x829ef220,0x8293001f,0x9294fe00,0x92b50008, +0x3015b814,0xb4800002,0x82b3001f,0x92b5fa00, +0x82beffdc,0x82850086,0x83250094,0x06d4b819, +0x02d6b816,0xb016ffff,0xb4a00009,0x82c50081, +0x9ab60020,0x82a60081,0x82a50086,0x92b50e10, +0x82a60094,0x82c60081,0x86b50704,0x82a6009b, +0x00ffb81c,0x00000000,0x00000000,0x00000000, +0x001f9012,0x001fb200,0x001f004c,0x001f2804, +0x801bfef0,0x8058fef4,0x803bff68,0x8078ff6c, +0x2000b801,0x2042b803,0x001fb204,0x005f2814, +0x82e70001,0x83640048,0x029fb014,0x829efef0, +0x8286000f,0x02bf2054,0x82bcfef4,0x82a6000e, +0x00ffb81a,0x80e70001,0x801336e3,0x9800eb76, +0x001fb200,0x800700ab,0x001f2804,0x801bc3e8, +0x8058c3ec,0x83640024,0x82e70000,0x83640036, +0x029fb3c0,0x029fb200,0x02bf2f04,0x02bf2804, +0x801bc000,0x8058c004,0x8364001b,0x82e70000, +0x8364002d,0x001f93c0,0x3000b814,0xb420000a, +0x001f0f04,0x3000b815,0xb4200007,0x829efef0, +0x82bcfef4,0x029fb012,0x02bf204c,0x82870001, +0x829cfef5,0x00ffb81a,0xb0070000,0xb4000007, +0x80e70000,0x801399fa,0x9800c92e,0x001fb200, +0x800700af,0x001f2804,0xb500ffdc,0x82870000, +0x829cfef5,0x00ffb81a,0x80c700ff,0x803bff68, +0x8078ff6c,0x14a0b806,0x2063b805,0x007f2814, +0x2021b802,0x58c8b806,0x14a0b806,0x58b0b805, +0x2021b805,0x58c8b806,0x14a0b806,0x2021b805, +0x58c8b806,0x14a0b806,0x5cb0b805,0x2021b805, +0x003fb204,0x00ffb81b,0x82c70000,0x83070800, +0x83270005,0x8197080c,0x81d7ffff,0x83840126, +0x83840001,0x00ffb81b,0x808f0000,0x806f001f, +0x80af001f,0x80270240,0x81e77c08,0x5de2b80f, +0xb6000208,0x00cfb801,0x01ffb178,0x59e2b80f, +0x01cfb80f,0x01ff9178,0xb520ffff,0x91ef0020, +0x90210020,0x80270280,0x81e77b00,0x5de2b80f, +0xb6000208,0x00cfb801,0x01ffb178,0x59e2b80f, +0x01cfb80f,0x01ff9178,0xb520ffff,0x91ef0020, +0x90210020,0x8057ffff,0x80170830,0x80070810, +0x80270808,0xb6000509,0x005ff000,0x90420900, +0x007ff001,0x90630a00,0x009ff002,0x00bff003, +0x2004a025,0x90000001,0x90210001,0x80070814, +0x80d7ffff,0x8097085c,0x8017083c,0xb6000404, +0x005ff000,0x007f87e0,0x84000001,0x2082a7e3, +0x80970860,0x80170840,0x2082b803,0x007f8000, +0x2083a004,0x80170830,0x80970850,0x80270808, +0xb6000508,0x005f8024,0x90420900,0x007ff001, +0x90630a00,0x009ff002,0x00bff003,0x2004a025, +0x90210001,0x80170840,0x00000000,0x02bf87e0, +0x80970860,0x82870000,0xb6000404,0x005f87e4, +0x5a88b814,0x204287e0,0x1a94b802,0x00ffb81c, +0x001f0e49,0x001f2b09,0x001f0e41,0x001f2b08, +0x001f0e46,0x001f2b07,0x001f0e48,0x001f2b06, +0x001f0e42,0x001f2b05,0x001f0e47,0x001f2b04, +0x001f0e45,0x001f2b03,0x001f0e43,0x001f2b02, +0x001f0e40,0x001f2b01,0x001f0e44,0x001f2b00, +0x001f0f25,0xa020000c,0x94400001,0x94600002, +0x94810004,0x94a10008,0x94c00010,0x5943b802, +0x5861b803,0x5882b804,0x5ca2b805,0x5cc4b806, +0x194ab803,0x194ab804,0x194ab805,0x194ab806, +0x015f2b38,0x801b7c00,0x003f92c1,0x5c28b801, +0x005f92c2,0x5858b802,0x1821b802,0x2000b801, +0x001fb2c4,0x80187c04,0x003f0b09,0x2000b801, +0x001f2b14,0x82c70001,0x82e70001,0x83070b10, +0x8327001e,0x81970b35,0x8384009f,0x02df0b38, +0x82170e30,0x838400f1,0x819efef0,0x817cfef4, +0x819eff68,0x817cff6c,0x00ffb81b,0x820f001f, +0x8018fef8,0x8057ffff,0x001f2b09,0x8018fef6, +0x80d7ffff,0x001f2b08,0x8018fefa,0x8157ffff, +0x001f2b07,0x8018fefd,0x81d7ffff,0x001f2b06, +0x8018fefb,0x802f001f,0x001f2b05,0x8018fefe, +0x00000000,0x001f2b04,0x8018fef9,0x00000000, +0x001f2b03,0x8018feff,0x00000000,0x001f2b02, +0x8018fef7,0x00000000,0x001f2b01,0x8018fefc, +0x00000000,0x001f2b00,0x001f0f25,0xa0200011, +0x94410001,0x94600002,0x94800004,0x94a00008, +0x94c10010,0x5941b802,0x5861b803,0x5c82b804, +0x58a1b805,0x5cc1b806,0x194ab803,0x194ab804, +0x194ab805,0x194ab806,0x015f2b38,0x801b7c00, +0x003f92c1,0x5c28b801,0x005f92c2,0x5858b802, +0x1821b802,0x2000b801,0x001fb2c4,0x80187c04, +0x003f0b09,0x2000b801,0x001f2b14,0x82c70001, +0x82e70001,0x83070b10,0x8327001e,0x81970b35, +0x83840055,0x02df0b38,0x82170e20,0x838400a7, +0x819efef0,0x817cfef4,0x5ac8b80c,0x02ff0e44, +0x1ad6b817,0x02dfb391,0x5ed8b80c,0x5968b80b, +0x1ad6b80b,0x02df6724,0x00ffb81b,0x820f001f, +0x8018fefe,0x8057ffff,0x001f2b09,0x8018fefa, +0x80d7ffff,0x001f2b08,0x8018fefc,0x8157ffff, +0x001f2b07,0x8018feff,0x81d7ffff,0x001f2b06, +0x8018fef8,0x802f001f,0x001f2b05,0x8018fefb, +0x00000000,0x001f2b04,0x8018fefd,0x00000000, +0x001f2b03,0x8018fef6,0x00000000,0x001f2b02, +0x8018fef9,0x00000000,0x001f2b01,0x8018fef7, +0x00000000,0x001f2b00,0x801b7c00,0x003f92c1, +0x5c28b801,0x005f92c2,0x5858b802,0x1821b802, +0x2000b801,0x001fb2c4,0x80187c04,0x003f0b09, +0x2000b801,0x001f2b14,0x82c70001,0x82e70001, +0x83070b10,0x8327001e,0x81970b35,0x83840016, +0x83270000,0x831bfef0,0x82f8fef4,0x02c7b819, +0x82170e28,0x83840065,0x300cb818,0xb4200002, +0x300bb817,0xb4000006,0x93390001,0xb0190020, +0xb480fff6,0x83270000,0x833cfef5,0x00ffb81b, +0x019fb390,0x017f2e44,0x033f2f25,0x83270001, +0x833cfef5,0x00ffb81b,0x0007b818,0x90000003, +0x00000000,0x015ff000,0x90000001,0x5949b80a, +0x013ff000,0x194ab809,0x84000002,0x994a0100, +0x017ff000,0x958b00f8,0x5981b80c,0x956b0007, +0x198cb80b,0x84000002,0x998c0008,0x017ff000, +0x90000001,0x5971b80b,0x198cb80b,0x017ff000, +0x5969b80b,0x198cb80b,0x81a70000,0x94d90003, +0x82a70000,0xb6260019,0xb6000818,0x5df0b80a, +0x5e02b80a,0x21efb810,0x95ef0001,0x5941b80a, +0x194ab80f,0x21efb816,0x5e18b80c,0x5e35b80c, +0x5e54b80c,0x5e6cb80c,0x2210b811,0x2252b813, +0x2210b812,0x96100001,0x5981b80c,0x198cb810, +0x2210b817,0x10afb810,0x10a5b80d,0x5da1b805, +0x94a50001,0x5aa1b815,0x1ab5b805,0x019fa7f5, +0x5cc2b819,0xb626001c,0x82870000,0xb6000419, +0xb6000818,0x5df0b80a,0x5e02b80a,0x21efb810, +0x95ef0001,0x5941b80a,0x194ab80f,0x21efb816, +0x5e18b80c,0x5e35b80c,0x5e54b80c,0x5e6cb80c, +0x2210b811,0x2252b813,0x2210b812,0x96100001, +0x5981b80c,0x198cb810,0x2210b817,0x10afb810, +0x10a5b80d,0x5da1b805,0x94a50001,0x5a81b814, +0x1a94b805,0x019fa7f4,0x00ffb81c,0x8257ffff, +0x808f0000,0x806f001f,0x80af001f,0x80270300, +0x81e778e0,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x80270340, +0x81e779e0,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x80270280, +0x81e77b00,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x806f0007, +0x80af0007,0x80270380,0x81e77ae0,0x5de2b80f, +0x00cfb801,0x01ffb178,0x59e2b80f,0x01cfb80f, +0x01ff9178,0xb520ffff,0x91ef0020,0x90210020, +0x80170b60,0x001f0b00,0x001fa020,0x001f0b01, +0x001fa020,0x001f0b02,0x001fa020,0x001f0b03, +0x001fa020,0x001f0b04,0x001fa000,0x80970b50, +0x81170b70,0x82a70b35,0x83a40060,0x001f87e4, +0xb6000405,0x86b50001,0x83a4005c,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b70,0x80170b50, +0x81170b50,0x81970b40,0x82a70b30,0x001f800c, +0x003f8008,0x2100a001,0x83a40050,0x001f87e4, +0xb6000405,0x86b50001,0x83a4004c,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b50,0x80170b70, +0x81170b70,0x81970b60,0x82a70b2b,0x001f800c, +0x003f8008,0x2100a001,0x83a40040,0x83a4004e, +0xb6000407,0x86b50001,0x83a4003c,0x001f8004, +0x003f87e8,0x2080a001,0x83a40047,0x00000000, +0x80970b70,0x80170b50,0x81170b50,0x81970b40, +0x82a70b26,0x001f800c,0x003f8008,0x2100a001, +0x83a4002e,0x83a4003c,0xb6000407,0x86b50001, +0x83a4002a,0x001f8004,0x003f87e8,0x2080a001, +0x83a40035,0x00000000,0x80970b50,0x80170b70, +0x81170b70,0x81970b60,0x82a70b21,0x001f800c, +0x003f8008,0x2100a001,0x83a4001c,0x001f87e4, +0xb6000405,0x86b50001,0x83a40018,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b70,0x80170b50, +0x81170b50,0x81970b40,0x82a70b1c,0x001f800c, +0x003f8008,0x2100a001,0x83a4000c,0x017f87e4, +0x81870000,0xb6000406,0x86b50001,0x83a40007, +0x001f87e4,0x200087e8,0x5988b80c,0x198cb800, +0x021fa02c,0x021fa00b,0x00ffb81c,0x005ff015, +0x90420a00,0x003f87e0,0x001ff002,0x2060b801, +0x90630c00,0x90960e00,0x001ff003,0x003ff004, +0x20a0b801,0x90a50d00,0x00000000,0x001ff005, +0x009fa000,0x00ffb81d,0x001f8004,0x5c21b800, +0x5847b800,0x1821b802,0x942100ff,0x2080a7e1, +0x00ffb81d,0x00000000,0x00000000,0x00000000, + +}; + +static u32 MPGI2S240Ucode1f5c00[] = { +0x00000000,0xfffff8c0,0x00003540,0xffff8d40, +0x0001fd40,0xfffaf7c0,0x00066b80,0xffdb63c0, +0x00494780,0x00249c40,0x00066b80,0x00050840, +0x0001fd40,0x000072c0,0x00003540,0x00000740, +0xffffffc0,0xfffff840,0x00003680,0xffff7e40, +0x0001f400,0xfffa9cc0,0x0005d1c0,0xffd99600, +0x00493c00,0x0022ce00,0x0006f780,0x0004ad00, +0x000203c0,0x00006440,0x00003400,0x00000680, +0xffffffc0,0xfffff740,0x00003780,0xffff6ec0, +0x0001e800,0xfffa4240,0x00052a00,0xffd7ca00, +0x00491a00,0x0020ffc0,0x00077600,0x00045240, +0x00020800,0x000056c0,0x00003280,0x00000600, +0xffffffc0,0xfffff680,0x00003840,0xffff5ec0, +0x0001d940,0xfff9e8c0,0x00047440,0xffd60080, +0x0048e180,0x001f32c0,0x0007e700,0x0003f7c0, +0x000209c0,0x00004980,0x00003100,0x00000540, +0xffffffc0,0xfffff5c0,0x000038c0,0xffff4e40, +0x0001c780,0xfff990c0,0x0003b000,0xffd43ac0, +0x00489240,0x001d6800,0x00084b00,0x00039e40, +0x00020940,0x00003d00,0x00002f80,0x000004c0, +0xffffffc0,0xfffff4c0,0x00003900,0xffff3d40, +0x0001b2c0,0xfff93a40,0x0002ddc0,0xffd279c0, +0x00482d00,0x001ba040,0x0008a200,0x000345c0, +0x000206c0,0x00003140,0x00002dc0,0x00000440, +0xffffffc0,0xfffff3c0,0x00003900,0xffff2c00, +0x00019b00,0xfff8e640,0x0001fd40,0xffd0be80, +0x0047b1c0,0x0019dc80,0x0008ecc0,0x0002ef00, +0x00020240,0x00002640,0x00002c00,0x00000400, +0xffffff80,0xfffff2c0,0x000038c0,0xffff1a40, +0x00017fc0,0xfff894c0,0x00010e80,0xffcf09c0, +0x004720c0,0x00181d80,0x00092b40,0x000299c0, +0x0001fc00,0x00001bc0,0x00002a40,0x00000380, +0xffffff80,0xfffff180,0x00003800,0xffff0840, +0x00016180,0xfff84680,0x00001180,0xffcd5cc0, +0x00467a40,0x00166440,0x00095e00,0x00024680, +0x0001f440,0x00001200,0x00002840,0x00000340, +0xffffff80,0xfffff040,0x00003740,0xfffef600, +0x00014000,0xfff7fbc0,0xffff0680,0xffcbb880, +0x0045bf00,0x0014b140,0x00098580,0x0001f580, +0x0001ea80,0x00000900,0x00002680,0x000002c0, +0xffffff80,0xffffef00,0x000035c0,0xfffee3c0, +0x00011ac0,0xfff7b540,0xfffded80,0xffca1d80, +0x0044ef80,0x00130580,0x0009a1c0,0x0001a700, +0x0001dfc0,0x00000080,0x000024c0,0x00000280, +0xffffff40,0xffffedc0,0x00003400,0xfffed180, +0x0000f280,0xfff77340,0xfffcc700,0xffc88d80, +0x00440bc0,0x001161c0,0x0009b3c0,0x00015b00, +0x0001d380,0xfffff8c0,0x000022c0,0x00000240, +0xffffff40,0xffffec40,0x00003200,0xfffebf40, +0x0000c680,0xfff73680,0xfffb92c0,0xffc708c0, +0x00431500,0x000fc6c0,0x0009bb80,0x000111c0, +0x0001c640,0xfffff1c0,0x00002100,0x00000200, +0xffffff00,0xffffeac0,0x00002f40,0xfffead00, +0x00009740,0xfff6ff40,0xfffa5180,0xffc59080, +0x00420b40,0x000e3500,0x0009b9c0,0x0000cb80, +0x0001b7c0,0xffffeb40,0x00001f40,0x000001c0, +0xffffff00,0xffffe940,0x00002c40,0xfffe9b00, +0x00006480,0xfff6ce00,0xfff90380,0xffc425c0, +0x0040ef80,0x000cad00,0x0009af00,0x00008840, +0x0001a880,0xffffe580,0x00001d40,0x000001c0, +0xfffffec0,0xffffe7c0,0x000028c0,0xfffe8980, +0x00002e40,0xfff6a3c0,0xfff7a900,0xffc2c900, +0x003fc280,0x000b2fc0,0x00099b80,0x00004800, +0x00019880,0xffffe040,0x00001bc0,0x00000180, +0xfffffec0,0xffffe600,0x00002480,0xfffe7840, +0xfffff4c0,0xfff68040,0xfff64240,0xffc17b40, +0x003e84c0,0x0009bdc0,0x00097fc0,0x00000b40, +0x000187c0,0xffffdb80,0x00001a00,0x00000140, +0xfffffe80,0xffffe440,0x00001fc0,0xfffe6780, +0xffffb800,0xfff66480,0xfff4d040,0xffc03d80, +0x003d3700,0x00085700,0x00095c40,0xffffd1c0, +0x00017680,0xffffd740,0x00001840,0x00000140, +0xfffffe40,0xffffe2c0,0x00001a80,0xfffe5780, +0xffff77c0,0xfff65100,0xfff35300,0xffbf1080, +0x003bda40,0x0006fc80,0x00093200,0xffff9b80, +0x00016500,0xffffd3c0,0x000016c0,0x00000100, +0xfffffe40,0xffffe0c0,0x000014c0,0xfffe4840, +0xffff3480,0xfff64640,0xfff1cb00,0xffbdf4c0, +0x003a6f80,0x0005ae80,0x000900c0,0xffff68c0, +0x00015300,0xffffd0c0,0x00001540,0x00000100, +0xfffffe00,0xffffdf00,0x00000e40,0xfffe39c0, +0xfffeee40,0xfff64480,0xfff03940,0xffbceb00, +0x0038f740,0x00046d40,0x0008c980,0xffff3980, +0x000140c0,0xffffce00,0x000013c0,0x000000c0, +0xfffffdc0,0xffffdd40,0x00000740,0xfffe2c80, +0xfffea500,0xfff64c40,0xffee9e40,0xffbbf440, +0x00377280,0x00033900,0x00088cc0,0xffff0d80, +0x00012e80,0xffffcc00,0x00001240,0x000000c0, +0xfffffd80,0xffffdb40,0xffffff80,0xfffe2040, +0xfffe5900,0xfff65e40,0xffecfa80,0xffbb1080, +0x0035e280,0x00021280,0x00084ac0,0xfffee540, +0x00011c40,0xffffca40,0x00001100,0x00000080, +0xfffffd40,0xffffd980,0xfffff700,0xfffe1580, +0xfffe0a80,0xfff67a80,0xffeb4ec0,0xffba4100, +0x00344780,0x0000f980,0x00080440,0xfffec000, +0x00010a00,0xffffc8c0,0x00000fc0,0x00000080, +0xfffffcc0,0xffffd7c0,0xffffee00,0xfffe0bc0, +0xfffdb980,0xfff6a200,0xffe99bc0,0xffb985c0, +0x0032a340,0xffffee80,0x0007b980,0xfffe9e80, +0x0000f7c0,0xffffc800,0x00000e80,0x00000080, +0xfffffc80,0xffffd5c0,0xffffe440,0xfffe0400, +0xfffd6640,0xfff6d4c0,0xffe7e280,0xffb8df40, +0x0030f640,0xfffef180,0x00076b40,0xfffe8040, +0x0000e5c0,0xffffc740,0x00000d40,0x00000080, +0xfffffc00,0xffffd400,0xffffd9c0,0xfffdfdc0, +0xfffd1100,0xfff71340,0xffe62380,0xffb84e40, +0x002f4180,0xfffe02c0,0x000719c0,0xfffe6500, +0x0000d400,0xffffc700,0x00000c40,0x00000040, +0xfffffbc0,0xffffd240,0xffffcec0,0xfffdf940, +0xfffcba40,0xfff75e00,0xffe45fc0,0xffb7d300, +0x002d8640,0xfffd2240,0x0006c5c0,0xfffe4d40, +0x0000c2c0,0xffffc700,0x00000b40,0x00000040, +0xfffffb40,0xffffd080,0xffffc300,0xfffdf6c0, +0xfffc61c0,0xfff7b500,0xffe29800,0xffb76dc0, +0x002bc540,0xfffc5000,0x00066f40,0xfffe3880, +0x0000b1c0,0xffffc740,0x00000a40,0x00000040, +0xfffffac0,0xffffcf00,0xffffb680,0xfffdf640, +0xfffc0840,0xfff81900,0xffe0cd40,0xffb71e80, +0x0029ff80,0xfffb8bc0,0x00061740,0xfffe26c0, +0x0000a140,0xffffc7c0,0x00000980,0x00000040, +0xfffffa00,0xffffcd80,0xffffa940,0xfffdf800, +0xfffbadc0,0xfff88a00,0xffdf0040,0xffb6e600, +0x00283600,0xfffad600,0x0005bdc0,0xfffe1800, +0x00009140,0xffffc880,0x000008c0,0x00000040, +0xfffff980,0xffffcc00,0xffff9bc0,0xfffdfc40, +0xfffb5300,0xfff90880,0xffdd3200,0xffb6c400, +0x00266a00,0xfffa2e40,0x00056340,0xfffe0c00, +0x000081c0,0xffffc980,0x000007c0,0x00000040, +0x004013c2,0x0040b346,0x0041fa2d,0x0043f934, +0x0046cc1c,0x004a9d9d,0x004fae37,0x0056601f, +0x005f4cf7,0x006b6fcf,0x007c7d1e,0x0115b035, +0x013df91b,0x0207655e,0x03342c83,0x0a185230, +0x00404f46,0x0042e13c,0x0048919f,0x0052cb0e, +0x0064e240,0x0107c449,0x015c7926,0x050cf270, +0x004140fb,0x004cf8df,0x0073326c,0x02480d9d, +0x004545ea,0x01273d75,0x005a827a,0x007fffff, +0x006597fb,0x0050a28c,0x00400000,0x0032cbfd, +0x00285146,0x00200000,0x001965ff,0x001428a3, +0x00100000,0x000cb2ff,0x000a1451,0x00080000, +0x00065980,0x00050a29,0x00040000,0x00032cc0, +0x00028514,0x00020000,0x00019660,0x0001428a, +0x00010000,0x0000cb30,0x0000a145,0x00008000, +0x00006598,0x000050a3,0x00004000,0x000032cc, +0x00002851,0x00002000,0x00001966,0x00001429, +0x00001000,0x00000cb3,0x00000a14,0x00000800, +0x00000659,0x0000050a,0x00000400,0x0000032d, +0x00000285,0x00000200,0x00000196,0x00000143, +0x00000100,0x000000cb,0x000000a1,0x00000080, +0x00000066,0x00000051,0x00000040,0x00000033, +0x00000028,0x00000020,0x00000019,0x00000014, +0x00000010,0x0000000d,0x0000000a,0x00000008, +0x00000006,0x00000005,0x00000000,0x00555555, +0x00666666,0x00492492,0x0071c71c,0x00444444, +0x00421084,0x00410410,0x00408102,0x00404040, +0x00402010,0x00401004,0x00400801,0x00400400, +0x00400200,0x00400100,0x00400080,0x00400040, +0x00400000,0x00400000,0x00200000,0x00400000, +0x00100000,0x00080000,0x00040000,0x00020000, +0x00010000,0x00008000,0x00004000,0x00002000, +0x00001000,0x00000800,0x00000400,0x00000200, +0x00000100,0x0003588d,0x0002b15e,0x0002056d, +0x00015600,0x0000a329,0xffffeed9,0xffff3960, +0xfffe8423,0xfffdd11c,0xfffd2048,0xfffc7353, +0xfffbcb6f,0xfffb29a6,0xfffa8f15,0x000494ae, +0x0003f991,0x00032dd1,0xfffd2d8f,0x0001eb47, +0xfffe9968,0x00009af6,0x000011de,0xffff4335, +0x00018d69,0xfffdecd4,0x000302f8,0xfffca0d7, +0x0004683d,0xfffb67f8,0x0005b36d,0x00045963, +0xfffbd51e,0x00030062,0xfffd0dee,0x0001d046, +0xfffe8a0a,0x00009258,0x000012b1,0xffff4d9e, +0x00019ec3,0xfffe0a44,0x0003245a,0xfffcd082, +0x000498f0,0xfffba919,0x0005f304,0x00041bf4, +0xfffba72a,0x0002d19e,0xfffcf060,0x0001b407, +0xfffe7c08,0x0000894a,0x0000138d,0xffff58ac, +0x0001afaf,0xfffe28fe,0x000343bf,0xfffd026f, +0x0004c6f6,0xfffbed06,0x00062e61,0x0003dc0e, +0xfffb7bf1,0x0002a17f,0xfffcd522,0x000196a0, +0xfffe6e70,0x00007ff6,0x00001439,0xffff63f6, +0x0001beb3,0xfffe4882,0x0003616d,0xfffd361b, +0x0004f1cf,0xfffc332a,0x0006658f,0x00039943, +0xfffb52c0,0x00026ec7,0xfffcbb94,0x0001789f, +0xfffe6160,0x00007677,0x000014d4,0xffff6f74, +0x0001cc9b,0xfffe694f,0x00037cbf,0xfffd6b41, +0x000519c2,0xfffc7baf,0x00069971,0x00035486, +0xfffb2d0c,0x00023ad8,0xfffca3ee,0x00015989, +0xfffe55af,0x00006ca7,0x00001570,0xffff7b71, +0x0001d9cb,0xfffe8b46,0x0003959e,0xfffda1fe, +0x00053ee6,0xfffcc6b4,0x0006c950,0x00030e08, +0xfffb0a7a,0x0002061e,0xfffc8ec0,0x00013911, +0xfffe4b1d,0x00006278,0x000015e8,0xffff87b6, +0x0001e577,0xfffeadd6,0x0003acc2,0xfffdda34, +0x00056059,0xfffd136d,0x0006f4b5,0x0002c562, +0xfffaea7c,0x0001cfa6,0xfffc7b14,0x0001182b, +0xfffe4159,0x00005817,0x0000165c,0xffff9417, +0x0001f00f,0xfffed14c,0x0003c199,0xfffe13f6, +0x00057e83,0xfffd61cd,0x00071ba1,0x00027ab5, +0xfffacdc3,0x00019833,0xfffc6989,0x0000f6ca, +0xfffe38da,0x00004d9d,0x000016ef,0xffffa103, +0x0001f98f,0xfffef5c0,0x0003d3d1,0xfffe4f00, +0x0005998c,0xfffdb21e,0x00073e77,0x00022e75, +0xfffab482,0x00015fd1,0xfffc5b13,0x0000d45d, +0xfffe318f,0x000042ed,0x0000176b,0xffffae8f, +0x0002018f,0xffff1a91,0x0003e40c,0xfffe8af2, +0x0005b0ca,0xfffe03b8,0x00075d14,0x0001e141, +0xfffa9e9b,0x0001262a,0xfffc4e31,0x0000b1af, +0xfffe2b26,0x00003805,0x000017b1,0xffffbc21, +0x000208b8,0xffff3fb6,0x0003f1d7,0xfffec7af, +0x0005c4c5,0xfffe5654,0x0007768a,0x000192fe, +0xfffa8bb0,0x0000ec3f,0xfffc4365,0x00008ec9, +0xfffe25f0,0x00002d05,0x000017ec,0xffffc984, +0x00020ec6,0xffff658d,0x0003fcba,0xffff0500, +0x0005d576,0xfffeaa37,0x00078bc6,0x00014367, +0xfffa7bec,0x0000b1f4,0xfffc3b82,0x00006b06, +0xfffe2201,0x000021eb,0x00001823,0xffffd704, +0x0002132a,0xffff8be7,0x00040534,0xffff4315, +0x0005e22e,0xfffeff0a,0x00079ce3,0x0000f33f, +0xfffa6fc9,0x000076ca,0xfffc3558,0x00004762, +0xfffe1ef3,0x000016a1,0x0000183f,0xffffe4a6, +0x00021664,0xffffb27d,0x00040b7b,0xffff81e5, +0x0005eb4e,0xffff5475,0x0007a857,0x0000a2cb, +0xfffa671b,0x00003b64,0xfffc31e2,0x00002416, +0xfffe1ce1,0x00000b46,0x00001850,0xfffff24d, +0x00021855,0xffffd93a,0x00040f75,0xffffc0e6, +0x0005f0e3,0xffffaa3e,0x0007af45,0x0000519f, +0xfffa6218,0x0003f991,0x0003588d,0x0002b15e, +0x0002056d,0x00015600,0x0000a329,0xffffeed9, +0xffff3960,0xfffe8423,0xfffdd11c,0xfffd2048, +0xfffc7353,0xfffbcb6f,0xfffb29a6,0xfffa8f15, +0x000494ae,0x0003c6b0,0xfffc7e8b,0x00028ef6, +0xfffde181,0x000144eb,0xffff5500,0xffffefb9, +0x0000d01d,0xfffe9755,0x000249a4,0xfffd453c, +0x0003b80e,0xfffc01aa,0x000511d6,0xfffad527, +0xfffb334e,0x0003916c,0xfffc5778,0x00026a92, +0xfffdc9f5,0x00013314,0xffff4d99,0xfffff0b6, +0x0000d911,0xfffeab80,0x00026369,0xfffd6c0a, +0x0003e17f,0xfffc39d8,0x000549df,0xfffb1eb2, +0xfffafe6c,0x00035929,0xfffc3321,0x000244a6, +0xfffdb402,0x00012035,0xffff46ac,0xfffff192, +0x0000e16a,0xfffebfe0,0x00027b3d,0xfffd9433, +0x0004087b,0xfffc74b7,0x00057e8d,0xfffb6a81, +0xfffacc1c,0x00031fbe,0xfffc10df,0x00021e0c, +0xfffd9f6d,0x00010cb7,0xffff402e,0xfffff279, +0x0000e965,0xfffed574,0x00029159,0xfffdbdc4, +0x00042c4c,0xfffcb1e7,0x0005b02d,0xfffbb942, +0xfffa9d38,0x0002e44a,0xfffbf0fd,0x0001f5b4, +0xfffd8c38,0x0000f8b1,0xffff3a21,0xfffff391, +0x0000f0e6,0xfffeec44,0x0002a642,0xfffde90e, +0x00044e32,0xfffcf0fb,0x0005de46,0xfffc0b18, +0xfffa71d1,0x0002a659,0xfffbd3de,0x0001cb90, +0xfffd7a97,0x0000e403,0xffff3490,0xfffff49c, +0x0000f7a8,0xffff0340,0x0002b95f,0xfffe1573, +0x00046dbe,0xfffd3284,0x00060888,0xfffc5f51, +0xfffa4996,0x00026786,0xfffbb8df,0x0001a0e1, +0xfffd6a4e,0x0000ced2,0xffff2f75,0xfffff593, +0x0000fdbe,0xffff1a53,0x0002ca87,0xfffe42f5, +0x0004898a,0xfffd7563,0x00062f0b,0xfffcb5de, +0xfffa2508,0x00022713,0xfffba0bf,0x0001754a, +0xfffd5b5f,0x0000b92c,0xffff2acd,0xfffff6b0, +0x0001034f,0xffff3241,0x0002da5c,0xfffe71c6, +0x0004a341,0xfffdb946,0x000651e8,0xfffd0e37, +0xfffa0402,0x0001e4d4,0xfffb8b9c,0x00014898, +0xfffd4e7d,0x0000a304,0xffff26b7,0xfffff7e1, +0x00010846,0xffff4b34,0x0002e897,0xfffea13f, +0x0004ba63,0xfffdff2d,0x00067115,0xfffd6839, +0xfff9e680,0x0001a1fa,0xfffb789e,0x00011b2e, +0xfffd43a4,0x00008c6e,0xffff2341,0xfffff8fd, +0x00010c9c,0xffff6469,0x0002f48f,0xfffed1a4, +0x0004cd6a,0xfffe4608,0x00068c1b,0xfffdc409, +0xfff9cd15,0x00015dfe,0xfffb68a0,0x0000ecee, +0xfffd3a2e,0x0000757d,0xffff204b,0xfffffa1e, +0x00011054,0xffff7da1,0x0002fe9c,0xffff033e, +0x0004de57,0xfffe8dc6,0x0006a2d5,0xfffe213e, +0xfff9b77d,0x000118d3,0xfffb5bde,0x0000be25, +0xfffd3224,0x00005e52,0xffff1dc1,0xfffffb4b, +0x00011353,0xffff9740,0x00030748,0xffff351c, +0x0004ec95,0xfffed755,0x0006b5b4,0xfffe7fc6, +0xfff9a599,0x0000d334,0xfffb519f,0x00008f08, +0xfffd2bbf,0x00004704,0xffff1bc1,0xfffffc71, +0x00011598,0xffffb135,0x00030e43,0xffff6720, +0x0004f6f3,0xffff2119,0x0006c46e,0xfffedf38, +0xfff997c7,0x00008d13,0xfffb4a55,0x00005fa5, +0xfffd273b,0x00002f76,0xffff1a63,0xfffffda0, +0x00011744,0xffffcb67,0x000312ff,0xffff99cf, +0x0004ff0c,0xffff6a9c,0x0006cebd,0xffff3f0a, +0xfff98dbe,0x00004691,0xfffb4620,0x00003010, +0xfffd24fc,0x000017b5,0xffff199d,0xfffffed8, +0x0001185a,0xffffe5c6,0x0003157e,0xffffcce3, +0x000503ae,0xffffb515,0x0006d537,0xffff9f5a, +0xfff98767,0xfffb44b0,0xfffc3131,0xfffd2475, +0xfffe1c28,0xffff195d,0x00001859,0x000118bd, +0x000218df,0x0003163a,0x000410e0,0x000504a7, +0x0005f2b3,0x0006d796,0x0007b1fe,0xfff98537, +0xfffa609b,0xfffc7e8b,0x00028ef6,0xfffde181, +0x000144eb,0xffff5500,0xffffefb9,0x0000d01d, +0xfffe9755,0x000249a4,0xfffd453c,0x0003b80e, +0xfffc01aa,0x000511d6,0xfffad527,0xfffb334e, +0x0003c6b0,0xfffc5778,0x00026a92,0xfffdc9f5, +0x00013314,0xffff4d99,0xfffff0b6,0x0000d911, +0xfffeab80,0x00026369,0xfffd6c0a,0x0003e17f, +0xfffc39d8,0x000549df,0xfffb1eb2,0xfffafe6c, +0x0003916c,0xfffc3321,0x000244a6,0xfffdb402, +0x00012035,0xffff46ac,0xfffff192,0x0000e16a, +0xfffebfe0,0x00027b3d,0xfffd9433,0x0004087b, +0xfffc74b7,0x00057e8d,0xfffb6a81,0xfffacc1c, +0x00035929,0xfffc10df,0x00021e0c,0xfffd9f6d, +0x00010cb7,0xffff402e,0xfffff279,0x0000e965, +0xfffed574,0x00029159,0xfffdbdc4,0x00042c4c, +0xfffcb1e7,0x0005b02d,0xfffbb942,0xfffa9d38, +0x00031fbe,0xfffbf0fd,0x0001f5b4,0xfffd8c38, +0x0000f8b1,0xffff3a21,0xfffff391,0x0000f0e6, +0xfffeec44,0x0002a642,0xfffde90e,0x00044e32, +0xfffcf0fb,0x0005de46,0xfffc0b18,0xfffa71d1, +0x0002e44a,0xfffbd3de,0x0001cb90,0xfffd7a97, +0x0000e403,0xffff3490,0xfffff49c,0x0000f7a8, +0xffff0340,0x0002b95f,0xfffe1573,0x00046dbe, +0xfffd3284,0x00060888,0xfffc5f51,0xfffa4996, +0x0002a659,0xfffbb8df,0x0001a0e1,0xfffd6a4e, +0x0000ced2,0xffff2f75,0xfffff593,0x0000fdbe, +0xffff1a53,0x0002ca87,0xfffe42f5,0x0004898a, +0xfffd7563,0x00062f0b,0xfffcb5de,0xfffa2508, +0x00026786,0xfffba0bf,0x0001754a,0xfffd5b5f, +0x0000b92c,0xffff2acd,0xfffff6b0,0x0001034f, +0xffff3241,0x0002da5c,0xfffe71c6,0x0004a341, +0xfffdb946,0x000651e8,0xfffd0e37,0xfffa0402, +0x00022713,0xfffb8b9c,0x00014898,0xfffd4e7d, +0x0000a304,0xffff26b7,0xfffff7e1,0x00010846, +0xffff4b34,0x0002e897,0xfffea13f,0x0004ba63, +0xfffdff2d,0x00067115,0xfffd6839,0xfff9e680, +0x0001e4d4,0xfffb789e,0x00011b2e,0xfffd43a4, +0x00008c6e,0xffff2341,0xfffff8fd,0x00010c9c, +0xffff6469,0x0002f48f,0xfffed1a4,0x0004cd6a, +0xfffe4608,0x00068c1b,0xfffdc409,0xfff9cd15, +0x0001a1fa,0xfffb68a0,0x0000ecee,0xfffd3a2e, +0x0000757d,0xffff204b,0xfffffa1e,0x00011054, +0xffff7da1,0x0002fe9c,0xffff033e,0x0004de57, +0xfffe8dc6,0x0006a2d5,0xfffe213e,0xfff9b77d, +0x00015dfe,0xfffb5bde,0x0000be25,0xfffd3224, +0x00005e52,0xffff1dc1,0xfffffb4b,0x00011353, +0xffff9740,0x00030748,0xffff351c,0x0004ec95, +0xfffed755,0x0006b5b4,0xfffe7fc6,0xfff9a599, +0x000118d3,0xfffb519f,0x00008f08,0xfffd2bbf, +0x00004704,0xffff1bc1,0xfffffc71,0x00011598, +0xffffb135,0x00030e43,0xffff6720,0x0004f6f3, +0xffff2119,0x0006c46e,0xfffedf38,0xfff997c7, +0x0000d334,0xfffb4a55,0x00005fa5,0xfffd273b, +0x00002f76,0xffff1a63,0xfffffda0,0x00011744, +0xffffcb67,0x000312ff,0xffff99cf,0x0004ff0c, +0xffff6a9c,0x0006cebd,0xffff3f0a,0xfff98dbe, +0x00008d13,0xfffb4620,0x00003010,0xfffd24fc, +0x000017b5,0xffff199d,0xfffffed8,0x0001185a, +0xffffe5c6,0x0003157e,0xffffcce3,0x000503ae, +0xffffb515,0x0006d537,0xffff9f5a,0xfff98767, +0x00004691,0xfffa609b,0xfffb44b0,0xfffc3131, +0xfffd2475,0xfffe1c28,0xffff195d,0x00001859, +0x000118bd,0x000218df,0x0003163a,0x000410e0, +0x000504a7,0x0005f2b3,0x0006d796,0x0007b1fe, +0xfff98537,0xfffbd51e,0x00032dd1,0xfffd2d8f, +0x0001eb47,0xfffe9968,0x00009af6,0x000011de, +0xffff4335,0x00018d69,0xfffdecd4,0x000302f8, +0xfffca0d7,0x0004683d,0xfffb67f8,0x0005b36d, +0x00045963,0xfffba72a,0x00030062,0xfffd0dee, +0x0001d046,0xfffe8a0a,0x00009258,0x000012b1, +0xffff4d9e,0x00019ec3,0xfffe0a44,0x0003245a, +0xfffcd082,0x000498f0,0xfffba919,0x0005f304, +0x00041bf4,0xfffb7bf1,0x0002d19e,0xfffcf060, +0x0001b407,0xfffe7c08,0x0000894a,0x0000138d, +0xffff58ac,0x0001afaf,0xfffe28fe,0x000343bf, +0xfffd026f,0x0004c6f6,0xfffbed06,0x00062e61, +0x0003dc0e,0xfffb52c0,0x0002a17f,0xfffcd522, +0x000196a0,0xfffe6e70,0x00007ff6,0x00001439, +0xffff63f6,0x0001beb3,0xfffe4882,0x0003616d, +0xfffd361b,0x0004f1cf,0xfffc332a,0x0006658f, +0x00039943,0xfffb2d0c,0x00026ec7,0xfffcbb94, +0x0001789f,0xfffe6160,0x00007677,0x000014d4, +0xffff6f74,0x0001cc9b,0xfffe694f,0x00037cbf, +0xfffd6b41,0x000519c2,0xfffc7baf,0x00069971, +0x00035486,0xfffb0a7a,0x00023ad8,0xfffca3ee, +0x00015989,0xfffe55af,0x00006ca7,0x00001570, +0xffff7b71,0x0001d9cb,0xfffe8b46,0x0003959e, +0xfffda1fe,0x00053ee6,0xfffcc6b4,0x0006c950, +0x00030e08,0xfffaea7c,0x0002061e,0xfffc8ec0, +0x00013911,0xfffe4b1d,0x00006278,0x000015e8, +0xffff87b6,0x0001e577,0xfffeadd6,0x0003acc2, +0xfffdda34,0x00056059,0xfffd136d,0x0006f4b5, +0x0002c562,0xfffacdc3,0x0001cfa6,0xfffc7b14, +0x0001182b,0xfffe4159,0x00005817,0x0000165c, +0xffff9417,0x0001f00f,0xfffed14c,0x0003c199, +0xfffe13f6,0x00057e83,0xfffd61cd,0x00071ba1, +0x00027ab5,0xfffab482,0x00019833,0xfffc6989, +0x0000f6ca,0xfffe38da,0x00004d9d,0x000016ef, +0xffffa103,0x0001f98f,0xfffef5c0,0x0003d3d1, +0xfffe4f00,0x0005998c,0xfffdb21e,0x00073e77, +0x00022e75,0xfffa9e9b,0x00015fd1,0xfffc5b13, +0x0000d45d,0xfffe318f,0x000042ed,0x0000176b, +0xffffae8f,0x0002018f,0xffff1a91,0x0003e40c, +0xfffe8af2,0x0005b0ca,0xfffe03b8,0x00075d14, +0x0001e141,0xfffa8bb0,0x0001262a,0xfffc4e31, +0x0000b1af,0xfffe2b26,0x00003805,0x000017b1, +0xffffbc21,0x000208b8,0xffff3fb6,0x0003f1d7, +0xfffec7af,0x0005c4c5,0xfffe5654,0x0007768a, +0x000192fe,0xfffa7bec,0x0000ec3f,0xfffc4365, +0x00008ec9,0xfffe25f0,0x00002d05,0x000017ec, +0xffffc984,0x00020ec6,0xffff658d,0x0003fcba, +0xffff0500,0x0005d576,0xfffeaa37,0x00078bc6, +0x00014367,0xfffa6fc9,0x0000b1f4,0xfffc3b82, +0x00006b06,0xfffe2201,0x000021eb,0x00001823, +0xffffd704,0x0002132a,0xffff8be7,0x00040534, +0xffff4315,0x0005e22e,0xfffeff0a,0x00079ce3, +0x0000f33f,0xfffa671b,0x000076ca,0xfffc3558, +0x00004762,0xfffe1ef3,0x000016a1,0x0000183f, +0xffffe4a6,0x00021664,0xffffb27d,0x00040b7b, +0xffff81e5,0x0005eb4e,0xffff5475,0x0007a857, +0x0000a2cb,0xfffa6218,0x00003b64,0xfffc31e2, +0x00002416,0xfffe1ce1,0x00000b46,0x00001850, +0xfffff24d,0x00021855,0xffffd93a,0x00040f75, +0xffffc0e6,0x0005f0e3,0xffffaa3e,0x0007af45, +0x0000519f,0x00030000,0x000f0007,0x003f001f, +0x00ff007f,0x03ff01ff,0x0fff07ff,0x3fff1fff, +0xffff7fff,0x00030000,0x00070005,0x000f0009, +0x003f001f,0x00ff007f,0x03ff01ff,0x0fff07ff, +0xffff1fff,0x00030000,0x00070005,0x000f0009, +0xffff001f,0x00030000,0xffff0005,0x04030504, +0x08070605,0x0c0b0a09,0x100f0e0d,0x03070504, +0x0605040a,0x0a090807,0x100d0c0b,0x03070503, +0x1005040a,0x10070502,0x03030100,0x03030303, +0x03030303,0x03030303,0x03010100,0x03030301, +0x03030303,0x03030303,0x03010100,0x03030301, +0x03010100,0x04020000,0x08070605,0x0c0b0a09, +0x100f0e0d,0x02010000,0x06050403,0x0a090807, +0x100d0c0b,0x02010000,0x10050403,0x10010000, +0x00030000,0x00090005,0x001f000f,0x007f003f, +0x01ff00ff,0x07ff03ff,0x1fff0fff,0x7fff3fff, +0x00030000,0x00090005,0x001f000f,0x007f003f, +0x0a070504,0x07060504,0x0b0a0908,0x0f0e0d0c, +0x0a070503,0x07060504,0x01010100,0x03030303, +0x03030303,0x03030303,0x01010100,0x03030303, +0x03010000,0x07060504,0x0b0a0908,0x0f0e0d0c, +0x03010000,0x07060504,0x00555555,0x002aaaab, +0x00249249,0x00124925,0x00111111,0x00088889, +0x00084210,0x00421084,0x00041041,0x00020821, +0x00020408,0x00081020,0x00010101,0x00008081, +0x00008040,0x00100804,0x00004010,0x00020080, +0x00002004,0x00004008,0x00001001,0x00000801, +0x00000800,0x00200100,0x00000400,0x00080020, +0x00000200,0x00020004,0x00200000,0x00600040, +0x00a00080,0x00e000c0,0x01200100,0x01600140, +0x01a00180,0x000001c0,0x00300020,0x00400038, +0x00600050,0x00800070,0x00c000a0,0x010000e0, +0x01800140,0x00200000,0x00300028,0x00400038, +0x00600050,0x00800070,0x00c000a0,0x010000e0, +0x00000140,0x00900000,0x00fc00d8,0x01680120, +0x01f801b0,0x02d00240,0x03f00360,0x05a00480, +0x000006c0,0x00680000,0x00b6009c,0x010500d0, +0x016d0139,0x020a01a1,0x02db0272,0x04140343, +0x000004e5,0x006c0000,0x00bd00a2,0x010e00d8, +0x017a0144,0x006301b0,0x013b00cf,0x00c601a7, +0x0000019e,0x00600000,0x00a80090,0x00f000c0, +0x01500120,0x01e00180,0x02a00240,0x03c00300, +0x00000480,0x10000000,0x10101010,0x20101010, +0x20202020,0x20202020,0x28202020,0x28282828, +0x00002828,0x10100000,0x10101010,0x10101010, +0x00000000,0x00000000,0x00000000,0x00000000, +0xcbcecdc4,0xcfcac9c8,0xc3c6c5cc,0xc7c2c1c0, +0x1b1e1d14,0x1f1a1918,0x1316151c,0x17121110, +0x2b2e2d24,0x2f2a2928,0x2326252c,0x27222120, +0x3b3e3d34,0x3f3a3938,0x3336353c,0x37323130, +0x0b0e0d04,0x0f0a0908,0x0306050c,0x07020100, +0xdbdeddd4,0xdfdad9d8,0xd3d6d5dc,0xd7d2d1d0, +0xebeeede4,0xefeae9e8,0xe3e6e5ec,0xe7e2e1e0, +0xfbfefdf4,0xfffaf9f8,0xf3f6f5fc,0xf7f2f1f0, +0x4b4e4d44,0x4f4a4948,0x4346454c,0x47424140, +0x9b9e9d94,0x9f9a9998,0x9396959c,0x97929190, +0xabaeada4,0xafaaa9a8,0xa3a6a5ac,0xa7a2a1a0, +0xbbbebdb4,0xbfbab9b8,0xb3b6b5bc,0xb7b2b1b0, +0x8b8e8d84,0x8f8a8988,0x8386858c,0x87828180, +0x5b5e5d54,0x5f5a5958,0x5356555c,0x57525150, +0x6b6e6d64,0x6f6a6968,0x6366656c,0x67626160, +0x7b7e7d74,0x7f7a7978,0x7376757c,0x77727170, +0x341424c4,0x3e1e2ece,0x3d1d2dcd,0x3b1b2bcb, +0xb494a444,0xbe9eae4e,0xbd9dad4d,0xbb9bab4b, +0xf4d4e404,0xfedeee0e,0xfddded0d,0xfbdbeb0b, +0x74546484,0x7e5e6e8e,0x7d5d6d8d,0x7b5b6b8b, +0x3c1c2ccc,0x361626c6,0x351525c5,0x331323c3, +0xbc9cac4c,0xb696a646,0xb595a545,0xb393a343, +0xfcdcec0c,0xf6d6e606,0xf5d5e505,0xf3d3e303, +0x7c5c6c8c,0x76566686,0x75556585,0x73536383, +0x381828c8,0x3a1a2aca,0x391929c9,0x3f1f2fcf, +0xb898a848,0xba9aaa4a,0xb999a949,0xbf9faf4f, +0xf8d8e808,0xfadaea0a,0xf9d9e909,0xffdfef0f, +0x78586888,0x7a5a6a8a,0x79596989,0x7f5f6f8f, +0x301020c0,0x321222c2,0x311121c1,0x371727c7, +0xb090a040,0xb292a242,0xb191a141,0xb797a747, +0xf0d0e000,0xf2d2e202,0xf1d1e101,0xf7d7e707, +0x70506080,0x72526282,0x71516181,0x77576787, +0x05040100,0x15141110,0x25242120,0x35343130, +0x85848180,0x95949190,0xa5a4a1a0,0xb5b4b1b0, +0xc0408000,0xe060a020,0xd0509010,0xf070b030, +0xc8488808,0xe868a828,0xd8589818,0xf878b838, +0xc4448404,0xe464a424,0xd4549414,0xf474b434, +0xcc4c8c0c,0xec6cac2c,0xdc5c9c1c,0xfc7cbc3c, +0xc2428202,0xe262a222,0xd2529212,0xf272b232, +0xca4a8a0a,0xea6aaa2a,0xda5a9a1a,0xfa7aba3a, +0xc6468606,0xe666a626,0xd6569616,0xf676b636, +0xce4e8e0e,0xee6eae2e,0xde5e9e1e,0xfe7ebe3e, +0xc1418101,0xe161a121,0xd1519111,0xf171b131, +0xc9498909,0xe969a929,0xd9599919,0xf979b939, +0xc5458505,0xe565a525,0xd5559515,0xf575b535, +0xcd4d8d0d,0xed6dad2d,0xdd5d9d1d,0xfd7dbd3d, +0xc3438303,0xe363a323,0xd3539313,0xf373b333, +0xcb4b8b0b,0xeb6bab2b,0xdb5b9b1b,0xfb7bbb3b, +0xc7478707,0xe767a727,0xd7579717,0xf777b737, +0xcf4f8f0f,0xef6faf2f,0xdf5f9f1f,0xff7fbf3f, +0x1045a3e2,0x000000f4,0x263b7333,0x766b2363, +0x2b367e3e,0x7b662e6e,0x06db93d3,0x964b0343, +0x0bd69ede,0x9b460e4e,0x825f1757,0x12cf87c7, +0x8f521a5a,0x1fc28aca,0x00d199d9,0x90410949, +0x01d098d8,0x91400848,0x24357d3d,0x74652d6d, +0x25347c3c,0x75642c6c,0x04d59ddd,0x94450d4d, +0x05d49cdc,0x95440c4c,0x80511959,0x10c189c9, +0x81501858,0x11c088c8,0x02df97d7,0x924f0747, +0x0fd29ada,0x9f420a4a,0x865b1353,0x16cb83c3, +0x8b561e5e,0x1bc68ece,0xa6bbf3b3,0xf6eba3e3, +0xabb6febe,0xfbe6aeee,0x223f7737,0x726f2767, +0x2f327a3a,0x7f622a6a,0xa0b1f9b9,0xf0e1a9e9, +0xa1b0f8b8,0xf1e0a8e8,0x84551d5d,0x14c58dcd, +0x85541c5c,0x15c48ccc,0xa4b5fdbd,0xf4e5aded, +0xa5b4fcbc,0xf5e4acec,0x20317939,0x70612969, +0x21307838,0x71602868,0xa2bff7b7,0xf2efa7e7, +0xafb2faba,0xffe2aaea,0x00000000,0x00000000, + +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/mpgi2s.h linux.20pre2-ac1/drivers/media/video/ls220/mpgi2s.h --- linux.20pre2/drivers/media/video/ls220/mpgi2s.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/mpgi2s.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1611 @@ +static u32 MPGI2SUcode1f1800[] = { +0x820f001f,0x802f001f,0x81df0000,0xb500000c, +0x00ffb81e,0x00000000,0x00000000,0x00000000, +0x00ffb81e,0x00000000,0x00000000,0x00000000, +0xb5000c0f,0x00000000,0x00000000,0x00000000, +0x80070800,0x001f6047,0x8013001f,0x90208000, +0x003fb174,0x803effe8,0x803effec,0x9020fa00, +0x803effd0,0x803effdc,0x803effd8,0x9020fe00, +0x803effd4,0x805bff7c,0x802500d4,0x94020080, +0xb0000000,0xb4200023,0x8013ffcf,0x9800cfff, +0x80730030,0x98631000,0x94420007,0xb0020002, +0xb4200005,0x8013ffc7,0x9800c7ff,0x80730038, +0x98631000,0xb5000006,0xb0020001,0xb4200004, +0x8013ffcf,0x9800cfff,0x80730030,0x98631000, +0x1421b800,0x1821b803,0x802600d4,0x8033001f, +0x98210000,0x802600a2,0x8033001f,0x98210300, +0x802600a3,0x80270225,0x80530001,0x98420100, +0x1821b802,0x80530200,0x98420000,0x804600a6, +0xb500001d,0x805bff7c,0x8013ffcf,0x9800cfff, +0x80730030,0x98632000,0x94420007,0xb0020002, +0xb4200005,0x8013ffc7,0x9800c7ff,0x80730038, +0x98632800,0xb5000006,0xb0020001,0xb4200004, +0x8013ffcf,0x9800cfff,0x80730030,0x98632000, +0x1421b800,0x1821b803,0x802600d4,0x8033001f, +0x98210000,0x802600a2,0x8033001f,0x98210600, +0x802600a3,0x80270eff,0x802600a1,0x80270002, +0x803eff84,0x80070000,0x801effc0,0x801effc4, +0x801effc8,0x801effcc,0x801eff88,0x80770000, +0x8057ffff,0x80170080,0x80070000,0xb6003f02, +0xb6002001,0x001fa020,0x8007ffff,0x801eff84, +0x80070001,0x001f25dc,0x001f20b1,0x80070000, +0x001f6046,0x001fb17c,0x001fb17d,0x80070000, +0x801e78d0,0x98004000,0x001f62ea,0x80070100, +0x801efff0,0x81df0004,0x00000000,0x00000000, +0x801bfff0,0x00000000,0x940000ff,0xb0000000, +0xb420005b,0x003f42ea,0x94010010,0xb0000000, +0xb400fff7,0x003f05dc,0xb0010001,0xb4200034, +0x803bffe8,0x801bffec,0x00000000,0x3001b800, +0xb4600001,0x90214000,0x0421b800,0xb0010800, +0xb460000d,0x80050086,0x005f902e,0xb0020000, +0xb4200002,0x001fb02e,0xb5000006,0x0420b802, +0xb0010930,0xb4a0ffe2,0x80070000,0x001fb02e, +0x83e40162,0xb500ffde,0x83e40129,0x80070000, +0x001fb02e,0x001f42ea,0x9400000f,0xb0000000, +0xb4000010,0x9400fff0,0x001f62ea,0x003f9174, +0x9421ffff,0x90210004,0xb001c000,0xb4800002, +0x8421c000,0x90218000,0x8013001f,0x1821b800, +0x003fb174,0x003f917c,0x90210004,0x003fb17c, +0x83e4014a,0x8013001f,0x83e71b0c,0x1bffb800, +0x003f9179,0x1821b800,0x00ffb801,0xb5000008, +0x80270000,0x003f25dc,0x8013001f,0x83e71b30, +0x1bffb800,0x003f917a,0x1821b800,0x00ffb801, +0x80070000,0x001f20b1,0x001f42ea,0x9420000f, +0xb0010000,0xb4200003,0x98000800,0x001f62ea, +0xb500ffaf,0x9400fff0,0x001f62ea,0x80270000, +0x8057ffff,0x80770000,0x80171980,0x81df0000, +0x00000000,0x00000000,0xb6000602,0xb6002001, +0x001fa021,0x81df0004,0xb500ffa1,0xb500ffa0, +0x803bffc0,0x805bffc4,0x807bffc8,0x809bffcc, +0x5828b801,0x5cb8b802,0x1821b805,0x5848b802, +0x5cb8b803,0x1842b805,0x5868b803,0x5cb8b804, +0x1863b805,0x5888b804,0x1884b800,0x803effc0, +0x805effc4,0x807effc8,0x809effcc,0x003f42ea, +0xb0000086,0xb4400079,0xb0000084,0xb4000049, +0xb0000085,0xb4000063,0xb0000086,0xb400006c, +0xb0000081,0xb4000005,0xb0000082,0xb4000003, +0xb0000080,0xb4000001,0xb5000069,0x8013007f, +0x9800ffff,0x001fb02d,0x80070000,0x001fb17c, +0x8013001f,0x9040fa00,0x805effd0,0x805effdc, +0x805effd8,0x9040fe00,0x805effd4,0x9040c000, +0x805effe4,0x90008000,0x801effe0,0x001fb174, +0x801effe8,0x801effec,0x80078000,0x801e78d4, +0x80070000,0x001fb17c,0x001fb17d,0x001fb02e, +0x83e400e6,0x8013001f,0x98000000,0x800600a2, +0x8013001f,0x98000600,0x800600a3,0x805bff7c, +0x80070eff,0x94420080,0xb0020080,0xb420000d, +0x8013001f,0x98000000,0x800600a2,0x8013001f, +0x98000300,0x800600a3,0x80070225,0x80530001, +0x98420100,0x1800b802,0x80530200,0x98420000, +0x804600a6,0x800600a1,0x80050080,0x98000022, +0x80060080,0x80072080,0x001fb179,0x80074618, +0x001fb17a,0x80070001,0x001f25dc,0x98214000, +0xb5000029,0x8047ffff,0x805eff84,0x805bff88, +0x00000000,0xb0020001,0xb4200002,0x80470000, +0x805eff88,0x805bff7c,0x80070eff,0x94420080, +0xb0020080,0xb4200007,0x80070225,0x80530001, +0x98420100,0x1800b802,0x80530200,0x98420000, +0x804600a6,0x800600a1,0x80070001,0x800600a0, +0x9421efff,0x98210010,0xb500000f,0x80070000, +0x001fb17c,0x80070001,0x001f25dc,0x83e400a3, +0x80050081,0x80330008,0x98210000,0x1800b801, +0x80060081,0x003f42ea,0x9421ffef,0xb5000002, +0x98211000,0x9421ffef,0x83e40098,0x003f62ea, +0x80070100,0x801efff0,0xb500ff11,0xb000008b, +0xb400001c,0xb0000087,0xb400ffe8,0xb0000088, +0xb4000023,0xb000008a,0xb4000024,0xb000008c, +0xb4000019,0xb000008e,0xb4000014,0xb000008d, +0xb400001d,0xb0000089,0xb400001f,0xb00000a0, +0xb4000021,0xb00000a1,0xb4000022,0xb00000a2, +0xb400002f,0xb00000a3,0xb4000027,0xb00000a4, +0xb4000031,0xb00000a5,0xb4000035,0xb00000a6, +0xb4000039,0x803efff8,0xb500ffdd,0x80070000, +0x001fb17e,0xb500ffda,0x803bffb0,0x00000000, +0x003fb02d,0xb500ffd6,0x98210020,0xb500ffd2, +0x9421ffdf,0xb500ffd0,0xb500ffd1,0x80270351, +0x803efff8,0xb500ffce,0x803bff80,0x00000000, +0x003f62ef,0xb500ffca,0x003f917b,0x803efff8, +0xb500ffc7,0x80270000,0x8047fef0,0x003eb802, +0x90420004,0x003eb802,0x90420004,0x003eb802, +0x90420004,0x003eb802,0x81df0000,0x00000000, +0x00000000,0x83640db9,0x81df0004,0xb500ffb8, +0x81df0000,0x00000000,0x00000000,0x83640d63, +0x81df0004,0xb500ffb2,0x81df0000,0x00000000, +0x00000000,0x83640d1e,0x81df0004,0xb500ffac, +0x81df0000,0x00000000,0x00000000,0x83440c81, +0x81df0004,0xb500ffa6,0x81df0000,0x00000000, +0x00000000,0x83440c66,0x81df0004,0xb500ffa0, +0x817bffe8,0x815b78d4,0x00000000,0x956bffff, +0x300bb80a,0xb4600001,0x916b4000,0x056bb80a, +0xb00b0080,0xb4a0002a,0x80af001f,0x808f0000, +0x806f0000,0x81b300ff,0x8057ffff,0x5d67b80b, +0x5d42b80a,0x81df0000,0x00000000,0x00000000, +0xb62b001c,0xb00a3000,0xb4800001,0x854a1000, +0x80cf0400,0x015fb178,0x5942b80a,0x01cfb80a, +0x015f9178,0xb520ffff,0x80171000,0xb600200a, +0x01ff8000,0x5a18b80f,0x5a28b80f,0x1631b80d, +0x5e48b80f,0x9652ff00,0x5e78b80f,0x1a73b810, +0x1a73b811,0x1813a032,0x80cf0400,0x015fb178, +0x5942b80a,0x01afb80a,0x015f9178,0xb520ffff, +0x914a0020,0x81df0004,0x5942b80a,0x815e78d4, +0x00000000,0x00000000,0x00ffb81f,0x81df0000, +0x80070000,0x80470000,0x81171800,0xb6002003, +0xb6003002,0x001eb802,0x90420004,0xb6002003, +0x011fa020,0x011fa020,0x011fa020,0x81df0004, +0x00ffb81f,0x80070000,0x80478000,0x81df0000, +0x00000000,0x00000000,0xb6002003,0xb6008002, +0x001eb802,0x90420004,0x81df0004,0x00ffb81f, +0x015f42ea,0x944a4000,0xb0024000,0xb4200081, +0x954abfff,0x015f62ea,0x808f0000,0x80ef007c, +0x80171000,0x80971400,0x80270000,0xb6001003, +0xb6002002,0x001fa021,0x009fa021,0x80a76604, +0x80271400,0x81df0000,0x00000000,0x00000000, +0xb6001004,0x01efb801,0x01afb805,0xb520ffff, +0x90a50080,0x81df0004,0x80a76e04,0x80271400, +0x81df0000,0x00000000,0x00000000,0xb6001004, +0x01efb801,0x01afb805,0xb520ffff,0x90a50080, +0x81df0004,0x806f001f,0x80af001f,0x80276400, +0x5c22b801,0x806701e1,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x80275c00,0x5c22b801, +0x80670200,0x81df0000,0x00000000,0x00000000, +0xb600100a,0x00cfb803,0x003fb178,0x5822b801, +0x01cfb801,0x003f9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x90210020,0x90630020,0x81df0004, +0x808f0000,0x806f001f,0x80af001f,0x8027647c, +0x5c22b801,0x8067017e,0x81df0000,0x00000000, +0x00000000,0xb600020a,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90210020,0x90630020, +0x81df0004,0x806f0010,0x80af0010,0x8027657c, +0x5c22b801,0x806701be,0x00cfb803,0x003fb178, +0x5822b801,0x01cfb801,0x003f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x802765c0,0x5c22b801, +0x806701cf,0x00cfb803,0x003fb178,0x5822b801, +0x01cfb801,0x003f9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x80276000,0x005fb801,0x8033001f, +0x98218000,0x803effe0,0x90214000,0x803effe4, +0x8193001f,0x998c8000,0x019fb174,0x83270000, +0x003fb819,0x003f9174,0x5823b801,0x83338000, +0x1b39b801,0x003fb819,0x00000000,0x00000000, +0x81550000,0x0187b860,0x858c0040,0x81b380fc, +0x99ad0000,0x300cb80d,0xb4600003,0x81b30002, +0x99ad0000,0x118cb80d,0x003fb80c,0x00000000, +0x00000000,0x81550000,0x8257ffff,0x82d7ffff, +0x8357ffff,0x81672000,0x83440191,0xb00a0001, +0xb4000141,0x0187b860,0x858c0010,0x5988b80c, +0x5d8bb80c,0x958cffff,0xb00cc000,0xb4800002, +0x858cc000,0x918c8000,0x81b3001f,0x198cb80d, +0x801bffec,0x00000000,0x819effec,0x819e78d8, +0x019fb174,0x05acb800,0x300cb800,0xb4600001, +0x91ad4000,0x001f917c,0x1000b80d,0x001fb17c, +0x8344019c,0xb00a0000,0xb4200127,0x015f0081, +0xb00a0002,0xb4200124,0x037f0082,0xb01b0000, +0xb400001e,0x0367b860,0x5b68b81b,0x5f68b81b, +0x017f4047,0x916b0010,0x5963b80b,0x83440168, +0x801bff84,0xb00a0001,0xb400000b,0xb00b00c0, +0xb460fffa,0x803f0000,0x80138000,0x1b7bb800, +0x003fb81b,0x00000000,0x00000000,0x80150000, +0x801bff84,0xb5000009,0x803f0000,0x80138000, +0x1b7bb800,0x003fb81b,0x00000000,0x00000000, +0x80150000,0x801bff84,0xb5000103,0x801bff84, +0x003f0084,0x3000b801,0x803eff84,0xb4000073, +0x801bff7c,0x00000000,0x94800080,0xb0040080, +0xb4200036,0x94800007,0x80730200,0xb0010002, +0xb420000e,0x80270265,0xb0040001,0xb4200003, +0x80130030,0x98000000,0xb5000006,0x80130030, +0x98000000,0xb0040000,0xb4000002,0x80130038, +0x98000000,0x98630060,0xb500001f,0xb0010000, +0xb420000e,0x80270225,0xb0040001,0xb4200003, +0x80130030,0x98001000,0xb5000006,0x80130030, +0x98001000,0xb0040000,0xb4000002,0x80130038, +0x98001000,0x98630000,0xb500000f,0xb0010001, +0xb420004a,0x80270225,0xb0040001,0xb4200003, +0x80130030,0x98002000,0xb5000006,0x80130030, +0x98000000,0xb0040000,0xb4000002,0x80130038, +0x98000000,0x98630040,0x806600a6,0x80530001, +0x98420100,0x1821b802,0xb500002d,0x94800007, +0xb0010002,0xb420000d,0x80270eff,0xb0040001, +0xb4200003,0x80130030,0x98002000,0xb5000006, +0x80130030,0x98000000,0xb0040000,0xb4000002, +0x80130038,0x98000000,0xb500001d,0xb0010000, +0xb420000d,0x80270eff,0xb0040001,0xb4200003, +0x80130030,0x98002000,0xb5000006,0x80130030, +0x98002000,0xb0040000,0xb4000002,0x80130038, +0x98002800,0xb500000e,0xb0010001,0xb4200017, +0x80270eff,0xb0040001,0xb4200003,0x80130030, +0x98002000,0xb5000006,0x80130030,0x98002000, +0xb0040000,0xb4000002,0x80130038,0x98002800, +0x806500d4,0x8053ffcf,0x9842cfff,0xb0040002, +0xb4200002,0x8053ffc7,0x9842c7ff,0x802600a1, +0x1463b802,0x1863b800,0x806600d4,0x807bff7c, +0x00000000,0x94630080,0xb0030080,0xb420000b, +0x807bff88,0x00000000,0xb0030001,0xb4000007, +0x802500a1,0x80670001,0x807eff88,0x80530001, +0x98420100,0x1821b802,0x802600a1,0x81070000, +0x011f62e2,0x011f62e3,0x011f0082,0xb0080000, +0xb4200004,0x81150010,0x00000000,0x00000000, +0x011f62de,0x011f0081,0xb0080001,0xb4200026, +0x81070020,0x011f25c1,0x81070180,0x011f62e1, +0x8344023e,0x8344026a,0x011f0082,0xb0080000, +0xb4200004,0x834401bd,0x834401aa,0xb00a0000, +0xb4200061,0x80c70000,0x00df25cb,0x83440281, +0x8344064f,0x02ff05b9,0x82a70000,0x82870000, +0x83440407,0x92940001,0x3014b817,0xb480fffc, +0x834406ef,0x80270000,0x003f25dc,0x834407de, +0x003f05dc,0xb0010001,0xb4000003,0x80272694, +0x003fb17a,0x00ffb81f,0x80d3001f,0x8347266c, +0x1b5ab806,0xb500002d,0xb0080002,0x81470004, +0xb4200045,0x81070008,0x011f25c1,0x81070480, +0x011f62e1,0x8344029e,0x834402dc,0x011f0082, +0xb0080000,0xb4200004,0x834401aa,0x83440181, +0xb00a0000,0xb4200038,0x80c70000,0x00df25cb, +0x83440368,0x02df05cb,0x5ec2b816,0x8344066b, +0x02ff05b9,0x82a70000,0x82870000,0x834403dc, +0x92940001,0x3014b817,0xb480fffc,0x92b50001, +0xb0150003,0xb480fff8,0x834406c1,0x80270000, +0x003f25dc,0x834407b0,0x003f05dc,0xb0010001, +0xb4000003,0x8027274c,0x003fb17a,0x00ffb81f, +0x80d3001f,0x83472710,0x1b5ab806,0x80db78d8, +0x80fbffec,0x00000000,0x3006b807,0xb4200007, +0x00df05cb,0x90c60001,0x00df25cb,0xb006000c, +0xb4000002,0x035fb179,0x00ffb81f,0x80c70000, +0x00df25cb,0x80fb78dc,0x00000000,0x90e70001, +0xb00701b9,0xb4a00001,0x80e70001,0x80fe78dc, +0xb500feb0,0x802500a5,0x8153001f,0x3001b80a, +0xb420fffc,0x00ffb81f,0x001f42ea,0x1800b80a, +0x001f62ea,0x017f4047,0x5963b80b,0x0187b860, +0x118cb80b,0x81b380fe,0x99ad0000,0x300cb80d, +0xb4800003,0x81b30002,0x99ad0000,0x058cb80d, +0x003fb80c,0x00000000,0x00000000,0x81550000, +0x0187b860,0x5988b80c,0x5d8bb80c,0x958cffff, +0xb00cc000,0xb4800002,0x858cc000,0x918c8000, +0x81b3001f,0x198cb80d,0x801bffec,0x00000000, +0x819effec,0x019fb174,0x05acb800,0x300cb800, +0xb4600001,0x91ad4000,0x001f917c,0x1000b80d, +0x001fb17c,0x80171000,0x80971400,0x80270000, +0xb6001003,0xb6002002,0x001fa021,0x009fa021, +0x80171800,0xb6000602,0xb6002001,0x001fa021, +0x806f001f,0x80af001f,0x80a76604,0x80271400, +0x81df0000,0x00000000,0x00000000,0xb6001004, +0x01efb801,0x01afb805,0xb520ffff,0x90a50080, +0x81df0004,0x80a76e04,0x80271400,0x81df0000, +0x00000000,0x00000000,0xb6001004,0x01efb801, +0x01afb805,0xb520ffff,0x90a50080,0x81df0004, +0x81472080,0x015fb179,0x00ffb81f,0x00000000, +0x811be024,0x0107b860,0x95080007,0xb0080000, +0xb4000004,0xa5080008,0x00000000,0x0155b808, +0x00000000,0x8115000c,0x856b000c,0xb0080fff, +0xb400000b,0x81550004,0x856b0004,0x5904b808, +0x1908b80a,0x95080fff,0xb0080fff,0xb4000004, +0x81470001,0xb00b0020,0xb440fff6,0xb500000c, +0x81d50004,0x856b0004,0x00000000,0xb00e000f, +0xb400fffb,0x940b0007,0xb0000000,0xb420ffed, +0x001f42ea,0x9400fffe,0x81470000,0x001f62ea, +0x00ffb81a,0x950e0008,0x5d03b808,0x00000000, +0xb0080000,0xb40000cd,0x011f2080,0x950e0006, +0x5d01b808,0x81270004,0x0529b808,0x950e0001, +0x013f2081,0x011f2082,0x81150004,0x00000000, +0xb0080000,0xb40000c1,0xb008000f,0xb40000bf, +0x011f2083,0x81150002,0x00000000,0x81670004, +0xb0080002,0xb46000b9,0x011f2084,0x013f0081, +0xb0090002,0xb4200011,0x013f0083,0xb0080000, +0xb4200002,0x81077844,0xb5000005,0xb0080001, +0xb4200002,0x81077884,0xb5000001,0x81077824, +0x013f0083,0x5921b809,0x1129b808,0x0119b809, +0x00000000,0x00000000,0x011f6047,0x81150001, +0x00000000,0x011f2085,0x81150001,0x00000000, +0x011f2086,0x81350002,0x00000000,0x013f2087, +0x81150002,0x00000000,0x011f2088,0x81150001, +0x00000000,0x011f2089,0x81150001,0x00000000, +0x011f208a,0x81150002,0x00000000,0x011f208b, +0x81070001,0xb0090003,0xb4000001,0x81070002, +0x011f25b9,0x81070020,0x013f0081,0xb0090002, +0xb4200069,0x85290001,0xad29000f,0x00000000, +0x011f0083,0x1108b809,0x5901b808,0x910877c8, +0x0139b808,0x011f05b9,0x85080001,0x6928b809, +0x011f0084,0xb0090038,0xb4800007,0xb0080001, +0xb4000002,0xb0090050,0xb4400003,0x81270000, +0x8107001b,0xb5000010,0xb0080001,0xb4000005, +0xb0090060,0xb4800003,0x81270001,0x8107001e, +0xb5000009,0xb0080002,0xb4000005,0xb0090030, +0xb4400003,0x81270002,0x81070008,0xb5000002, +0x81270003,0x8107000c,0x011f25bb,0x013f25c0, +0xb0090002,0xb460001b,0x80477604,0x5c42b802, +0x814fffc0,0x80cf0037,0x005fb178,0x5842b802, +0x01cfb802,0x005f9178,0xb520ffff,0x90420020, +0x814fb580,0x80cf0057,0x005fb178,0x5842b802, +0x01cfb802,0x005f9178,0xb520ffff,0x804778a4, +0x5c42b802,0x814f39c0,0x80cf002f,0x005fb178, +0x5842b802,0x01cfb802,0x005f9178,0xb520ffff, +0xb5000025,0x804776e0,0x5c42b802,0x814fef40, +0x80cf0037,0x005fb178,0x5842b802,0x01cfb802, +0x005f9178,0xb520ffff,0x8297013c,0x8317018c, +0x81df0000,0x00000000,0x00000000,0xb6000602, +0x005f8034,0x031fa022,0x82970124,0x83170160, +0xb6000602,0x005f8034,0x031fa022,0x8297010c, +0x83170134,0xb6000602,0x005f8034,0x031fa022, +0x81df0004,0x804778c4,0x5c42b802,0x814f1080, +0x80cf002f,0x005fb178,0x5842b802,0x01cfb802, +0x005f9178,0xb520ffff,0x013f0081,0xb0090001, +0xb420000e,0x808f0000,0x806f001b,0x80af001b, +0x80277758,0x5c22b801,0x80670037,0x00cfb803, +0x003fb178,0x5822b801,0x01cfb801,0x003f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x011f25bb, +0x011f0087,0xb0080001,0xb4000002,0x011f05bb, +0xb5000003,0x011f0088,0x91080001,0x5902b808, +0x011f25ba,0x81470000,0x00ffb81a,0x81470008, +0x00ffb81a,0x81270000,0x81470000,0x300842de, +0xb400000b,0x013f42e2,0x91290001,0x013f62e2, +0x013f42e3,0x91290001,0x013f62e3,0x83640006, +0x00000000,0x00000000,0x013f42e2,0x81470002, +0x013f62e2,0x00ffb81a,0x00ffb81b,0x83640049, +0x80c70004,0x80270000,0x81df0000,0x00000000, +0x00000000,0xb600200d,0x00ff05b9,0x5c42b801, +0x300205ba,0xb4800001,0x80e70001,0x80470000, +0xb6270005,0x1062b801,0x914301b8,0x00fff00a, +0x83840055,0x90420080,0x90210004,0x81df0004, +0x00ffb81a,0x83640033,0x017f05bb,0x800700bc, +0x80270000,0x81df0000,0xb00b0000,0xb4000015, +0xb62b0014,0x00ff05b9,0x5c42b801,0x300205ba, +0xb4800001,0x80e70001,0x80470000,0xb0070000, +0xb400000b,0xb627000a,0x1062b801,0x914301b8, +0x00fff00a,0x5c62b801,0x1063b800,0x00bff003, +0x90650134,0x00dff003,0x83840037,0x90420080, +0x90210004,0x81df0004,0x019f05b9,0x80c70002, +0x80270000,0x81df0000,0xb00b0000,0xb400000f, +0xb62b000e,0x80470000,0xb00c0000,0xb400000a, +0xb62c0009,0x1062b801,0x914301b8,0x00fff00a, +0xb0070000,0xb4000003,0x906302b8,0x00fff003, +0x83840021,0x90420080,0x90210004,0x81df0004, +0x00ffb81a,0x8107ffff,0x80c70004,0x00ff0083, +0x83840019,0x80c70002,0x00ff0084,0x83840016, +0x80c70001,0x00ff0085,0x83840013,0x80c70001, +0x00ff0086,0x83840010,0x80c70002,0x00ff0087, +0x8384000d,0x80c70002,0x00ff0088,0x8384000a, +0x80c70001,0x00ff0089,0x83840007,0x80c70001, +0x00ff008a,0x83840004,0x80c70002,0x00ff008b, +0x83840001,0x00ffb81b,0x80a70001,0x64a6b805, +0x5ca1b805,0xb0050000,0xb400000e,0x95288000, +0xb0090000,0xb4000001,0x81270001,0x5901b808, +0x1547b805,0xb00a0000,0xb4000001,0x81470001, +0x2129b80a,0xb0090000,0xb4000001,0xa1088005, +0xb500ffef,0x9508ffff,0x00ffb81c,0x015f05ba, +0x013f05b9,0x800700bc,0xb0090000,0xb4000012, +0xb00a0000,0xb4000010,0x80270000,0x81df0000, +0x00000000,0x00000000,0xb62a000b,0x80470000, +0xb6290008,0x80950004,0x5865b802,0x1063b801, +0x5862b803,0x906301b8,0x0217b803,0x90420001, +0x021fa004,0x90210001,0x81df0004,0xa54a0020, +0xb4c00011,0xb0090000,0xb400000f,0x81df0000, +0x00000000,0x00000000,0xb62a000b,0x80950004, +0x80470000,0xb6290007,0x5865b802,0x1063b801, +0x5862b803,0x906301b8,0x0217b803,0x90420001, +0x021fa004,0x90210001,0x81df0004,0x00ffb81a, +0x013f05b9,0xb0090000,0xb400001c,0x80270000, +0x81df0000,0x00000000,0x00000000,0xb6002017, +0x80470000,0xb6290014,0x5865b802,0x1063b801, +0x5862b803,0x914301b8,0x009ff00a,0xad420060, +0x00000000,0x114ab801,0x5942b80a,0x914a1c80, +0x0217b80a,0xb0040000,0xb4000004,0x80950006, +0x00000000,0x021fa004,0xb5000002,0x8087003f, +0x021fa004,0x90420001,0x90210001,0x81df0004, +0x00ffb81a,0x8257ffff,0x82d7ffff,0x011f05ba, +0x013f05b9,0x80270000,0xb0090000,0xb4000033, +0x81df0000,0x00000000,0x00000000,0xb6280015, +0x80470000,0xb6290012,0x5865b802,0x1063b801, +0x5862b803,0x914301b8,0xaca20060,0x009ff00a, +0x10a5b801,0x58a2b805,0x90a502b8,0x0217b805, +0x80670000,0xb0040000,0xb4000003,0x90840001, +0x0075b804,0x00000000,0x021fa003,0x90420001, +0x90210001,0x81df0004,0xa5480020,0xb4000017, +0x5822b801,0x81df0000,0x00000000,0x00000000, +0xb62a0011,0x914101b8,0x90a102b8,0x0217b805, +0x009ff00a,0xb0040000,0x80670000,0xb4000002, +0x90840001,0x0075b804,0xb6290006,0x021fa203, +0x009f8210,0x009f8210,0x009f8210,0x009f8210, +0x009f8210,0x90210004,0x81df0004,0x00ffb81a, +0x015f05ba,0x013f05b9,0x800700bc,0xb0090000, +0xb4000016,0xb00a0000,0xb4000014,0x80270000, +0x81df0000,0x00000000,0x00000000,0xb62a000f, +0x80470000,0xb629000c,0x1080b801,0x007ff004, +0x90830134,0x007ff004,0x0095b803,0x5865b802, +0x1063b801,0x5862b803,0x906301b8,0x0217b803, +0x90420001,0x021fa004,0x90210001,0x011f05bb, +0x254ab808,0xb4c0000d,0xb62a000c,0x1080b801, +0x007ff004,0x90830134,0x007ff004,0x0095b803, +0x5862b801,0x906301b8,0x0217b803,0x90210001, +0x021fa204,0x007f8210,0x021fa004,0xa5480020, +0xb4c0000e,0xb0090000,0xb400000c,0x80870000, +0xb62a000a,0x80470000,0xb6290007,0x5865b802, +0x1063b801,0x5862b803,0x906301b8,0x0217b803, +0x90420001,0x021fa004,0x90210001,0x81df0004, +0x00000000,0x00000000,0x00ffb81a,0x011f05bb, +0x013f05b9,0xb0080000,0xb4000016,0xb0090000, +0xb4000014,0x81df0000,0x00000000,0x80270000, +0xb6280010,0x80470000,0xb629000d,0x5865b802, +0x1063b801,0x5862b803,0x914301b8,0x009ff00a, +0xb0040000,0xb4000005,0x80950002,0x906302b8, +0x0217b803,0x00000000,0x021fa004,0x90420001, +0x90210001,0x81df0004,0xa5480020,0xb00a0000, +0xb4000011,0xb0090000,0xb400000f,0x81df0000, +0x00000000,0x80870000,0xb62a000b,0x80470000, +0xb6290008,0x5865b802,0x1063b801,0x5862b803, +0x906302b8,0x0217b803,0x00000000,0x021fa004, +0x90420001,0x90210001,0x81df0004,0xb0080000, +0xb400004d,0xb0090000,0xb400004b,0x81df0000, +0x00000000,0x80270000,0xb6280047,0x80470000, +0xb6290044,0x5865b802,0x1063b801,0x5862b803, +0x914301b8,0x009ff00a,0xad420060,0x00000000, +0x00000000,0x00000000,0x114ab801,0x5942b80a, +0x914a1c80,0x0217b80a,0xb0040000,0xb400002e, +0x906302b8,0x009ff003,0xb0040000,0xb420000a, +0x80950006,0x00000000,0x021fa204,0x80950006, +0x015f8210,0x021fa204,0x80950006,0x015f8210, +0x021fa004,0xb5000026,0xb0040001,0xb4200009, +0x80950006,0x00000000,0x021fa204,0x015f8210, +0x021fa204,0x80950006,0x015f8210,0x021fa004, +0xb500001b,0xb0040003,0xb4200009,0x80950006, +0x00000000,0x021fa204,0x80950006,0x015f8210, +0x021fa204,0x015f8210,0x021fa004,0xb5000010, +0xb0040002,0xb420000e,0x80950006,0x00000000, +0x021fa204,0x015f8210,0x021fa204,0x015f8210, +0x021fa004,0xb5000006,0x8087003f,0x021fa204, +0x015f8210,0x021fa204,0x015f8210,0x021fa004, +0x90420001,0x90210001,0x81df0004,0xa5480020, +0xb4c00012,0xb0090000,0xb4000010,0x8087003f, +0x81df0000,0x5862b801,0x90631afc,0xb62a000b, +0x90630004,0x0047b803,0xb6290008,0x90420180, +0x0217b802,0x00000000,0x021fa204,0x003f8210, +0x021fa204,0x003f8210,0x021fa004,0x81df0004, +0x00ffb81a,0x8257ffff,0x82d7ffff,0x011f05bb, +0x013f05b9,0x80270000,0x00e7b809,0x300105ba, +0xb4800001,0x80e70001,0x800700bc,0x80470000, +0x81df0000,0xb0070000,0xb400004c,0xb627004b, +0x5865b802,0x1063b801,0x5862b803,0x914301b8, +0xaca20060,0x009ff00a,0x10a5b801,0x58a2b805, +0x90a502b8,0x0217b805,0xb0040000,0xb400002b, +0x1060b801,0x00bff003,0x10a5b804,0x90650160, +0x00dff003,0xb0060003,0xb4200007,0x90650134, +0x00dff003,0xb6000303,0x0075b806,0x021fa203, +0x007f8210,0xb5000021,0x5861b805,0x906300dc, +0x009fd803,0x90650134,0x00dff003,0xaca20060, +0x00000000,0x00000000,0x00000000,0x0075b806, +0x10a5b801,0x58a2b805,0x90a502b8,0x0217b805, +0x588fb804,0xb600030c,0xb6001007,0x04a3b804, +0xb4600002,0x58a1b803,0xb5000002,0x58a1b805, +0x90a50001,0x0067b805,0x9465ffff,0x5d50b805, +0x021fa20a,0x015f8210,0xb5000004,0x81470000, +0xb6000302,0x021fa20a,0x009f8210,0x009f05b9, +0xb0040002,0xb420000c,0x300105ba,0xb480000a, +0x58a2b801,0x90a502b8,0x0217b805,0x90a50180, +0x0297b805,0xb6000304,0x00bf8210,0x009f8210, +0x029fa205,0x009f8214,0x90420001,0x81df0004, +0x90210001,0x3001b808,0xb480ffa7,0xa5480020, +0xb00a0000,0xb4000019,0xb0090000,0xb4000017, +0x58a2b801,0x90a502b8,0x81df0000,0x00000000, +0x00000000,0xb62a0010,0x80470000,0xb629000d, +0xaca20060,0x00000000,0x00000000,0x00000000, +0x80670000,0x10a5b801,0x58a2b805,0x90a502b8, +0x0217b805,0xb6000302,0x021fa203,0x00bf8210, +0x90420001,0x90210001,0x81df0004,0x00ffb81a, +0x80770000,0x8057ffff,0x80f70000,0x80d7ffff, +0x81770000,0x8157ffff,0x81f70000,0x81d7ffff, +0xac140060,0xac350020,0x00000000,0x00000000, +0x12c0b801,0x5ac2b816,0x92d61980,0x83a400bd, +0xad940400,0x009f9173,0x013f05ca,0x914c6604, +0x114ab804,0x001f97e0,0x001eb80a,0xb0090000, +0xb4000003,0x80a76e44,0x80c76644,0xb5000002, +0x80a76644,0x80c76e44,0x808f000f,0x806f0000, +0x80af000e,0x80cf07e1,0x11e5b80c,0x11efb804, +0x5de2b80f,0x01ffb178,0x59e2b80f,0x01afb80f, +0x01ff9178,0x0047b86f,0xb0020001,0xb4c0fffd, +0x80cf07f0,0x1206b80c,0x1210b804,0x5e02b810, +0x021fb178,0x5a02b810,0x01afb810,0x021f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x916c6e04, +0x116bb804,0x001f97ff,0x001eb80b,0x808f0000, +0x806f001f,0x80af001f,0x90ac6604,0x5ca2b805, +0x80270400,0x81df0000,0x00000000,0x00000000, +0xb600080a,0x00cfb801,0x00bfb178,0x58a2b805, +0x01cfb805,0x00bf9178,0x0047b86f,0xb0020001, +0xb4c0fffd,0x90210020,0x90a50020,0x81df0004, +0x90ac6e04,0x5ca2b805,0x80270500,0x81df0000, +0x00000000,0x00000000,0xb600080a,0x00cfb801, +0x00bfb178,0x58a2b805,0x01cfb805,0x00bf9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x90210020, +0x90a50020,0x81df0004,0x81530020,0xac140060, +0xac350020,0x80170800,0x80d7003c,0x12c0b801, +0x5ac2b816,0x92d602b8,0x0117b816,0x90241000, +0x0097b801,0x80470000,0x4002b803,0x81df0000, +0x00000000,0x00000000,0xb6000804,0x005f8020, +0x480287e4,0x005f8020,0x500287e4,0x81df0004, +0x00000000,0x00000000,0x00000000,0x1021b80a, +0x5c36b801,0x5801b800,0x18c0b801,0xb0090000, +0xb4000002,0x90641440,0xb5000001,0x90641040, +0x81df0000,0x00000000,0x00000000,0xb6000f0d, +0x0097b803,0x80470000,0x4002b803,0xb6001002, +0x005f8020,0x480287e4,0x0108a026,0x90630040, +0x00000000,0x1021b80a,0x5c36b801,0x5801b800, +0x18c0b801,0x81df0004,0x90641400,0x0097b803, +0x80470000,0x4002b803,0x005f8020,0x005f87e4, +0x81df0000,0x00000000,0x00000000,0xb6000802, +0x005f8040,0x480287c4,0x81df0004,0x005f87e0, +0x0108a026,0x00000000,0x1021b80a,0x5c36b801, +0x5801b800,0x18c0b801,0xb0090000,0xb4000002, +0x906417c0,0xb5000001,0x906413c0,0x81df0000, +0x00000000,0x00000000,0xb6000f0f,0x0097b803, +0x80470000,0x4002b803,0xb6000804,0x005f8020, +0x500287e4,0x005f8020,0x480287e4,0x0108a026, +0x84630040,0x00000000,0x1021b80a,0x5c36b801, +0x5801b800,0x18c0b801,0x81df0004,0xb0140000, +0xb4200005,0x90840004,0x9484003f,0x009fb173, +0xa1290001,0x013f25ca,0x80d7ffff,0x0108a026, +0x00ffb81a,0x81330004,0x8093007f,0x9884ffff, +0x80b3ff80,0x0017b816,0x90360040,0x0097b801, +0x81530010,0x81df0000,0x00000000,0x00000000, +0xb6001004,0x400a8000,0x404a8004,0x0008a020, +0x0088a022,0x81df0004,0x0017b816,0x9036007c, +0x0097b801,0x81171000,0x81df0000,0x00000000, +0x00000000,0xb6001004,0x40048020,0x480487e4, +0x00000000,0x0108a020,0x81df0004,0x81470000, +0x81670001,0x81870008,0x81a70040,0x81c707c4, +0x81e70040,0x81df0000,0x00000000,0x00000000, +0xb6000432,0xb00a0001,0xb4e00004,0x80c71000, +0x80e71000,0x81171040,0xb5000003,0x80c71040, +0x80e71040,0x81171000,0x844d0004,0x10e7b802, +0xb62b001f,0x0017b806,0x0097b807,0xb62c0004, +0x40048020,0x480487e4,0x00000000,0x0108a020, +0x0017b806,0x0097b807,0x0197b80e,0x00000000, +0x001f8020,0x042087e4,0xb62c000f,0x4041800c, +0x001f8020,0x0048b802,0x5e38802c,0x2e11b801, +0x042087e4,0x1042b810,0x0462b804,0xb4a00002, +0x0047b804,0xb5000003,0x0462b805,0xb4600001, +0x0047b805,0x011fa022,0x10c6b80f,0x10e7b80f, +0x5961b80b,0x5d81b80c,0x5da1b80d,0x5de1b80f, +0x914a0001,0x954a0001,0x11ceb80f,0x81df0004, +0x80171018,0x81171fcc,0x80470000,0x41448020, +0x494487c0,0x00000000,0x0188b80a,0x494487e0, +0x00000000,0x0148b80a,0x0502a10a,0x4145b80c, +0x494580e0,0x00000000,0x0108a5ea,0x41448080, +0x494487c0,0x00000000,0x0108a78a,0x49448020, +0x00000000,0x0108a2ea,0x41448020,0x49448720, +0x00000000,0x0188b80a,0x4145b80c,0x49458080, +0x494587a0,0x00000000,0x0108a68a,0x4145b80c, +0x49458080,0x494587a0,0x00000000,0x0108a08a, +0x4145b80c,0x49458020,0x49458040,0x00000000, +0x0188b80a,0x494587e0,0x00000000,0x0108a08a, +0x4144b80c,0x494587a0,0x00000000,0x0108a52a, +0x41448080,0x49448040,0x494486c0,0x00000000, +0x0108a04a,0x41448040,0x49448720,0x00000000, +0x0108a36a,0x04028020,0x011fa420,0x001f8040, +0x011fa100,0x001f8080,0x011fa080,0x001f8100, +0x011fa040,0x001f8660,0x011fa120,0x41458020, +0x49458000,0x00000000,0x0108a00a,0x0017b816, +0x9036007c,0x0097b801,0x81171000,0x81970784, +0x00000000,0x001f8020,0x042087e4,0x81df0000, +0x00000000,0x00000000,0xb600100f,0x4041800c, +0x001f8020,0x0048b802,0x5e38802c,0x2e11b801, +0x042087e4,0x1042b810,0x0462b804,0xb4a00002, +0x0047b804,0xb5000003,0x0462b805,0xb4600001, +0x0047b805,0x011fa022,0x81df0004,0x81470000, +0x81670001,0x81870008,0x81a70040,0x81c707c4, +0x81e70040,0x81df0000,0x00000000,0x00000000, +0xb6000432,0xb00a0001,0xb4e00004,0x80c71000, +0x80e71000,0x81171040,0xb5000003,0x80c71040, +0x80e71040,0x81171000,0x844d0004,0x10e7b802, +0xb62b001f,0x0017b806,0x0097b807,0xb62c0004, +0x40048020,0x480487e4,0x00000000,0x0108a020, +0x0017b806,0x0097b807,0x0197b80e,0x00000000, +0x001f8020,0x042087e4,0xb62c000f,0x4041800c, +0x001f8020,0x0048b802,0x5e38802c,0x2e11b801, +0x042087e4,0x1042b810,0x0462b804,0xb4a00002, +0x0047b804,0xb5000003,0x0462b805,0xb4600001, +0x0047b805,0x011fa022,0x10c6b80f,0x10e7b80f, +0x5961b80b,0x5d81b80c,0x5da1b80d,0x5de1b80f, +0x914a0001,0x954a0001,0x11ceb80f,0x81df0004, +0x80171034,0x81171f84,0x80470000,0x41448040, +0x49448640,0x00000000,0x0188b80a,0x49448100, +0x49448780,0x00000000,0x0108a08a,0x4144b80c, +0x49448040,0x49448080,0x494487c0,0x00000000, +0x0108a16a,0x4145b80c,0x49458700,0x00000000, +0x0188b80a,0x494581a0,0x494586e0,0x00000000, +0x0108a66a,0x4145b80c,0x49448040,0x494487e0, +0x00000000,0x0188b80a,0x011fa1ec,0x4145b80c, +0x49458100,0x49458780,0x00000000,0x0108a08a, +0x41458720,0x49458100,0x494586e0,0x49458160, +0x49458020,0x49458020,0x49458760,0x00000000, +0x0108a08a,0x414587a0,0x49458080,0x49458760, +0x494580c0,0x49458700,0x49458140,0x49458020, +0x49458760,0x00000000,0x0108a74a,0x414587a0, +0x49458080,0x49458760,0x494580e0,0x49458700, +0x49458120,0x49458020,0x49458760,0x00000000, +0x0108a08a,0x41458720,0x49458100,0x494586e0, +0x49458140,0x49458040,0x49458020,0x49458720, +0x00000000,0x0108a0ca,0x41458080,0x49458040, +0x49458020,0x49458620,0x00000000,0x0188b80a, +0x49458080,0x00000000,0x0108a7ca,0x4144b80c, +0x49458040,0x49458020,0x49458080,0x00000000, +0x0108a5ea,0x41448080,0x49448700,0x00000000, +0x0188b80a,0x49448780,0x00000000,0x0108a7ca, +0x4144b80c,0x49448140,0x00000000,0x0108a7ca, +0x49448040,0x00000000,0x0108a0ca,0x41448700, +0x00000000,0x0188b80a,0x49448000,0x00000000, +0x0108a04a,0x011fa00c,0x80171f80,0x81df0000, +0x00000000,0x00000000,0xb6002006,0x40048000, +0x48048000,0x48048000,0x48048000,0x00000000, +0x0008a020,0x81df0004,0x00ffb81d,0x00000000, +0x80770000,0x8057ffff,0x015f05b9,0x017f05bb, +0x8293ffff,0x9a94ffff,0x81a70000,0x81df0000, +0x00000000,0x00000000,0xb62a003a,0xaded0180, +0xae0d0180,0xadcd0080,0x902f1980,0x0017b801, +0xb6002033,0x904e01b8,0x00000000,0x013ff002, +0xb0090000,0xb400001f,0x904f02b8,0x80c70000, +0x011fd802,0x6829b808,0x94210001,0xb0010001, +0xb4e00001,0x00c7b814,0x6429b806,0x80470001, +0x6449b802,0x84420001,0x1442b808,0x84690001, +0x5863b803,0x906300dc,0x1042b801,0x003f9803, +0x90420001,0x4082b801,0x90630004,0x003f9803, +0x00000000,0x5897b804,0x1804b805,0x4082b801, +0x00000000,0x00000000,0x00000000,0x10a4b800, +0xb5000001,0x80a70000,0x90501c80,0x00000000, +0x007ff002,0x5842b803,0x904205f8,0x0097b802, +0x00000000,0x40058004,0x48058004,0x00000000, +0x0008a020,0x91ce0004,0x91ef0004,0x92100004, +0x91ad0001,0x81df0004,0x00ffb81a,0x80770000, +0x8057ffff,0x80d7ffff,0x015f05b9,0x017f05bb, +0x8293ff80,0x9a940000,0x82a70020,0x81a70000, +0x81e702b8,0x80171980,0x81df0000,0x00000000, +0x00000000,0xb62a004f,0xb600034d,0xac0d0080, +0xac4d0180,0xac960080,0x822700bc,0x91c001b8, +0x00000000,0x1042b804,0x92021c80,0xb62b003a, +0x013ff00e,0x00fff011,0xb0090000,0xb4000027, +0x10e7b809,0x5821b807,0x902100dc,0x00000000, +0x001fd801,0x82470000,0x80270001,0x6452b801, +0x3002b800,0xb4600002,0x92520001,0xb500fffb, +0x86520001,0x80c70000,0x011fd80f,0x6832b808, +0xb0010001,0xb4e00001,0x00c7b814,0x84520017, +0x0056b802,0x80270001,0x6432b801,0x84210001, +0x1408b801,0x6402b800,0x10c6b800,0x9027018c, +0x00000000,0x001ff001,0x5802b800,0x9020073c, +0x904006f8,0x007f9801,0x0097b802,0x10c6b803, +0x40868004,0x48868004,0xb5000003,0x80c70000, +0x40868004,0x00000000,0x0088b804,0x003ff010, +0x5822b801,0x902105f8,0x0097b801,0x91ce0004, +0x91ef0004,0x40448004,0x48448004,0x92100004, +0x0008a022,0x92310001,0x0435b80b,0xb4000007, +0x80870000,0xb6210005,0x001fa024,0x91ce0004, +0x91ef0004,0x92100004,0x92310001,0x00000000, +0x91ad0001,0x81df0004,0x00ffb81a,0x00000000, +0x007f05b9,0x001f0081,0xb0000001,0xb440002d, +0x001f05d8,0xac400080,0x801702b8,0x80970438, +0x90421800,0x0117b802,0x8087ffff,0x80b3ffff, +0x80d3007f,0x98c6ff00,0x80f3ff80,0x81070080, +0x81df0000,0x00000000,0x00000000,0xb6002018, +0x10088020,0x0056b800,0x0442b806,0xb4a00004, +0xb0000000,0x0007b806,0xb4400001,0x0007b807, +0x0027b800,0x5c08b800,0x1400b804,0xb0030001, +0xb4000008,0x10288024,0x0056b801,0x0442b806, +0xb4a00004,0xb0010000,0x0027b806,0xb4400001, +0x0027b807,0x5828b801,0x1421b805,0x1900a021, +0x81df0004,0x001f05d8,0x90000001,0x001f25d8, +0x00ffb81a,0x801702b8,0x80970438,0x81171800, +0x8087ffff,0x80b3ffff,0x80d3007f,0x98c6ff00, +0x80f3ff80,0x81070080,0x81df0000,0x00000000, +0x00000000,0xb6006018,0x10088020,0x0056b800, +0x0442b806,0xb4a00004,0xb0000000,0x0007b806, +0xb4400001,0x0007b807,0x0027b800,0x5c08b800, +0x1400b804,0xb0030001,0xb4000008,0x10288024, +0x0056b801,0x0442b806,0xb4a00004,0xb0010000, +0x0027b806,0xb4400001,0x0027b807,0x5828b801, +0x1421b805,0x1900a021,0x81df0004,0x00ffb81a, +0x001f0081,0xb0000001,0xb4400006,0x001f05d8, +0xb0000003,0xb4000003,0x80270001,0x003f25dc, +0x00ffb81a,0x003f05d9,0x009f05cb,0xb0010000, +0xb400000e,0x015f42ed,0x81070000,0x8127017c, +0xb00a0000,0xb4000002,0x81070180,0x812702fc, +0x802500a5,0x9421ffff,0x3001b808,0xb4800011, +0x3001b809,0xb4a0007f,0xb500000e,0x001f0081, +0xb0000001,0xb4400003,0xb0040002,0xb4200006, +0xb5000002,0xb0040000,0xb4200003,0x802702ff, +0x81470000,0xb5000003,0x80270001,0x003f25d9, +0x81470180,0xb0040000,0xb4200001,0x838402e6, +0x80070000,0x001f25d8,0x009f902d,0x80af001f, +0x808f0000,0x806f0000,0x8007ffff,0x8033ffff, +0x80171800,0x81df0000,0x807bff8c,0x94630003, +0xb0030003,0xb4000016,0xb0030002,0xb4000035, +0xb0030001,0xb4000024,0xb6006010,0x14618000, +0x6068b803,0x40c4b803,0x14608000,0x00c8b806, +0x5870b803,0x6068b803,0x4104b803,0x58c8b806, +0x0108b808,0x14c6b801,0x00000000,0x00000000, +0x5d08b808,0x1508b800,0x1806a028,0xb5000030, +0xb6006010,0x14618000,0x6068b803,0x40c4b803, +0x14608000,0x00c8b806,0x5870b803,0x6068b803, +0x4104b803,0x5cc8b806,0x0108b808,0x14c6b800, +0x00000000,0x00000000,0x5908b808,0x1508b801, +0x1806a028,0xb500001e,0xb600600d,0x14618000, +0x6068b803,0x40c4b803,0x00000000,0x00c8b806, +0x00000000,0x00000000,0x00000000,0x5d08b806, +0x1508b800,0x58c8b806,0x14c6b801,0x1806a028, +0xb500000f,0xb600600e,0x14608000,0x5868b803, +0x6068b803,0x40c4b803,0x00000000,0x00c8b806, +0x00000000,0x00000000,0x00000000,0x5d08b806, +0x1508b800,0x58c8b806,0x14c6b801,0x1806a028, +0x81df0004,0x80670600,0x5d22b80a,0x81df0000, +0x00000000,0x00000000,0xb600030a,0x00cfb803, +0x013fb178,0x5922b809,0x01afb809,0x013f9178, +0x0047b86f,0xb0020001,0xb4c0fffd,0x90630020, +0x91290020,0x81df0004,0x81270180,0xb00a0000, +0xb4000001,0x81270000,0x013f62ed,0x80270001, +0x003f25dc,0x00ffb81a,0x801bff7c,0x00000000, +0x94000080,0xb0000080,0xb400ff61,0x001f0081, +0xb0000001,0xb4400006,0x001f05d8,0xb0000003, +0xb4000003,0x80270001,0x003f25dc,0x00ffb81a, +0x003f05d9,0x009f05cb,0xb0010000,0xb400000e, +0x015f42ed,0x81070000,0x812702fc,0xb00a0000, +0xb4000002,0x81070300,0x812705fc,0x802500a5, +0x9421ffff,0x3001b808,0xb4800011,0x3001b809, +0xb4a00073,0xb500000e,0x001f0081,0xb0000001, +0xb4400003,0xb0040002,0xb4200006,0xb5000002, +0xb0040000,0xb4200003,0x802705ff,0x81470000, +0xb5000003,0x80270001,0x003f25d9,0x81470300, +0xb0040000,0xb4200001,0x83840247,0x80070000, +0x001f25d8,0x009f902d,0x80af001f,0x808f0000, +0x806f0000,0x8007ffff,0x8033ffff,0x80171800, +0x807bff8c,0x80971980,0x81df0000,0x94630003, +0xb0030003,0xb4000013,0xb0030002,0xb400002c, +0xb0030001,0xb400001e,0xb600600d,0x58708000, +0x6068b803,0x40c4b803,0x14618020,0x00c8b806, +0x6068b803,0x4104b803,0x00000000,0x0108b808, +0x5887a026,0x00000000,0x00000000,0x5887a028, +0xb5000026,0xb600600d,0x14618000,0x6068b803, +0x40c4b803,0x58708020,0x00c8b806,0x6068b803, +0x4104b803,0x00000000,0x0108b808,0x5887a026, +0x00000000,0x00000000,0x5887a028,0xb5000017, +0xb600600a,0x14618000,0x6068b803,0x40c4b803, +0x00000000,0x00c8b806,0x00000000,0x00000000, +0x00000000,0x5887a026,0x5887a026,0xb500000b, +0xb600600a,0x58708000,0x6068b803,0x40c4b803, +0x00000000,0x00c8b806,0x00000000,0x00000000, +0x00000000,0x5887a026,0x5887a026,0x81df0004, +0x80670660,0x5d22b80a,0x81df0000,0x00000000, +0x00000000,0xb600060a,0x00cfb803,0x013fb178, +0x5922b809,0x01afb809,0x013f9178,0x0047b86f, +0xb0020001,0xb4c0fffd,0x90630020,0x91290020, +0x81df0004,0x81270300,0xb00a0000,0xb4000001, +0x81270000,0x013f62ed,0x80270001,0x003f25dc, +0x00ffb81a,0x00000000,0x00000000,0x00000000, +0x029fb024,0x02bfb025,0x02dfb026,0x02ffb027, +0x031fb028,0x033fb029,0x033f4046,0x0287b86f, +0x029fb02a,0x8285009c,0x96b48000,0xb0158000, +0xb400018e,0x96b40100,0xb0150100,0xb40001a4, +0x96b40400,0xb0150400,0xb40001a5,0x96b40001, +0xb0150001,0xb400000c,0x96b40008,0xb0150008, +0xb4000197,0x96b44000,0xb0154000,0xb40001a4, +0x96b40002,0xb0150002,0xb400015b,0x00000000, +0x00000000,0xb50001b6,0x02bf917e,0x92b50001, +0x02bfb17e,0x82850082,0x5efdb814,0x96f70001, +0xb0170001,0xb420000b,0x83050069,0x9718003f, +0x82e50064,0x12f7b818,0x86f70109,0x82feff74, +0x02e7b86f,0x9af74000,0x01ffb817,0x96f7bfff, +0x01ffb817,0x83050081,0x82a5009a,0x96b50001, +0xb0150001,0xb4200014,0x82a70000,0x02bfb17e, +0x96b41840,0xb0150800,0xb420000c,0x96b40008, +0x5aa9b815,0x96d46000,0x5ec3b816,0x82f3000f, +0x9af7c00f,0x1718b817,0x1ab5b818,0x1ab5b816, +0x9ab50340,0x82a60081,0xb500012b,0x9b180180, +0x83060081,0xb5000128,0x82a5009a,0x96b50002, +0xb0150002,0xb420001b,0x82a70000,0x02bfb17e, +0x96b41800,0xb0151800,0xb4000013,0x96b40040, +0xb0150040,0xb4200004,0xa3180c00,0x9b180340, +0x83060081,0xb5000118,0x96b40008,0x5aa9b815, +0x96d46000,0x5ec3b816,0x82f3000f,0x9af7c00f, +0x1718b817,0x1ab5b818,0x1ab5b816,0x9ab50340, +0x82a60081,0xb500010c,0x9b180180,0x83060081, +0xb5000109,0x82a500c1,0x96b5000f,0xb015000b, +0xb420000e,0x96b40020,0xb0150020,0xb400000b, +0x96b40200,0xb0150200,0xb4000008,0x82c50086, +0x82e50094,0x3016b817,0xb4400004,0x06f7b816, +0xb017ff00,0xb4400001,0xb50000f7,0x96b46000, +0xb0156000,0xb4000011,0x96b41820,0xb0150820, +0xb4200004,0x9b391000,0x82a5009a,0x96b5feff, +0x82a6009a,0x96b40040,0xb0150040,0xb4200001, +0x9739efff,0x96b91000,0xb0151000,0xb4200003, +0x82a5009a,0x9ab50100,0x82a6009a,0x96b40040, +0xb0150040,0xb4200019,0x96b41800,0xb0151800, +0xb4200006,0x96b98000,0xb0158000,0xb4200003, +0x9b180180,0x83060081,0xb50000d7,0x96d80c00, +0x82b300ff,0x9ab5f3ff,0x1718b815,0xb0160c00, +0xb4000007,0x82e50098,0x96f70400,0xb0170400, +0xb4200002,0x82c70c00,0xb5000001,0xa2d60c00, +0x1b18b816,0x9b180340,0xb50000bd,0x96b40220, +0xb0150000,0xb4e00021,0x82a5009d,0x82f3ffff, +0x16b5b817,0x82f3000e,0x3015b817,0xb420001b, +0x96f98000,0xb0178000,0xb4000018,0x82a70000, +0x02bfb17e,0x82c5009d,0x96d6ffff,0x82b30032, +0x9ab58001,0x82e500c1,0x96f7000f,0xb017000b, +0xb4000002,0x82b30022,0x9ab58001,0x1ab5b816, +0x82c5009a,0x96d60020,0xb0160020,0xb4200002, +0x82b30032,0x9ab58001,0x82a6009d,0x02ff917e, +0x00000000,0xb0170040,0xb4800000,0x5eb5b814, +0x96b500f0,0x96f46000,0x5eedb817,0x1ab5b817, +0xb0170003,0xb4000004,0x96b500ef,0x96f70001, +0x5ae4b817,0x1ab5b817,0x96d41800,0xb0161800, +0xb400000a,0x96f900ff,0x96b500ff,0x9739ff00, +0x1b39b815,0x02a7b817,0x96b500f3,0x96d40008, +0x5ec1b816,0x1ab5b816,0xb500000c,0x96f98000, +0xb0178000,0xb4200007,0x5efeb814,0x96f70001, +0xb0170001,0xb4000003,0x9b180180,0x83060081, +0xb5000081,0x96b500f3,0x9ab50008,0x9739fff3, +0x96d40020,0xb0160020,0xb4200017,0x9b398000, +0x82c70000,0x02dfb17e,0x96d40010,0x5ac8b816, +0x82f300ff,0x9af7cfff,0x1718b817,0x1b18b816, +0x9b180340,0x82c5009d,0x96d6ffff,0x82f3000e, +0x9af78001,0x1af7b816,0x82c5009a,0x96d60020, +0xb0160020,0xb4200002,0x82f30032,0x9af78001, +0x82e6009d,0xb500005a,0x97397fff,0x96b500ff, +0x5aaab815,0x82f300fc,0x9af703ff,0x1718b817, +0x1b18b815,0x9b180340,0x82c5009a,0x96d60010, +0xb0160010,0xb4200024,0x82c70000,0x02dfb17e, +0x82c50086,0x92d60e10,0x82c60086,0x82c50094, +0x5eefb818,0x96f70003,0xb0170003,0xb4200002, +0x82e70e10,0xb5000001,0x82e70e10,0x12d6b817, +0x82e50081,0x9af70020,0x82e60081,0x82c60094, +0xa2f70020,0x82e60081,0x82f30001,0x16f7b818, +0x5ef0b817,0xb0170001,0xb4000004,0x96f84000, +0x5ee4b817,0x9718f3ff,0x1b18b817,0x82f3000a, +0x9af78000,0x82e6009d,0x83060081,0x83070001, +0x8306009f,0xb5000096,0x82c5009d,0x82f3000e, +0x9af78001,0x3016b817,0xb420000f,0x82b30032, +0x9ab58001,0x82e500c1,0x96f7000f,0xb017000b, +0xb4000002,0x82b30022,0x9ab58001,0x82c5009a, +0x96d60020,0xb0160020,0xb4200002,0x82b30032, +0x9ab58001,0x82a6009d,0x82c5009a,0x96d60080, +0xb0160080,0xb4000011,0x02df917e,0x00000000, +0xb0160010,0xb480000d,0x82c500c1,0x96d6000f, +0xb016000b,0xb4000009,0x82c50087,0x96d60080, +0x5ac7b816,0x96f84000,0x3017b816,0xb4200003, +0x033f4046,0x9b394000,0xb500000b,0x9739bfff, +0x82e50061,0x96f70008,0xb0170008,0xb4000005, +0x5eefb818,0x96f70003,0xb0170003,0xb4000001, +0x9718ffff,0x83060081,0x83070001,0x8306009f, +0x00000000,0xb500005e,0x82850083,0x96b400ff, +0xb015003c,0xb4200019,0x96b92000,0xb0152000, +0xb4000002,0x9b392000,0xb5000014,0x9739d3ff, +0x82870000,0x82860087,0x82870008,0x82860083, +0x829bff78,0x82a7001f,0xb0140400,0xb4000001, +0x82a70010,0x82a600c9,0x829bff78,0x00000000, +0x828600cb,0x8285009d,0x82b3ffff,0x9ab5fffd, +0x1694b815,0x8286009d,0xb5000000,0x83070002, +0x8306009f,0x00000000,0xb500003d,0x96b90800, +0xb0150800,0xb4200009,0x9739f7ff,0x82a703fd, +0x82a600cb,0x82a7003c,0x82a60083,0x8285009d, +0x9a940002,0x8286009d,0xb5000004,0x82850087, +0x5a82b814,0xa2940200,0x82860087,0xb5000000, +0x83078000,0x8306009f,0x00000000,0xb5000028, +0x83070008,0x8306009f,0x00000000,0xb5000024, +0x83070100,0x8306009f,0x00000000,0xb5000020, +0x83070000,0x83050081,0x9b180180,0x83060081, +0x83070400,0x8306009f,0x00000000,0xb5000018, +0x82870000,0x82850082,0x5eb7b814,0x96b500fc, +0x96d40006,0x5ec1b816,0x1ab5b816,0x5aacb815, +0x83050081,0x82d3001c,0x9ad600ff,0x1718b816, +0x1b18b815,0x9b180e00,0x83060081,0x83074000, +0x8306009f,0x8305009d,0x82d300ff,0x9ad6bfff, +0x1718b816,0x8306009d,0x00000000,0xb5000000, +0x029f902a,0x01ffb814,0x033f6046,0x029f9024, +0x02bf9025,0x02df9026,0x02ff9027,0x031f9028, +0x033f9029,0x00ffb81e,0x02ff917d,0x92f7092f, +0x031f0084,0xb0180001,0xb4200002,0x02ff917d, +0x92f70870,0x02ffb17d,0x02ff917c,0x82bbffdc, +0x829bffd8,0x93150004,0x3014b815,0xb4000017, +0x02dbb818,0x029bb815,0x3017b816,0xb4800013, +0x5a81b814,0x029fb17d,0x82def200,0x82fef204, +0x82e50086,0x06f7b814,0x02f6b817,0x82fef208, +0x82860095,0x82870001,0x829ef220,0x8293001f, +0x9294fe00,0x92b50008,0x3015b814,0xb4800002, +0x82b3001f,0x92b5fa00,0x82beffdc,0x82850086, +0x83250094,0x06d4b819,0x02d6b816,0xb016ffff, +0xb4a00009,0x82c50081,0x9ab60020,0x82a60081, +0x82a50086,0x92b50e10,0x82a60094,0x82c60081, +0x86b50704,0x82a6009b,0x00ffb81c,0x00000000, +0x001f9012,0x001fb200,0x001f004c,0x001f2804, +0x801bfef0,0x8058fef4,0x803bff68,0x8078ff6c, +0x2000b801,0x2042b803,0x001fb204,0x005f2814, +0x82e70001,0x83640048,0x029fb014,0x829efef0, +0x8286000f,0x02bf2054,0x82bcfef4,0x82a6000e, +0x00ffb81a,0x80e70001,0x801336e3,0x9800eb76, +0x001fb200,0x800700ab,0x001f2804,0x801bc3e8, +0x8058c3ec,0x83640024,0x82e70000,0x83640036, +0x029fb3c0,0x029fb200,0x02bf2f04,0x02bf2804, +0x801bc000,0x8058c004,0x8364001b,0x82e70000, +0x8364002d,0x001f93c0,0x3000b814,0xb420000a, +0x001f0f04,0x3000b815,0xb4200007,0x829efef0, +0x82bcfef4,0x029fb012,0x02bf204c,0x82870001, +0x829cfef5,0x00ffb81a,0xb0070000,0xb4000007, +0x80e70000,0x801399fa,0x9800c92e,0x001fb200, +0x800700af,0x001f2804,0xb500ffdc,0x82870000, +0x829cfef5,0x00ffb81a,0x80c700ff,0x803bff68, +0x8078ff6c,0x14a0b806,0x2063b805,0x007f2814, +0x2021b802,0x58c8b806,0x14a0b806,0x58b0b805, +0x2021b805,0x58c8b806,0x14a0b806,0x2021b805, +0x58c8b806,0x14a0b806,0x5cb0b805,0x2021b805, +0x003fb204,0x00ffb81b,0x82c70000,0x83070800, +0x83270005,0x8197080c,0x81d7ffff,0x83840126, +0x83840001,0x00ffb81b,0x808f0000,0x806f001f, +0x80af001f,0x80270240,0x81e77c08,0x5de2b80f, +0xb6000208,0x00cfb801,0x01ffb178,0x59e2b80f, +0x01cfb80f,0x01ff9178,0xb520ffff,0x91ef0020, +0x90210020,0x80270280,0x81e77b00,0x5de2b80f, +0xb6000208,0x00cfb801,0x01ffb178,0x59e2b80f, +0x01cfb80f,0x01ff9178,0xb520ffff,0x91ef0020, +0x90210020,0x8057ffff,0x80170830,0x80070810, +0x80270808,0xb6000509,0x005ff000,0x90420900, +0x007ff001,0x90630a00,0x009ff002,0x00bff003, +0x2004a025,0x90000001,0x90210001,0x80070814, +0x80d7ffff,0x8097085c,0x8017083c,0xb6000404, +0x005ff000,0x007f87e0,0x84000001,0x2082a7e3, +0x80970860,0x80170840,0x2082b803,0x007f8000, +0x2083a004,0x80170830,0x80970850,0x80270808, +0xb6000508,0x005f8024,0x90420900,0x007ff001, +0x90630a00,0x009ff002,0x00bff003,0x2004a025, +0x90210001,0x80170840,0x00000000,0x02bf87e0, +0x80970860,0x82870000,0xb6000404,0x005f87e4, +0x5a88b814,0x204287e0,0x1a94b802,0x00ffb81c, +0x001f0e49,0x001f2b09,0x001f0e41,0x001f2b08, +0x001f0e46,0x001f2b07,0x001f0e48,0x001f2b06, +0x001f0e42,0x001f2b05,0x001f0e47,0x001f2b04, +0x001f0e45,0x001f2b03,0x001f0e43,0x001f2b02, +0x001f0e40,0x001f2b01,0x001f0e44,0x001f2b00, +0x001f0f25,0xa020000c,0x94400001,0x94600002, +0x94810004,0x94a10008,0x94c00010,0x5943b802, +0x5861b803,0x5882b804,0x5ca2b805,0x5cc4b806, +0x194ab803,0x194ab804,0x194ab805,0x194ab806, +0x015f2b38,0x801b7c00,0x003f92c1,0x5c28b801, +0x005f92c2,0x5858b802,0x1821b802,0x2000b801, +0x001fb2c4,0x80187c04,0x003f0b09,0x2000b801, +0x001f2b14,0x82c70001,0x82e70001,0x83070b10, +0x8327001e,0x81970b35,0x8384009f,0x02df0b38, +0x82170e30,0x838400f1,0x819efef0,0x817cfef4, +0x819eff68,0x817cff6c,0x00ffb81b,0x820f001f, +0x8018fef8,0x8057ffff,0x001f2b09,0x8018fef6, +0x80d7ffff,0x001f2b08,0x8018fefa,0x8157ffff, +0x001f2b07,0x8018fefd,0x81d7ffff,0x001f2b06, +0x8018fefb,0x802f001f,0x001f2b05,0x8018fefe, +0x00000000,0x001f2b04,0x8018fef9,0x00000000, +0x001f2b03,0x8018feff,0x00000000,0x001f2b02, +0x8018fef7,0x00000000,0x001f2b01,0x8018fefc, +0x00000000,0x001f2b00,0x001f0f25,0xa0200011, +0x94410001,0x94600002,0x94800004,0x94a00008, +0x94c10010,0x5941b802,0x5861b803,0x5c82b804, +0x58a1b805,0x5cc1b806,0x194ab803,0x194ab804, +0x194ab805,0x194ab806,0x015f2b38,0x801b7c00, +0x003f92c1,0x5c28b801,0x005f92c2,0x5858b802, +0x1821b802,0x2000b801,0x001fb2c4,0x80187c04, +0x003f0b09,0x2000b801,0x001f2b14,0x82c70001, +0x82e70001,0x83070b10,0x8327001e,0x81970b35, +0x83840055,0x02df0b38,0x82170e20,0x838400a7, +0x819efef0,0x817cfef4,0x5ac8b80c,0x02ff0e44, +0x1ad6b817,0x02dfb391,0x5ed8b80c,0x5968b80b, +0x1ad6b80b,0x02df6724,0x00ffb81b,0x820f001f, +0x8018fefe,0x8057ffff,0x001f2b09,0x8018fefa, +0x80d7ffff,0x001f2b08,0x8018fefc,0x8157ffff, +0x001f2b07,0x8018feff,0x81d7ffff,0x001f2b06, +0x8018fef8,0x802f001f,0x001f2b05,0x8018fefb, +0x00000000,0x001f2b04,0x8018fefd,0x00000000, +0x001f2b03,0x8018fef6,0x00000000,0x001f2b02, +0x8018fef9,0x00000000,0x001f2b01,0x8018fef7, +0x00000000,0x001f2b00,0x801b7c00,0x003f92c1, +0x5c28b801,0x005f92c2,0x5858b802,0x1821b802, +0x2000b801,0x001fb2c4,0x80187c04,0x003f0b09, +0x2000b801,0x001f2b14,0x82c70001,0x82e70001, +0x83070b10,0x8327001e,0x81970b35,0x83840016, +0x83270000,0x831bfef0,0x82f8fef4,0x02c7b819, +0x82170e28,0x83840065,0x300cb818,0xb4200002, +0x300bb817,0xb4000006,0x93390001,0xb0190020, +0xb480fff6,0x83270000,0x833cfef5,0x00ffb81b, +0x019fb390,0x017f2e44,0x033f2f25,0x83270001, +0x833cfef5,0x00ffb81b,0x0007b818,0x90000003, +0x00000000,0x015ff000,0x90000001,0x5949b80a, +0x013ff000,0x194ab809,0x84000002,0x994a0100, +0x017ff000,0x958b00f8,0x5981b80c,0x956b0007, +0x198cb80b,0x84000002,0x998c0008,0x017ff000, +0x90000001,0x5971b80b,0x198cb80b,0x017ff000, +0x5969b80b,0x198cb80b,0x81a70000,0x94d90003, +0x82a70000,0xb6260019,0xb6000818,0x5df0b80a, +0x5e02b80a,0x21efb810,0x95ef0001,0x5941b80a, +0x194ab80f,0x21efb816,0x5e18b80c,0x5e35b80c, +0x5e54b80c,0x5e6cb80c,0x2210b811,0x2252b813, +0x2210b812,0x96100001,0x5981b80c,0x198cb810, +0x2210b817,0x10afb810,0x10a5b80d,0x5da1b805, +0x94a50001,0x5aa1b815,0x1ab5b805,0x019fa7f5, +0x5cc2b819,0xb626001c,0x82870000,0xb6000419, +0xb6000818,0x5df0b80a,0x5e02b80a,0x21efb810, +0x95ef0001,0x5941b80a,0x194ab80f,0x21efb816, +0x5e18b80c,0x5e35b80c,0x5e54b80c,0x5e6cb80c, +0x2210b811,0x2252b813,0x2210b812,0x96100001, +0x5981b80c,0x198cb810,0x2210b817,0x10afb810, +0x10a5b80d,0x5da1b805,0x94a50001,0x5a81b814, +0x1a94b805,0x019fa7f4,0x00ffb81c,0x8257ffff, +0x808f0000,0x806f001f,0x80af001f,0x80270300, +0x81e778e0,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x80270340, +0x81e779e0,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x80270280, +0x81e77b00,0x5de2b80f,0xb6000208,0x00cfb801, +0x01ffb178,0x59e2b80f,0x01cfb80f,0x01ff9178, +0xb520ffff,0x91ef0020,0x90210020,0x806f0007, +0x80af0007,0x80270380,0x81e77ae0,0x5de2b80f, +0x00cfb801,0x01ffb178,0x59e2b80f,0x01cfb80f, +0x01ff9178,0xb520ffff,0x91ef0020,0x90210020, +0x80170b60,0x001f0b00,0x001fa020,0x001f0b01, +0x001fa020,0x001f0b02,0x001fa020,0x001f0b03, +0x001fa020,0x001f0b04,0x001fa000,0x80970b50, +0x81170b70,0x82a70b35,0x83a40060,0x001f87e4, +0xb6000405,0x86b50001,0x83a4005c,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b70,0x80170b50, +0x81170b50,0x81970b40,0x82a70b30,0x001f800c, +0x003f8008,0x2100a001,0x83a40050,0x001f87e4, +0xb6000405,0x86b50001,0x83a4004c,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b50,0x80170b70, +0x81170b70,0x81970b60,0x82a70b2b,0x001f800c, +0x003f8008,0x2100a001,0x83a40040,0x83a4004e, +0xb6000407,0x86b50001,0x83a4003c,0x001f8004, +0x003f87e8,0x2080a001,0x83a40047,0x00000000, +0x80970b70,0x80170b50,0x81170b50,0x81970b40, +0x82a70b26,0x001f800c,0x003f8008,0x2100a001, +0x83a4002e,0x83a4003c,0xb6000407,0x86b50001, +0x83a4002a,0x001f8004,0x003f87e8,0x2080a001, +0x83a40035,0x00000000,0x80970b50,0x80170b70, +0x81170b70,0x81970b60,0x82a70b21,0x001f800c, +0x003f8008,0x2100a001,0x83a4001c,0x001f87e4, +0xb6000405,0x86b50001,0x83a40018,0x001f8004, +0x003f87e8,0x2080a7e1,0x80970b70,0x80170b50, +0x81170b50,0x81970b40,0x82a70b1c,0x001f800c, +0x003f8008,0x2100a001,0x83a4000c,0x017f87e4, +0x81870000,0xb6000406,0x86b50001,0x83a40007, +0x001f87e4,0x200087e8,0x5988b80c,0x198cb800, +0x021fa02c,0x021fa00b,0x00ffb81c,0x005ff015, +0x90420a00,0x003f87e0,0x001ff002,0x2060b801, +0x90630c00,0x90960e00,0x001ff003,0x003ff004, +0x20a0b801,0x90a50d00,0x00000000,0x001ff005, +0x009fa000,0x00ffb81d,0x001f8004,0x5c21b800, +0x5847b800,0x1821b802,0x942100ff,0x2080a7e1, +0x00ffb81d,0x00000000,0x00000000,0x00000000, + +}; + +static u32 MPGI2SUcode1f5c00[] = { +0x00000000,0xfffff8c0,0x00003540,0xffff8d40, +0x0001fd40,0xfffaf7c0,0x00066b80,0xffdb63c0, +0x00494780,0x00249c40,0x00066b80,0x00050840, +0x0001fd40,0x000072c0,0x00003540,0x00000740, +0xffffffc0,0xfffff840,0x00003680,0xffff7e40, +0x0001f400,0xfffa9cc0,0x0005d1c0,0xffd99600, +0x00493c00,0x0022ce00,0x0006f780,0x0004ad00, +0x000203c0,0x00006440,0x00003400,0x00000680, +0xffffffc0,0xfffff740,0x00003780,0xffff6ec0, +0x0001e800,0xfffa4240,0x00052a00,0xffd7ca00, +0x00491a00,0x0020ffc0,0x00077600,0x00045240, +0x00020800,0x000056c0,0x00003280,0x00000600, +0xffffffc0,0xfffff680,0x00003840,0xffff5ec0, +0x0001d940,0xfff9e8c0,0x00047440,0xffd60080, +0x0048e180,0x001f32c0,0x0007e700,0x0003f7c0, +0x000209c0,0x00004980,0x00003100,0x00000540, +0xffffffc0,0xfffff5c0,0x000038c0,0xffff4e40, +0x0001c780,0xfff990c0,0x0003b000,0xffd43ac0, +0x00489240,0x001d6800,0x00084b00,0x00039e40, +0x00020940,0x00003d00,0x00002f80,0x000004c0, +0xffffffc0,0xfffff4c0,0x00003900,0xffff3d40, +0x0001b2c0,0xfff93a40,0x0002ddc0,0xffd279c0, +0x00482d00,0x001ba040,0x0008a200,0x000345c0, +0x000206c0,0x00003140,0x00002dc0,0x00000440, +0xffffffc0,0xfffff3c0,0x00003900,0xffff2c00, +0x00019b00,0xfff8e640,0x0001fd40,0xffd0be80, +0x0047b1c0,0x0019dc80,0x0008ecc0,0x0002ef00, +0x00020240,0x00002640,0x00002c00,0x00000400, +0xffffff80,0xfffff2c0,0x000038c0,0xffff1a40, +0x00017fc0,0xfff894c0,0x00010e80,0xffcf09c0, +0x004720c0,0x00181d80,0x00092b40,0x000299c0, +0x0001fc00,0x00001bc0,0x00002a40,0x00000380, +0xffffff80,0xfffff180,0x00003800,0xffff0840, +0x00016180,0xfff84680,0x00001180,0xffcd5cc0, +0x00467a40,0x00166440,0x00095e00,0x00024680, +0x0001f440,0x00001200,0x00002840,0x00000340, +0xffffff80,0xfffff040,0x00003740,0xfffef600, +0x00014000,0xfff7fbc0,0xffff0680,0xffcbb880, +0x0045bf00,0x0014b140,0x00098580,0x0001f580, +0x0001ea80,0x00000900,0x00002680,0x000002c0, +0xffffff80,0xffffef00,0x000035c0,0xfffee3c0, +0x00011ac0,0xfff7b540,0xfffded80,0xffca1d80, +0x0044ef80,0x00130580,0x0009a1c0,0x0001a700, +0x0001dfc0,0x00000080,0x000024c0,0x00000280, +0xffffff40,0xffffedc0,0x00003400,0xfffed180, +0x0000f280,0xfff77340,0xfffcc700,0xffc88d80, +0x00440bc0,0x001161c0,0x0009b3c0,0x00015b00, +0x0001d380,0xfffff8c0,0x000022c0,0x00000240, +0xffffff40,0xffffec40,0x00003200,0xfffebf40, +0x0000c680,0xfff73680,0xfffb92c0,0xffc708c0, +0x00431500,0x000fc6c0,0x0009bb80,0x000111c0, +0x0001c640,0xfffff1c0,0x00002100,0x00000200, +0xffffff00,0xffffeac0,0x00002f40,0xfffead00, +0x00009740,0xfff6ff40,0xfffa5180,0xffc59080, +0x00420b40,0x000e3500,0x0009b9c0,0x0000cb80, +0x0001b7c0,0xffffeb40,0x00001f40,0x000001c0, +0xffffff00,0xffffe940,0x00002c40,0xfffe9b00, +0x00006480,0xfff6ce00,0xfff90380,0xffc425c0, +0x0040ef80,0x000cad00,0x0009af00,0x00008840, +0x0001a880,0xffffe580,0x00001d40,0x000001c0, +0xfffffec0,0xffffe7c0,0x000028c0,0xfffe8980, +0x00002e40,0xfff6a3c0,0xfff7a900,0xffc2c900, +0x003fc280,0x000b2fc0,0x00099b80,0x00004800, +0x00019880,0xffffe040,0x00001bc0,0x00000180, +0xfffffec0,0xffffe600,0x00002480,0xfffe7840, +0xfffff4c0,0xfff68040,0xfff64240,0xffc17b40, +0x003e84c0,0x0009bdc0,0x00097fc0,0x00000b40, +0x000187c0,0xffffdb80,0x00001a00,0x00000140, +0xfffffe80,0xffffe440,0x00001fc0,0xfffe6780, +0xffffb800,0xfff66480,0xfff4d040,0xffc03d80, +0x003d3700,0x00085700,0x00095c40,0xffffd1c0, +0x00017680,0xffffd740,0x00001840,0x00000140, +0xfffffe40,0xffffe2c0,0x00001a80,0xfffe5780, +0xffff77c0,0xfff65100,0xfff35300,0xffbf1080, +0x003bda40,0x0006fc80,0x00093200,0xffff9b80, +0x00016500,0xffffd3c0,0x000016c0,0x00000100, +0xfffffe40,0xffffe0c0,0x000014c0,0xfffe4840, +0xffff3480,0xfff64640,0xfff1cb00,0xffbdf4c0, +0x003a6f80,0x0005ae80,0x000900c0,0xffff68c0, +0x00015300,0xffffd0c0,0x00001540,0x00000100, +0xfffffe00,0xffffdf00,0x00000e40,0xfffe39c0, +0xfffeee40,0xfff64480,0xfff03940,0xffbceb00, +0x0038f740,0x00046d40,0x0008c980,0xffff3980, +0x000140c0,0xffffce00,0x000013c0,0x000000c0, +0xfffffdc0,0xffffdd40,0x00000740,0xfffe2c80, +0xfffea500,0xfff64c40,0xffee9e40,0xffbbf440, +0x00377280,0x00033900,0x00088cc0,0xffff0d80, +0x00012e80,0xffffcc00,0x00001240,0x000000c0, +0xfffffd80,0xffffdb40,0xffffff80,0xfffe2040, +0xfffe5900,0xfff65e40,0xffecfa80,0xffbb1080, +0x0035e280,0x00021280,0x00084ac0,0xfffee540, +0x00011c40,0xffffca40,0x00001100,0x00000080, +0xfffffd40,0xffffd980,0xfffff700,0xfffe1580, +0xfffe0a80,0xfff67a80,0xffeb4ec0,0xffba4100, +0x00344780,0x0000f980,0x00080440,0xfffec000, +0x00010a00,0xffffc8c0,0x00000fc0,0x00000080, +0xfffffcc0,0xffffd7c0,0xffffee00,0xfffe0bc0, +0xfffdb980,0xfff6a200,0xffe99bc0,0xffb985c0, +0x0032a340,0xffffee80,0x0007b980,0xfffe9e80, +0x0000f7c0,0xffffc800,0x00000e80,0x00000080, +0xfffffc80,0xffffd5c0,0xffffe440,0xfffe0400, +0xfffd6640,0xfff6d4c0,0xffe7e280,0xffb8df40, +0x0030f640,0xfffef180,0x00076b40,0xfffe8040, +0x0000e5c0,0xffffc740,0x00000d40,0x00000080, +0xfffffc00,0xffffd400,0xffffd9c0,0xfffdfdc0, +0xfffd1100,0xfff71340,0xffe62380,0xffb84e40, +0x002f4180,0xfffe02c0,0x000719c0,0xfffe6500, +0x0000d400,0xffffc700,0x00000c40,0x00000040, +0xfffffbc0,0xffffd240,0xffffcec0,0xfffdf940, +0xfffcba40,0xfff75e00,0xffe45fc0,0xffb7d300, +0x002d8640,0xfffd2240,0x0006c5c0,0xfffe4d40, +0x0000c2c0,0xffffc700,0x00000b40,0x00000040, +0xfffffb40,0xffffd080,0xffffc300,0xfffdf6c0, +0xfffc61c0,0xfff7b500,0xffe29800,0xffb76dc0, +0x002bc540,0xfffc5000,0x00066f40,0xfffe3880, +0x0000b1c0,0xffffc740,0x00000a40,0x00000040, +0xfffffac0,0xffffcf00,0xffffb680,0xfffdf640, +0xfffc0840,0xfff81900,0xffe0cd40,0xffb71e80, +0x0029ff80,0xfffb8bc0,0x00061740,0xfffe26c0, +0x0000a140,0xffffc7c0,0x00000980,0x00000040, +0xfffffa00,0xffffcd80,0xffffa940,0xfffdf800, +0xfffbadc0,0xfff88a00,0xffdf0040,0xffb6e600, +0x00283600,0xfffad600,0x0005bdc0,0xfffe1800, +0x00009140,0xffffc880,0x000008c0,0x00000040, +0xfffff980,0xffffcc00,0xffff9bc0,0xfffdfc40, +0xfffb5300,0xfff90880,0xffdd3200,0xffb6c400, +0x00266a00,0xfffa2e40,0x00056340,0xfffe0c00, +0x000081c0,0xffffc980,0x000007c0,0x00000040, +0x004013c2,0x0040b346,0x0041fa2d,0x0043f934, +0x0046cc1c,0x004a9d9d,0x004fae37,0x0056601f, +0x005f4cf7,0x006b6fcf,0x007c7d1e,0x0115b035, +0x013df91b,0x0207655e,0x03342c83,0x0a185230, +0x00404f46,0x0042e13c,0x0048919f,0x0052cb0e, +0x0064e240,0x0107c449,0x015c7926,0x050cf270, +0x004140fb,0x004cf8df,0x0073326c,0x02480d9d, +0x004545ea,0x01273d75,0x005a827a,0x007fffff, +0x006597fb,0x0050a28c,0x00400000,0x0032cbfd, +0x00285146,0x00200000,0x001965ff,0x001428a3, +0x00100000,0x000cb2ff,0x000a1451,0x00080000, +0x00065980,0x00050a29,0x00040000,0x00032cc0, +0x00028514,0x00020000,0x00019660,0x0001428a, +0x00010000,0x0000cb30,0x0000a145,0x00008000, +0x00006598,0x000050a3,0x00004000,0x000032cc, +0x00002851,0x00002000,0x00001966,0x00001429, +0x00001000,0x00000cb3,0x00000a14,0x00000800, +0x00000659,0x0000050a,0x00000400,0x0000032d, +0x00000285,0x00000200,0x00000196,0x00000143, +0x00000100,0x000000cb,0x000000a1,0x00000080, +0x00000066,0x00000051,0x00000040,0x00000033, +0x00000028,0x00000020,0x00000019,0x00000014, +0x00000010,0x0000000d,0x0000000a,0x00000008, +0x00000006,0x00000005,0x00000000,0x00555555, +0x00666666,0x00492492,0x0071c71c,0x00444444, +0x00421084,0x00410410,0x00408102,0x00404040, +0x00402010,0x00401004,0x00400801,0x00400400, +0x00400200,0x00400100,0x00400080,0x00400040, +0x00400000,0x00400000,0x00200000,0x00400000, +0x00100000,0x00080000,0x00040000,0x00020000, +0x00010000,0x00008000,0x00004000,0x00002000, +0x00001000,0x00000800,0x00000400,0x00000200, +0x00000100,0x0003588d,0x0002b15e,0x0002056d, +0x00015600,0x0000a329,0xffffeed9,0xffff3960, +0xfffe8423,0xfffdd11c,0xfffd2048,0xfffc7353, +0xfffbcb6f,0xfffb29a6,0xfffa8f15,0x000494ae, +0x0003f991,0x00032dd1,0xfffd2d8f,0x0001eb47, +0xfffe9968,0x00009af6,0x000011de,0xffff4335, +0x00018d69,0xfffdecd4,0x000302f8,0xfffca0d7, +0x0004683d,0xfffb67f8,0x0005b36d,0x00045963, +0xfffbd51e,0x00030062,0xfffd0dee,0x0001d046, +0xfffe8a0a,0x00009258,0x000012b1,0xffff4d9e, +0x00019ec3,0xfffe0a44,0x0003245a,0xfffcd082, +0x000498f0,0xfffba919,0x0005f304,0x00041bf4, +0xfffba72a,0x0002d19e,0xfffcf060,0x0001b407, +0xfffe7c08,0x0000894a,0x0000138d,0xffff58ac, +0x0001afaf,0xfffe28fe,0x000343bf,0xfffd026f, +0x0004c6f6,0xfffbed06,0x00062e61,0x0003dc0e, +0xfffb7bf1,0x0002a17f,0xfffcd522,0x000196a0, +0xfffe6e70,0x00007ff6,0x00001439,0xffff63f6, +0x0001beb3,0xfffe4882,0x0003616d,0xfffd361b, +0x0004f1cf,0xfffc332a,0x0006658f,0x00039943, +0xfffb52c0,0x00026ec7,0xfffcbb94,0x0001789f, +0xfffe6160,0x00007677,0x000014d4,0xffff6f74, +0x0001cc9b,0xfffe694f,0x00037cbf,0xfffd6b41, +0x000519c2,0xfffc7baf,0x00069971,0x00035486, +0xfffb2d0c,0x00023ad8,0xfffca3ee,0x00015989, +0xfffe55af,0x00006ca7,0x00001570,0xffff7b71, +0x0001d9cb,0xfffe8b46,0x0003959e,0xfffda1fe, +0x00053ee6,0xfffcc6b4,0x0006c950,0x00030e08, +0xfffb0a7a,0x0002061e,0xfffc8ec0,0x00013911, +0xfffe4b1d,0x00006278,0x000015e8,0xffff87b6, +0x0001e577,0xfffeadd6,0x0003acc2,0xfffdda34, +0x00056059,0xfffd136d,0x0006f4b5,0x0002c562, +0xfffaea7c,0x0001cfa6,0xfffc7b14,0x0001182b, +0xfffe4159,0x00005817,0x0000165c,0xffff9417, +0x0001f00f,0xfffed14c,0x0003c199,0xfffe13f6, +0x00057e83,0xfffd61cd,0x00071ba1,0x00027ab5, +0xfffacdc3,0x00019833,0xfffc6989,0x0000f6ca, +0xfffe38da,0x00004d9d,0x000016ef,0xffffa103, +0x0001f98f,0xfffef5c0,0x0003d3d1,0xfffe4f00, +0x0005998c,0xfffdb21e,0x00073e77,0x00022e75, +0xfffab482,0x00015fd1,0xfffc5b13,0x0000d45d, +0xfffe318f,0x000042ed,0x0000176b,0xffffae8f, +0x0002018f,0xffff1a91,0x0003e40c,0xfffe8af2, +0x0005b0ca,0xfffe03b8,0x00075d14,0x0001e141, +0xfffa9e9b,0x0001262a,0xfffc4e31,0x0000b1af, +0xfffe2b26,0x00003805,0x000017b1,0xffffbc21, +0x000208b8,0xffff3fb6,0x0003f1d7,0xfffec7af, +0x0005c4c5,0xfffe5654,0x0007768a,0x000192fe, +0xfffa8bb0,0x0000ec3f,0xfffc4365,0x00008ec9, +0xfffe25f0,0x00002d05,0x000017ec,0xffffc984, +0x00020ec6,0xffff658d,0x0003fcba,0xffff0500, +0x0005d576,0xfffeaa37,0x00078bc6,0x00014367, +0xfffa7bec,0x0000b1f4,0xfffc3b82,0x00006b06, +0xfffe2201,0x000021eb,0x00001823,0xffffd704, +0x0002132a,0xffff8be7,0x00040534,0xffff4315, +0x0005e22e,0xfffeff0a,0x00079ce3,0x0000f33f, +0xfffa6fc9,0x000076ca,0xfffc3558,0x00004762, +0xfffe1ef3,0x000016a1,0x0000183f,0xffffe4a6, +0x00021664,0xffffb27d,0x00040b7b,0xffff81e5, +0x0005eb4e,0xffff5475,0x0007a857,0x0000a2cb, +0xfffa671b,0x00003b64,0xfffc31e2,0x00002416, +0xfffe1ce1,0x00000b46,0x00001850,0xfffff24d, +0x00021855,0xffffd93a,0x00040f75,0xffffc0e6, +0x0005f0e3,0xffffaa3e,0x0007af45,0x0000519f, +0xfffa6218,0x0003f991,0x0003588d,0x0002b15e, +0x0002056d,0x00015600,0x0000a329,0xffffeed9, +0xffff3960,0xfffe8423,0xfffdd11c,0xfffd2048, +0xfffc7353,0xfffbcb6f,0xfffb29a6,0xfffa8f15, +0x000494ae,0x0003c6b0,0xfffc7e8b,0x00028ef6, +0xfffde181,0x000144eb,0xffff5500,0xffffefb9, +0x0000d01d,0xfffe9755,0x000249a4,0xfffd453c, +0x0003b80e,0xfffc01aa,0x000511d6,0xfffad527, +0xfffb334e,0x0003916c,0xfffc5778,0x00026a92, +0xfffdc9f5,0x00013314,0xffff4d99,0xfffff0b6, +0x0000d911,0xfffeab80,0x00026369,0xfffd6c0a, +0x0003e17f,0xfffc39d8,0x000549df,0xfffb1eb2, +0xfffafe6c,0x00035929,0xfffc3321,0x000244a6, +0xfffdb402,0x00012035,0xffff46ac,0xfffff192, +0x0000e16a,0xfffebfe0,0x00027b3d,0xfffd9433, +0x0004087b,0xfffc74b7,0x00057e8d,0xfffb6a81, +0xfffacc1c,0x00031fbe,0xfffc10df,0x00021e0c, +0xfffd9f6d,0x00010cb7,0xffff402e,0xfffff279, +0x0000e965,0xfffed574,0x00029159,0xfffdbdc4, +0x00042c4c,0xfffcb1e7,0x0005b02d,0xfffbb942, +0xfffa9d38,0x0002e44a,0xfffbf0fd,0x0001f5b4, +0xfffd8c38,0x0000f8b1,0xffff3a21,0xfffff391, +0x0000f0e6,0xfffeec44,0x0002a642,0xfffde90e, +0x00044e32,0xfffcf0fb,0x0005de46,0xfffc0b18, +0xfffa71d1,0x0002a659,0xfffbd3de,0x0001cb90, +0xfffd7a97,0x0000e403,0xffff3490,0xfffff49c, +0x0000f7a8,0xffff0340,0x0002b95f,0xfffe1573, +0x00046dbe,0xfffd3284,0x00060888,0xfffc5f51, +0xfffa4996,0x00026786,0xfffbb8df,0x0001a0e1, +0xfffd6a4e,0x0000ced2,0xffff2f75,0xfffff593, +0x0000fdbe,0xffff1a53,0x0002ca87,0xfffe42f5, +0x0004898a,0xfffd7563,0x00062f0b,0xfffcb5de, +0xfffa2508,0x00022713,0xfffba0bf,0x0001754a, +0xfffd5b5f,0x0000b92c,0xffff2acd,0xfffff6b0, +0x0001034f,0xffff3241,0x0002da5c,0xfffe71c6, +0x0004a341,0xfffdb946,0x000651e8,0xfffd0e37, +0xfffa0402,0x0001e4d4,0xfffb8b9c,0x00014898, +0xfffd4e7d,0x0000a304,0xffff26b7,0xfffff7e1, +0x00010846,0xffff4b34,0x0002e897,0xfffea13f, +0x0004ba63,0xfffdff2d,0x00067115,0xfffd6839, +0xfff9e680,0x0001a1fa,0xfffb789e,0x00011b2e, +0xfffd43a4,0x00008c6e,0xffff2341,0xfffff8fd, +0x00010c9c,0xffff6469,0x0002f48f,0xfffed1a4, +0x0004cd6a,0xfffe4608,0x00068c1b,0xfffdc409, +0xfff9cd15,0x00015dfe,0xfffb68a0,0x0000ecee, +0xfffd3a2e,0x0000757d,0xffff204b,0xfffffa1e, +0x00011054,0xffff7da1,0x0002fe9c,0xffff033e, +0x0004de57,0xfffe8dc6,0x0006a2d5,0xfffe213e, +0xfff9b77d,0x000118d3,0xfffb5bde,0x0000be25, +0xfffd3224,0x00005e52,0xffff1dc1,0xfffffb4b, +0x00011353,0xffff9740,0x00030748,0xffff351c, +0x0004ec95,0xfffed755,0x0006b5b4,0xfffe7fc6, +0xfff9a599,0x0000d334,0xfffb519f,0x00008f08, +0xfffd2bbf,0x00004704,0xffff1bc1,0xfffffc71, +0x00011598,0xffffb135,0x00030e43,0xffff6720, +0x0004f6f3,0xffff2119,0x0006c46e,0xfffedf38, +0xfff997c7,0x00008d13,0xfffb4a55,0x00005fa5, +0xfffd273b,0x00002f76,0xffff1a63,0xfffffda0, +0x00011744,0xffffcb67,0x000312ff,0xffff99cf, +0x0004ff0c,0xffff6a9c,0x0006cebd,0xffff3f0a, +0xfff98dbe,0x00004691,0xfffb4620,0x00003010, +0xfffd24fc,0x000017b5,0xffff199d,0xfffffed8, +0x0001185a,0xffffe5c6,0x0003157e,0xffffcce3, +0x000503ae,0xffffb515,0x0006d537,0xffff9f5a, +0xfff98767,0xfffb44b0,0xfffc3131,0xfffd2475, +0xfffe1c28,0xffff195d,0x00001859,0x000118bd, +0x000218df,0x0003163a,0x000410e0,0x000504a7, +0x0005f2b3,0x0006d796,0x0007b1fe,0xfff98537, +0xfffa609b,0xfffc7e8b,0x00028ef6,0xfffde181, +0x000144eb,0xffff5500,0xffffefb9,0x0000d01d, +0xfffe9755,0x000249a4,0xfffd453c,0x0003b80e, +0xfffc01aa,0x000511d6,0xfffad527,0xfffb334e, +0x0003c6b0,0xfffc5778,0x00026a92,0xfffdc9f5, +0x00013314,0xffff4d99,0xfffff0b6,0x0000d911, +0xfffeab80,0x00026369,0xfffd6c0a,0x0003e17f, +0xfffc39d8,0x000549df,0xfffb1eb2,0xfffafe6c, +0x0003916c,0xfffc3321,0x000244a6,0xfffdb402, +0x00012035,0xffff46ac,0xfffff192,0x0000e16a, +0xfffebfe0,0x00027b3d,0xfffd9433,0x0004087b, +0xfffc74b7,0x00057e8d,0xfffb6a81,0xfffacc1c, +0x00035929,0xfffc10df,0x00021e0c,0xfffd9f6d, +0x00010cb7,0xffff402e,0xfffff279,0x0000e965, +0xfffed574,0x00029159,0xfffdbdc4,0x00042c4c, +0xfffcb1e7,0x0005b02d,0xfffbb942,0xfffa9d38, +0x00031fbe,0xfffbf0fd,0x0001f5b4,0xfffd8c38, +0x0000f8b1,0xffff3a21,0xfffff391,0x0000f0e6, +0xfffeec44,0x0002a642,0xfffde90e,0x00044e32, +0xfffcf0fb,0x0005de46,0xfffc0b18,0xfffa71d1, +0x0002e44a,0xfffbd3de,0x0001cb90,0xfffd7a97, +0x0000e403,0xffff3490,0xfffff49c,0x0000f7a8, +0xffff0340,0x0002b95f,0xfffe1573,0x00046dbe, +0xfffd3284,0x00060888,0xfffc5f51,0xfffa4996, +0x0002a659,0xfffbb8df,0x0001a0e1,0xfffd6a4e, +0x0000ced2,0xffff2f75,0xfffff593,0x0000fdbe, +0xffff1a53,0x0002ca87,0xfffe42f5,0x0004898a, +0xfffd7563,0x00062f0b,0xfffcb5de,0xfffa2508, +0x00026786,0xfffba0bf,0x0001754a,0xfffd5b5f, +0x0000b92c,0xffff2acd,0xfffff6b0,0x0001034f, +0xffff3241,0x0002da5c,0xfffe71c6,0x0004a341, +0xfffdb946,0x000651e8,0xfffd0e37,0xfffa0402, +0x00022713,0xfffb8b9c,0x00014898,0xfffd4e7d, +0x0000a304,0xffff26b7,0xfffff7e1,0x00010846, +0xffff4b34,0x0002e897,0xfffea13f,0x0004ba63, +0xfffdff2d,0x00067115,0xfffd6839,0xfff9e680, +0x0001e4d4,0xfffb789e,0x00011b2e,0xfffd43a4, +0x00008c6e,0xffff2341,0xfffff8fd,0x00010c9c, +0xffff6469,0x0002f48f,0xfffed1a4,0x0004cd6a, +0xfffe4608,0x00068c1b,0xfffdc409,0xfff9cd15, +0x0001a1fa,0xfffb68a0,0x0000ecee,0xfffd3a2e, +0x0000757d,0xffff204b,0xfffffa1e,0x00011054, +0xffff7da1,0x0002fe9c,0xffff033e,0x0004de57, +0xfffe8dc6,0x0006a2d5,0xfffe213e,0xfff9b77d, +0x00015dfe,0xfffb5bde,0x0000be25,0xfffd3224, +0x00005e52,0xffff1dc1,0xfffffb4b,0x00011353, +0xffff9740,0x00030748,0xffff351c,0x0004ec95, +0xfffed755,0x0006b5b4,0xfffe7fc6,0xfff9a599, +0x000118d3,0xfffb519f,0x00008f08,0xfffd2bbf, +0x00004704,0xffff1bc1,0xfffffc71,0x00011598, +0xffffb135,0x00030e43,0xffff6720,0x0004f6f3, +0xffff2119,0x0006c46e,0xfffedf38,0xfff997c7, +0x0000d334,0xfffb4a55,0x00005fa5,0xfffd273b, +0x00002f76,0xffff1a63,0xfffffda0,0x00011744, +0xffffcb67,0x000312ff,0xffff99cf,0x0004ff0c, +0xffff6a9c,0x0006cebd,0xffff3f0a,0xfff98dbe, +0x00008d13,0xfffb4620,0x00003010,0xfffd24fc, +0x000017b5,0xffff199d,0xfffffed8,0x0001185a, +0xffffe5c6,0x0003157e,0xffffcce3,0x000503ae, +0xffffb515,0x0006d537,0xffff9f5a,0xfff98767, +0x00004691,0xfffa609b,0xfffb44b0,0xfffc3131, +0xfffd2475,0xfffe1c28,0xffff195d,0x00001859, +0x000118bd,0x000218df,0x0003163a,0x000410e0, +0x000504a7,0x0005f2b3,0x0006d796,0x0007b1fe, +0xfff98537,0xfffbd51e,0x00032dd1,0xfffd2d8f, +0x0001eb47,0xfffe9968,0x00009af6,0x000011de, +0xffff4335,0x00018d69,0xfffdecd4,0x000302f8, +0xfffca0d7,0x0004683d,0xfffb67f8,0x0005b36d, +0x00045963,0xfffba72a,0x00030062,0xfffd0dee, +0x0001d046,0xfffe8a0a,0x00009258,0x000012b1, +0xffff4d9e,0x00019ec3,0xfffe0a44,0x0003245a, +0xfffcd082,0x000498f0,0xfffba919,0x0005f304, +0x00041bf4,0xfffb7bf1,0x0002d19e,0xfffcf060, +0x0001b407,0xfffe7c08,0x0000894a,0x0000138d, +0xffff58ac,0x0001afaf,0xfffe28fe,0x000343bf, +0xfffd026f,0x0004c6f6,0xfffbed06,0x00062e61, +0x0003dc0e,0xfffb52c0,0x0002a17f,0xfffcd522, +0x000196a0,0xfffe6e70,0x00007ff6,0x00001439, +0xffff63f6,0x0001beb3,0xfffe4882,0x0003616d, +0xfffd361b,0x0004f1cf,0xfffc332a,0x0006658f, +0x00039943,0xfffb2d0c,0x00026ec7,0xfffcbb94, +0x0001789f,0xfffe6160,0x00007677,0x000014d4, +0xffff6f74,0x0001cc9b,0xfffe694f,0x00037cbf, +0xfffd6b41,0x000519c2,0xfffc7baf,0x00069971, +0x00035486,0xfffb0a7a,0x00023ad8,0xfffca3ee, +0x00015989,0xfffe55af,0x00006ca7,0x00001570, +0xffff7b71,0x0001d9cb,0xfffe8b46,0x0003959e, +0xfffda1fe,0x00053ee6,0xfffcc6b4,0x0006c950, +0x00030e08,0xfffaea7c,0x0002061e,0xfffc8ec0, +0x00013911,0xfffe4b1d,0x00006278,0x000015e8, +0xffff87b6,0x0001e577,0xfffeadd6,0x0003acc2, +0xfffdda34,0x00056059,0xfffd136d,0x0006f4b5, +0x0002c562,0xfffacdc3,0x0001cfa6,0xfffc7b14, +0x0001182b,0xfffe4159,0x00005817,0x0000165c, +0xffff9417,0x0001f00f,0xfffed14c,0x0003c199, +0xfffe13f6,0x00057e83,0xfffd61cd,0x00071ba1, +0x00027ab5,0xfffab482,0x00019833,0xfffc6989, +0x0000f6ca,0xfffe38da,0x00004d9d,0x000016ef, +0xffffa103,0x0001f98f,0xfffef5c0,0x0003d3d1, +0xfffe4f00,0x0005998c,0xfffdb21e,0x00073e77, +0x00022e75,0xfffa9e9b,0x00015fd1,0xfffc5b13, +0x0000d45d,0xfffe318f,0x000042ed,0x0000176b, +0xffffae8f,0x0002018f,0xffff1a91,0x0003e40c, +0xfffe8af2,0x0005b0ca,0xfffe03b8,0x00075d14, +0x0001e141,0xfffa8bb0,0x0001262a,0xfffc4e31, +0x0000b1af,0xfffe2b26,0x00003805,0x000017b1, +0xffffbc21,0x000208b8,0xffff3fb6,0x0003f1d7, +0xfffec7af,0x0005c4c5,0xfffe5654,0x0007768a, +0x000192fe,0xfffa7bec,0x0000ec3f,0xfffc4365, +0x00008ec9,0xfffe25f0,0x00002d05,0x000017ec, +0xffffc984,0x00020ec6,0xffff658d,0x0003fcba, +0xffff0500,0x0005d576,0xfffeaa37,0x00078bc6, +0x00014367,0xfffa6fc9,0x0000b1f4,0xfffc3b82, +0x00006b06,0xfffe2201,0x000021eb,0x00001823, +0xffffd704,0x0002132a,0xffff8be7,0x00040534, +0xffff4315,0x0005e22e,0xfffeff0a,0x00079ce3, +0x0000f33f,0xfffa671b,0x000076ca,0xfffc3558, +0x00004762,0xfffe1ef3,0x000016a1,0x0000183f, +0xffffe4a6,0x00021664,0xffffb27d,0x00040b7b, +0xffff81e5,0x0005eb4e,0xffff5475,0x0007a857, +0x0000a2cb,0xfffa6218,0x00003b64,0xfffc31e2, +0x00002416,0xfffe1ce1,0x00000b46,0x00001850, +0xfffff24d,0x00021855,0xffffd93a,0x00040f75, +0xffffc0e6,0x0005f0e3,0xffffaa3e,0x0007af45, +0x0000519f,0x00030000,0x000f0007,0x003f001f, +0x00ff007f,0x03ff01ff,0x0fff07ff,0x3fff1fff, +0xffff7fff,0x00030000,0x00070005,0x000f0009, +0x003f001f,0x00ff007f,0x03ff01ff,0x0fff07ff, +0xffff1fff,0x00030000,0x00070005,0x000f0009, +0xffff001f,0x00030000,0xffff0005,0x04030504, +0x08070605,0x0c0b0a09,0x100f0e0d,0x03070504, +0x0605040a,0x0a090807,0x100d0c0b,0x03070503, +0x1005040a,0x10070502,0x03030100,0x03030303, +0x03030303,0x03030303,0x03010100,0x03030301, +0x03030303,0x03030303,0x03010100,0x03030301, +0x03010100,0x04020000,0x08070605,0x0c0b0a09, +0x100f0e0d,0x02010000,0x06050403,0x0a090807, +0x100d0c0b,0x02010000,0x10050403,0x10010000, +0x00030000,0x00090005,0x001f000f,0x007f003f, +0x01ff00ff,0x07ff03ff,0x1fff0fff,0x7fff3fff, +0x00030000,0x00090005,0x001f000f,0x007f003f, +0x0a070504,0x07060504,0x0b0a0908,0x0f0e0d0c, +0x0a070503,0x07060504,0x01010100,0x03030303, +0x03030303,0x03030303,0x01010100,0x03030303, +0x03010000,0x07060504,0x0b0a0908,0x0f0e0d0c, +0x03010000,0x07060504,0x00555555,0x002aaaab, +0x00249249,0x00124925,0x00111111,0x00088889, +0x00084210,0x00421084,0x00041041,0x00020821, +0x00020408,0x00081020,0x00010101,0x00008081, +0x00008040,0x00100804,0x00004010,0x00020080, +0x00002004,0x00004008,0x00001001,0x00000801, +0x00000800,0x00200100,0x00000400,0x00080020, +0x00000200,0x00020004,0x00200000,0x00600040, +0x00a00080,0x00e000c0,0x01200100,0x01600140, +0x01a00180,0x000001c0,0x00300020,0x00400038, +0x00600050,0x00800070,0x00c000a0,0x010000e0, +0x01800140,0x00200000,0x00300028,0x00400038, +0x00600050,0x00800070,0x00c000a0,0x010000e0, +0x00000140,0x00900000,0x00fc00d8,0x01680120, +0x01f801b0,0x02d00240,0x03f00360,0x05a00480, +0x000006c0,0x00680000,0x00b6009c,0x010500d0, +0x016d0139,0x020a01a1,0x02db0272,0x04140343, +0x000004e5,0x006c0000,0x00bd00a2,0x010e00d8, +0x017a0144,0x006301b0,0x013b00cf,0x00c601a7, +0x0000019e,0x00600000,0x00a80090,0x00f000c0, +0x01500120,0x01e00180,0x02a00240,0x03c00300, +0x00000480,0x10000000,0x10101010,0x20101010, +0x20202020,0x20202020,0x28202020,0x28282828, +0x00002828,0x10100000,0x10101010,0x10101010, +0x00000000,0x00000000,0x00000000,0x00000000, +0xcbcecdc4,0xcfcac9c8,0xc3c6c5cc,0xc7c2c1c0, +0x1b1e1d14,0x1f1a1918,0x1316151c,0x17121110, +0x2b2e2d24,0x2f2a2928,0x2326252c,0x27222120, +0x3b3e3d34,0x3f3a3938,0x3336353c,0x37323130, +0x0b0e0d04,0x0f0a0908,0x0306050c,0x07020100, +0xdbdeddd4,0xdfdad9d8,0xd3d6d5dc,0xd7d2d1d0, +0xebeeede4,0xefeae9e8,0xe3e6e5ec,0xe7e2e1e0, +0xfbfefdf4,0xfffaf9f8,0xf3f6f5fc,0xf7f2f1f0, +0x4b4e4d44,0x4f4a4948,0x4346454c,0x47424140, +0x9b9e9d94,0x9f9a9998,0x9396959c,0x97929190, +0xabaeada4,0xafaaa9a8,0xa3a6a5ac,0xa7a2a1a0, +0xbbbebdb4,0xbfbab9b8,0xb3b6b5bc,0xb7b2b1b0, +0x8b8e8d84,0x8f8a8988,0x8386858c,0x87828180, +0x5b5e5d54,0x5f5a5958,0x5356555c,0x57525150, +0x6b6e6d64,0x6f6a6968,0x6366656c,0x67626160, +0x7b7e7d74,0x7f7a7978,0x7376757c,0x77727170, +0x341424c4,0x3e1e2ece,0x3d1d2dcd,0x3b1b2bcb, +0xb494a444,0xbe9eae4e,0xbd9dad4d,0xbb9bab4b, +0xf4d4e404,0xfedeee0e,0xfddded0d,0xfbdbeb0b, +0x74546484,0x7e5e6e8e,0x7d5d6d8d,0x7b5b6b8b, +0x3c1c2ccc,0x361626c6,0x351525c5,0x331323c3, +0xbc9cac4c,0xb696a646,0xb595a545,0xb393a343, +0xfcdcec0c,0xf6d6e606,0xf5d5e505,0xf3d3e303, +0x7c5c6c8c,0x76566686,0x75556585,0x73536383, +0x381828c8,0x3a1a2aca,0x391929c9,0x3f1f2fcf, +0xb898a848,0xba9aaa4a,0xb999a949,0xbf9faf4f, +0xf8d8e808,0xfadaea0a,0xf9d9e909,0xffdfef0f, +0x78586888,0x7a5a6a8a,0x79596989,0x7f5f6f8f, +0x301020c0,0x321222c2,0x311121c1,0x371727c7, +0xb090a040,0xb292a242,0xb191a141,0xb797a747, +0xf0d0e000,0xf2d2e202,0xf1d1e101,0xf7d7e707, +0x70506080,0x72526282,0x71516181,0x77576787, +0x05040100,0x15141110,0x25242120,0x35343130, +0x85848180,0x95949190,0xa5a4a1a0,0xb5b4b1b0, +0xc0408000,0xe060a020,0xd0509010,0xf070b030, +0xc8488808,0xe868a828,0xd8589818,0xf878b838, +0xc4448404,0xe464a424,0xd4549414,0xf474b434, +0xcc4c8c0c,0xec6cac2c,0xdc5c9c1c,0xfc7cbc3c, +0xc2428202,0xe262a222,0xd2529212,0xf272b232, +0xca4a8a0a,0xea6aaa2a,0xda5a9a1a,0xfa7aba3a, +0xc6468606,0xe666a626,0xd6569616,0xf676b636, +0xce4e8e0e,0xee6eae2e,0xde5e9e1e,0xfe7ebe3e, +0xc1418101,0xe161a121,0xd1519111,0xf171b131, +0xc9498909,0xe969a929,0xd9599919,0xf979b939, +0xc5458505,0xe565a525,0xd5559515,0xf575b535, +0xcd4d8d0d,0xed6dad2d,0xdd5d9d1d,0xfd7dbd3d, +0xc3438303,0xe363a323,0xd3539313,0xf373b333, +0xcb4b8b0b,0xeb6bab2b,0xdb5b9b1b,0xfb7bbb3b, +0xc7478707,0xe767a727,0xd7579717,0xf777b737, +0xcf4f8f0f,0xef6faf2f,0xdf5f9f1f,0xff7fbf3f, +0x1045a3e2,0x000000f4,0x263b7333,0x766b2363, +0x2b367e3e,0x7b662e6e,0x06db93d3,0x964b0343, +0x0bd69ede,0x9b460e4e,0x825f1757,0x12cf87c7, +0x8f521a5a,0x1fc28aca,0x00d199d9,0x90410949, +0x01d098d8,0x91400848,0x24357d3d,0x74652d6d, +0x25347c3c,0x75642c6c,0x04d59ddd,0x94450d4d, +0x05d49cdc,0x95440c4c,0x80511959,0x10c189c9, +0x81501858,0x11c088c8,0x02df97d7,0x924f0747, +0x0fd29ada,0x9f420a4a,0x865b1353,0x16cb83c3, +0x8b561e5e,0x1bc68ece,0xa6bbf3b3,0xf6eba3e3, +0xabb6febe,0xfbe6aeee,0x223f7737,0x726f2767, +0x2f327a3a,0x7f622a6a,0xa0b1f9b9,0xf0e1a9e9, +0xa1b0f8b8,0xf1e0a8e8,0x84551d5d,0x14c58dcd, +0x85541c5c,0x15c48ccc,0xa4b5fdbd,0xf4e5aded, +0xa5b4fcbc,0xf5e4acec,0x20317939,0x70612969, +0x21307838,0x71602868,0xa2bff7b7,0xf2efa7e7, +0xafb2faba,0xffe2aaea,0x00000000,0x00000000, + +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/pcm_240.h linux.20pre2-ac1/drivers/media/video/ls220/pcm_240.h --- linux.20pre2/drivers/media/video/ls220/pcm_240.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/pcm_240.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,868 @@ +static u32 PCM240Ucode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb50001fb, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x029f9014, 0x829efef0, + 0x8286000f, 0x02bf0054, 0x82bcfef4, 0x82a6000e, + 0x80074000, 0x001f6193, 0x8013001f, 0x9020c000, + 0x003fb006, 0x803effe8, 0x803effec, 0x9020fa00, + 0x803effd0, 0x803effdc, 0x803effd8, 0x9020fe00, + 0x803effd4, 0x90400000, 0x804600a2, 0x90421800, + 0x804600a3, 0x80132000, 0x98000040, 0x800600a6, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x80070000, 0x001f23f9, 0x801e4b0c, + 0x001f210c, 0x80070001, 0x001f2324, 0x80070800, + 0x001f600f, 0x001fb0cb, 0x001fb010, 0x801efff0, + 0x98004000, 0x001f600e, 0x83e4011b, 0x80070000, + 0x801e4b14, 0x800500a0, 0xb0000001, 0xb4000009, + 0x80070001, 0x800600a0, 0x80050080, 0x98000020, + 0x80060080, 0x9400ffdf, 0x80060080, 0x80070000, + 0x800600a0, 0x80074000, 0x801e4b04, 0x81df0004, + 0x801bfff0, 0x00000000, 0x940000ff, 0xb0000000, + 0xb4200033, 0x003f400e, 0x94010010, 0xb0000000, + 0xb400fff7, 0x003f0013, 0xb0010001, 0xb420001f, + 0x803bffe8, 0x801bffec, 0x805b4b04, 0x00000000, + 0x3001b800, 0xb4600001, 0x9021a000, 0x0421b800, + 0x3001b802, 0xb460000d, 0x80050086, 0x005f9044, + 0x0420b802, 0xb00101e0, 0xb4a0ffe5, 0x001fb010, + 0x001f010c, 0xb0000001, 0xb400ffe1, 0x80070001, + 0x001f210c, 0x83e400e8, 0xb500ffdd, 0x8007001f, + 0x94000003, 0x5810b800, 0x83e719ec, 0x1bffb800, + 0x003f9008, 0x1821b800, 0x00ffb801, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671a14, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0x80070000, 0x001f210c, 0xb500ffc8, + 0x003f400e, 0xb0000086, 0xb4400051, 0xb0000084, + 0xb400003b, 0xb0000085, 0xb4000041, 0xb0000086, + 0xb4000043, 0xb0000083, 0xb4000000, 0x815bff7c, + 0x00000000, 0x940a0080, 0x5c07b800, 0xb0000001, + 0xb400006f, 0x81674b18, 0x940a0007, 0x5803b800, + 0x116bb800, 0x005bb80b, 0x916b0004, 0x001bb80b, + 0x806500d4, 0x1463b800, 0x1863b802, 0x806600d4, + 0x80073c21, 0x801e4b00, 0x800600a1, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x8013007f, + 0x9800ffff, 0x001fb040, 0x80070001, 0x001f2013, + 0x80070000, 0x001f2324, 0x001fb0cb, 0x001fb010, + 0x001fb041, 0x001fb042, 0x80073370, 0x001fb008, + 0x80071e40, 0x001fb009, 0x98214000, 0xb5000010, + 0x94011000, 0xb0001000, 0xb4200001, 0x9421efff, + 0x98210010, 0xb500000a, 0x80070000, 0x001fb0cb, + 0x83e40099, 0x003f400e, 0x9421ffef, 0xb5000004, + 0x83e40095, 0x003f400e, 0x98211000, 0x9421ffef, + 0x003f600e, 0x80070100, 0x801efff0, 0xb500ff74, + 0xb000008b, 0xb4000018, 0xb0000087, 0xb400ffee, + 0xb0000088, 0xb4000016, 0xb000008a, 0xb4000016, + 0xb000008c, 0xb4000017, 0xb0000089, 0xb4000019, + 0xb00000a0, 0xb400001b, 0xb00000a1, 0xb4000047, + 0xb00000a2, 0xb4000054, 0xb00000a3, 0xb400004c, + 0xb00000a4, 0xb4000056, 0xb00000a5, 0xb400005a, + 0xb00000a6, 0xb400005e, 0x803efff8, 0xb500ffe1, + 0x9421ffdf, 0xb500ffde, 0x80270100, 0x803efff8, + 0xb500ffdc, 0x803bffb0, 0x00000000, 0x003fb040, + 0xb500ffd8, 0x803bff80, 0x00000000, 0x003f6001, + 0xb500ffd4, 0x003f90ba, 0x803efff8, 0xb500ffd1, + 0x81674b18, 0x940a0007, 0x5803b800, 0x116bb800, + 0x005bb80b, 0x916b0004, 0x001bb80b, 0x806500d4, + 0x1463b800, 0x1863b802, 0x806600d4, 0x80130001, + 0x98003d21, 0x800600a1, 0x801e4b00, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x80070001, + 0x001f2013, 0x80070000, 0x001f2324, 0x001fb0cb, + 0x001fb010, 0x80073b60, 0x001fb008, 0x80074350, + 0x001fb009, 0x98214000, 0xb500ffa5, 0x80270000, + 0x8047fef0, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x81df0000, 0x00000000, 0x00000000, 0x83640443, + 0x81df0004, 0xb500ff97, 0x81df0000, 0x00000000, + 0x00000000, 0x836403ed, 0x81df0004, 0xb500ff91, + 0x81df0000, 0x00000000, 0x00000000, 0x836403a8, + 0x81df0004, 0xb500ff8b, 0x81df0000, 0x00000000, + 0x00000000, 0x8344030b, 0x81df0004, 0xb500ff85, + 0x81df0000, 0x00000000, 0x00000000, 0x834402f0, + 0x81df0004, 0xb500ff7f, 0x80070000, 0x80470000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002003, + 0xb6003002, 0x001eb802, 0x90420004, 0x80171000, + 0x8057ffff, 0xb6002002, 0xb6001801, 0x001fa020, + 0x81df0004, 0x00ffb81f, 0x83a70000, 0x8057ffff, + 0x80770000, 0x8073007d, 0x98636d4a, 0x0207b803, + 0x81df0000, 0x00000000, 0x00000000, 0x80171000, + 0xb6000007, 0x003fc020, 0x005fc7e0, 0x40c1b810, + 0x4102b810, 0x001fe026, 0x001fe0a8, 0x4210b803, + 0x81df0004, 0x80270000, 0x003f2013, 0x8007001f, + 0x94000003, 0x5810b800, 0x83671e1c, 0x1b7bb800, + 0x003f9009, 0x1821b800, 0x00ffb801, 0x003f0013, + 0xb0010001, 0xb420fff3, 0x93bd0001, 0xb01d0004, + 0xb480ffe3, 0x00ffb81f, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717f4, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00060, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x83840266, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6001811, 0xb6002010, 0x14618000, + 0x6068b803, 0x40c4b803, 0x14608000, 0x00c8b806, + 0x5870b803, 0x6068b803, 0x4104b803, 0x58c8b806, + 0x0108b808, 0x14c6b801, 0x00000000, 0x00000000, + 0x5d08b808, 0x1508b800, 0x1806a028, 0x81df0004, + 0x80670400, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x808f0000, 0x801b4b14, 0x80270001, + 0xb0000001, 0xb4000002, 0x802600a0, 0x803e4b14, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813e4b0c, 0x80270001, 0x003f2013, 0x80050086, + 0x001fb044, 0x00ffb81b, 0x00000000, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009d, 0x82b30002, 0x9ab50040, + 0x1a94b815, 0x8286009d, 0x8285009c, 0x96b48000, + 0xb0158000, 0xb400019c, 0x96b40100, 0xb0150100, + 0xb40001b8, 0x96b40400, 0xb0150400, 0xb40001ca, + 0x96b40001, 0xb0150001, 0xb4000014, 0x96b40008, + 0xb0150008, 0xb40001a5, 0x96b44000, 0xb0154000, + 0xb40001c9, 0x96b40002, 0xb0150002, 0xb4000169, + 0x96b40040, 0xb0150040, 0xb40001dc, 0x82d30002, + 0x9ad60000, 0x16b6b814, 0x3015b816, 0xb40001da, + 0x00000000, 0x00000000, 0xb50001db, 0x02bf9017, + 0x92b50001, 0x02bfb017, 0x82850082, 0x83050081, + 0x82a5009a, 0x96b50001, 0xb0150001, 0xb4200014, + 0x82a70000, 0x02bfb017, 0x96b41840, 0xb0150800, + 0xb420000c, 0x96b40008, 0x5aa9b815, 0x96d46000, + 0x5ec3b816, 0x82f3000f, 0x9af7c00f, 0x1718b817, + 0x1ab5b818, 0x1ab5b816, 0x9ab50340, 0x82a60081, + 0xb5000140, 0x9b180180, 0x83060081, 0xb500013d, + 0x82a5009a, 0x96b50002, 0xb0150002, 0xb420001b, + 0x82a70000, 0x02bfb017, 0x96b41800, 0xb0151800, + 0xb4000013, 0x96b40040, 0xb0150040, 0xb4200004, + 0xa3180c00, 0x9b180340, 0x83060081, 0xb500012d, + 0x96b40008, 0x5aa9b815, 0x96d46000, 0x5ec3b816, + 0x82f3000f, 0x9af7c00f, 0x1718b817, 0x1ab5b818, + 0x1ab5b816, 0x9ab50340, 0x82a60081, 0xb5000121, + 0x9b180180, 0x83060081, 0xb500011e, 0x82a500c1, + 0x96b5000f, 0xb015000b, 0xb420000e, 0x96b40020, + 0xb0150020, 0xb400000b, 0x96b40200, 0xb0150200, + 0xb4000008, 0x82c50086, 0x82e50094, 0x3016b817, + 0xb4400004, 0x06f7b816, 0xb017ff00, 0xb4400001, + 0xb500010c, 0x96b46000, 0xb0156000, 0xb4000011, + 0x96b41820, 0xb0150820, 0xb4200004, 0x9b391000, + 0x82a5009a, 0x96b5feff, 0x82a6009a, 0x96b40040, + 0xb0150040, 0xb4200001, 0x9739efff, 0x96b91000, + 0xb0151000, 0xb4200003, 0x82a5009a, 0x9ab50100, + 0x82a6009a, 0x96b40040, 0xb0150040, 0xb4200019, + 0x96b41800, 0xb0151800, 0xb4200006, 0x96b98000, + 0xb0158000, 0xb4200003, 0x9b180180, 0x83060081, + 0xb50000ec, 0x96d80c00, 0x82b300ff, 0x9ab5f3ff, + 0x1718b815, 0xb0160c00, 0xb4000007, 0x82e50098, + 0x96f70400, 0xb0170400, 0xb4200002, 0x82c70c00, + 0xb5000001, 0xa2d60c00, 0x1b18b816, 0x9b180340, + 0xb50000d2, 0x96b40220, 0xb0150000, 0xb4e00033, + 0x82a5009d, 0x82f3ffff, 0x16b5b817, 0x82f33802, + 0x3015b817, 0xb420002d, 0x96f98000, 0xb0178000, + 0xb400002a, 0x82a70000, 0x02bfb017, 0x82c50081, + 0x9ab60020, 0x82a60081, 0x82a50086, 0x92b50bb8, + 0x82a60094, 0x82c60081, 0x82c5009d, 0x96d6ffff, + 0x82b3c802, 0x9ab50041, 0x82e500c1, 0x96f7000f, + 0xb017000b, 0xb4000002, 0x82b38802, 0x9ab50041, + 0x1ab5b816, 0x82c5009a, 0x96d60020, 0xb0160020, + 0xb4200002, 0x82b3c802, 0x9ab50041, 0x82a6009d, + 0x02ff9017, 0x00000000, 0xb0170040, 0xb480000b, + 0x96f41c00, 0xb0171c00, 0xb4200008, 0x82e50086, + 0x82c50094, 0x92d63000, 0x3016b817, 0xb4400003, + 0x9b180180, 0x83060081, 0xb50000a6, 0x5eb5b814, + 0x96b500f0, 0x96f46000, 0x5eedb817, 0x1ab5b817, + 0xb0170003, 0xb4000004, 0x96b500ef, 0x96f70001, + 0x5ae4b817, 0x1ab5b817, 0x96d41800, 0xb0161800, + 0xb400000a, 0x96f900ff, 0x96b500ff, 0x9739ff00, + 0x1b39b815, 0x02a7b817, 0x96b500f3, 0x96d40008, + 0x5ec1b816, 0x1ab5b816, 0xb500000c, 0x96f98000, + 0xb0178000, 0xb4200007, 0x5efeb814, 0x96f70001, + 0xb0170001, 0xb4000003, 0x9b180180, 0x83060081, + 0xb5000084, 0x96b500f3, 0x9ab50008, 0x9739fff3, + 0x96d40020, 0xb0160020, 0xb4200017, 0x9b398000, + 0x82c70000, 0x02dfb017, 0x96d40010, 0x5ac8b816, + 0x82f300ff, 0x9af7cfff, 0x1718b817, 0x1b18b816, + 0x9b180340, 0x82c5009d, 0x96d6ffff, 0x82f33802, + 0x9af70041, 0x1af7b816, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82f3c802, 0x9af70041, + 0x82e6009d, 0xb500005d, 0x97397fff, 0x96b500ff, + 0x5aaab815, 0x82f300fc, 0x9af703ff, 0x1718b817, + 0x1b18b815, 0x9b180340, 0x82c5009a, 0x96d60010, + 0xb0160010, 0xb4200024, 0x82c70000, 0x02dfb017, + 0x82c50086, 0x92d60bb8, 0x82c60086, 0x82c50094, + 0x5eefb818, 0x96f70003, 0xb0170003, 0xb4200002, + 0x82e70bb8, 0xb5000001, 0x82e70bb8, 0x12d6b817, + 0x82e50081, 0x9af70020, 0x82e60081, 0x82c60094, + 0xa2f70020, 0x82e60081, 0x82f30001, 0x16f7b818, + 0x5ef0b817, 0xb0170001, 0xb4000004, 0x96f84000, + 0x5ee4b817, 0x9718f3ff, 0x1b18b817, 0x82f32802, + 0x9af70040, 0x82e6009d, 0x83060081, 0x83070001, + 0x8306009f, 0xb50000b8, 0x82c5009d, 0x82f33802, + 0x9af70041, 0x3016b817, 0xb420000f, 0x82b3c802, + 0x9ab50041, 0x82e500c1, 0x96f7000f, 0xb017000b, + 0xb4000002, 0x82b38802, 0x9ab50041, 0x82c5009a, + 0x96d60020, 0xb0160020, 0xb4200002, 0x82b3c802, + 0x9ab50041, 0x82a6009d, 0x82c5009a, 0x96d60080, + 0xb0160080, 0xb4000014, 0x02df9017, 0x00000000, + 0xb0160010, 0xb4800010, 0x82c500c1, 0x96d6000f, + 0xb016000b, 0xb400000c, 0x82c50087, 0x96d60080, + 0x5ac7b816, 0x82c50098, 0x96d60800, 0x5ac3b816, + 0x96f84000, 0x3017b816, 0xb4200003, 0x033f400f, + 0x9b394000, 0xb500000b, 0x9739bfff, 0x82e50061, + 0x96f70008, 0xb0170008, 0xb4000005, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4000001, 0x9718ffff, + 0x83060081, 0x83070001, 0x8306009f, 0x00000000, + 0xb500007d, 0x82850083, 0x96b400ff, 0xb015003c, + 0xb4200019, 0x96b92000, 0xb0152000, 0xb4000002, + 0x9b392000, 0xb5000014, 0x9739d3ff, 0x82870000, + 0x82860087, 0x82870008, 0x82860083, 0x829bff78, + 0x82a7001f, 0xb0140400, 0xb4000001, 0x82a70010, + 0x82a600c9, 0x829bff78, 0x00000000, 0x828600cb, + 0x8285009d, 0x82b3ffff, 0x9ab5fffd, 0x1694b815, + 0x8286009d, 0xb5000000, 0x83070002, 0x8306009f, + 0x00000000, 0xb500005c, 0x96b90800, 0xb0150800, + 0xb4200009, 0x9739f7ff, 0x82a703fd, 0x82a600cb, + 0x82a7003c, 0x82a60083, 0x8285009d, 0x9a940002, + 0x8286009d, 0xb5000004, 0x82850087, 0x5a82b814, + 0xa2940200, 0x82860087, 0xb5000000, 0x83078000, + 0x8306009f, 0x00000000, 0xb5000047, 0x82850086, + 0x82a50094, 0x3015b814, 0xb4800002, 0x86b50bb8, + 0x82a60086, 0x83070008, 0x8306009f, 0x00000000, + 0xb500003d, 0x83050069, 0x9718003f, 0x82e50064, + 0x12f7b818, 0x86f70088, 0x82feff74, 0x02e7b86f, + 0x9af74000, 0x01ffb817, 0x96f7bfff, 0x01ffb817, + 0x83050081, 0x82f3001c, 0x9af703ff, 0x1718b817, + 0x9b180140, 0x83060081, 0x83070100, 0x8306009f, + 0x00000000, 0xb5000028, 0x83070000, 0x83050081, + 0x9b180180, 0x83060081, 0x83070400, 0x8306009f, + 0x00000000, 0xb5000020, 0x82870000, 0x82850082, + 0x5eb7b814, 0x96b500fc, 0x96d40006, 0x5ec1b816, + 0x1ab5b816, 0x5aacb815, 0x83050081, 0x82d3001c, + 0x9ad600ff, 0x1718b816, 0x1b18b815, 0x9b180e00, + 0x83060081, 0x83074000, 0x8306009f, 0x8305009d, + 0x82d3ffff, 0x9ad6bfff, 0x1718b816, 0x8306009d, + 0x00000000, 0xb5000008, 0xb5000007, 0x83070040, + 0x8306009f, 0xb5000004, 0x83130002, 0x9b180000, + 0x8306009f, 0xb5000000, 0x029f9005, 0x01ffb814, + 0x033f600f, 0x029f900a, 0x02bf900b, 0x02df900c, + 0x02ff900d, 0x031f900e, 0x033f900f, 0x00ffb81e, + 0x02ff9010, 0x92f70b43, 0x02ffb010, 0x02ff90cb, + 0x82bbffdc, 0x829bffd8, 0x93150004, 0x3014b815, + 0xb4000010, 0x02dbb818, 0x029bb815, 0x3017b816, + 0xb480000c, 0x5a81b814, 0x029fb010, 0x82860095, + 0x8293001f, 0x9294fe00, 0x92b50008, 0x3015b814, + 0xb4800002, 0x82b3001f, 0x92b5fa00, 0x82beffdc, + 0xb500ffeb, 0x029f9010, 0x83250094, 0x06d4b819, + 0x02d6b816, 0xb016ffff, 0xb4a0000a, 0x82933802, + 0x9a940041, 0x82c5009d, 0x96d6ffff, 0x1a94b816, + 0x82c5009a, 0x96d60010, 0xb0160010, 0xb4000001, + 0x8286009d, 0x00ffb81c, 0x00000000, 0x00000000, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x803bff68, 0x8078ff6c, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x803bff68, + 0x8078ff6c, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x83840126, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e70228, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x80270180, 0x81e70120, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801b0220, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x80180224, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x819eff68, 0x817cff6c, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801b0220, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x80180224, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801b0220, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x80180224, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e7ff00, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270240, + 0x81e70000, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e70120, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x806f0007, + 0x80af0007, 0x80270280, 0x81e70100, 0x5de2b80f, + 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, + 0x01ff90bc, 0xb520ffff, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x829bff80, 0x80af001f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60020, 0x90210020, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6002005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb400008e, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb400001c, 0xb00a0003, + 0xb4000024, 0xb00a0004, 0xb4000052, 0xb00a0005, + 0xb400005b, 0xb00a0006, 0xb400007f, 0xb00a0007, + 0xb400007d, 0xb00a0008, 0xb400007b, 0x81df0000, + 0x00000000, 0x00000000, 0xb600800a, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x5c708028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x81df0004, 0xb500006b, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008004, 0x007f8028, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a400fa, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a400e5, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400d2, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6004005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a400cd, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a400b7, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x00000000, 0x00000000, + 0xb5000086, 0xb00a0001, 0xb400000e, 0xb00a0002, + 0xb4000017, 0xb00a0003, 0xb400001f, 0xb00a0004, + 0xb400004d, 0xb00a0005, 0xb4000056, 0xb00a0006, + 0xb400007a, 0xb00a0007, 0xb4000078, 0xb00a0008, + 0xb4000076, 0x81df0000, 0x00000000, 0x00000000, + 0xb6008005, 0x007f8028, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb500006b, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004004, + 0x007f8048, 0x019fa023, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000061, 0xb0130000, 0xb4000004, + 0xb0130001, 0xb4000009, 0xb0130002, 0xb400001a, + 0x83a40098, 0x80170f00, 0x007f8028, 0x001fa023, + 0x007f8028, 0x001fa023, 0xb5000054, 0x80170f00, + 0x00000000, 0x007f8020, 0x019fa023, 0x007f8000, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x83a40083, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000041, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40070, 0xb5000031, 0x81df0000, 0x00000000, + 0x00000000, 0xb6004005, 0x007f8008, 0x019fa023, + 0x007f8008, 0x019fa023, 0x019fa020, 0x81df0004, + 0xb5000026, 0xb0130000, 0xb4000008, 0xb0130001, + 0xb4000012, 0xb0130002, 0xb400001f, 0xb0130003, + 0xb400001d, 0xb0130004, 0xb400001b, 0x83a4006b, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x80170f00, + 0x007f8028, 0x001fa023, 0xb5000010, 0x80170f00, + 0x00000000, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x83a40055, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000001, 0xb5000000, 0x92730001, + 0x92520001, 0x3012b811, 0xb480fe89, 0x003f0324, + 0x90210001, 0xb0010006, 0xb4a00001, 0x80270001, + 0x003f2324, 0x2c8db811, 0x803bffe0, 0x805bffe4, + 0x5887b804, 0x1015b804, 0xad440003, 0x3000b802, + 0xb4800001, 0x8400a000, 0x801effec, 0x015f6193, + 0x809e4b04, 0x00ffb81f, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002a0c, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb600190f, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x81df0004, + 0x00ffb81d, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x829bff80, 0x80af001f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60020, 0x90210020, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6002005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb400008e, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb400001c, 0xb00a0003, + 0xb4000024, 0xb00a0004, 0xb4000052, 0xb00a0005, + 0xb400005b, 0xb00a0006, 0xb400007f, 0xb00a0007, + 0xb400007d, 0xb00a0008, 0xb400007b, 0x81df0000, + 0x00000000, 0x00000000, 0xb600800a, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x5c708028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x81df0004, 0xb500006b, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008004, 0x007f8028, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a400fa, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a400e5, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400d2, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6004005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a400cd, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a400b7, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x00000000, 0x00000000, + 0xb5000086, 0xb00a0001, 0xb400000e, 0xb00a0002, + 0xb4000017, 0xb00a0003, 0xb400001f, 0xb00a0004, + 0xb400004d, 0xb00a0005, 0xb4000056, 0xb00a0006, + 0xb400007a, 0xb00a0007, 0xb4000078, 0xb00a0008, + 0xb4000076, 0x81df0000, 0x00000000, 0x00000000, + 0xb6008005, 0x007f8028, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb500006b, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004004, + 0x007f8048, 0x019fa023, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000061, 0xb0130000, 0xb4000004, + 0xb0130001, 0xb4000009, 0xb0130002, 0xb400001a, + 0x83a40098, 0x80170f00, 0x007f8028, 0x001fa023, + 0x007f8028, 0x001fa023, 0xb5000054, 0x80170f00, + 0x00000000, 0x007f8020, 0x019fa023, 0x007f8000, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x83a40083, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000041, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40070, 0xb5000031, 0x81df0000, 0x00000000, + 0x00000000, 0xb6004005, 0x007f8008, 0x019fa023, + 0x007f8008, 0x019fa023, 0x019fa020, 0x81df0004, + 0xb5000026, 0xb0130000, 0xb4000008, 0xb0130001, + 0xb4000012, 0xb0130002, 0xb400001f, 0xb0130003, + 0xb400001d, 0xb0130004, 0xb400001b, 0x83a4006b, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x80170f00, + 0x007f8028, 0x001fa023, 0xb5000010, 0x80170f00, + 0x00000000, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x83a40055, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000001, 0xb5000000, 0x92730001, + 0x92520001, 0x3012b811, 0xb480fe89, 0x003f0324, + 0x90210001, 0xb0010006, 0xb4a00001, 0x80270001, + 0x003f2324, 0x2c8db811, 0x803bffe0, 0x805bffe4, + 0x5887b804, 0x1015b804, 0xad440003, 0x3000b802, + 0xb4800001, 0x8400a000, 0x801effec, 0x015f6193, + 0x809e4b04, 0x00ffb81f, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002a0c, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb600190f, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x81df0004, + 0x00ffb81d, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717f4, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00060, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x8384f922, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6001811, 0xb6002010, 0x14618000, + 0x6068b803, 0x40c4b803, 0x14608000, 0x00c8b806, + 0x5870b803, 0x6068b803, 0x4104b803, 0x58c8b806, + 0x0108b808, 0x14c6b801, 0x00000000, 0x00000000, + 0x5d08b808, 0x1508b800, 0x1806a028, 0x81df0004, + 0x80670400, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x808f0000, 0x801b4b14, 0x80270001, + 0xb0000001, 0xb4000002, 0x802600a0, 0x803e4b14, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813e4b0c, 0x80270001, 0x003f2013, 0x80050086, + 0x001fb044, 0x00ffb81b, 0x00000000, 0x00000000, +}; + +static u32 PCM240Ucode1f4b00[] = { + 0x00000000, 0x00000000, 0x00060504, 0x00000000, + 0x00000000, 0x00000000, 0x00300000, 0xffcfcfff, + 0x00302000, 0xffcfcfff, 0x00380000, 0xffc7c7ff, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; + +static u32 PCM240Ucode1fff00[] = { + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/pcm.h linux.20pre2-ac1/drivers/media/video/ls220/pcm.h --- linux.20pre2/drivers/media/video/ls220/pcm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/pcm.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,792 @@ +static u32 PCMUcode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb50001fb, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x029f9014, 0x829efef0, + 0x8286000f, 0x02bf0054, 0x82bcfef4, 0x82a6000e, + 0x80074000, 0x001f6193, 0x8013001f, 0x9020c000, + 0x003fb006, 0x803effe8, 0x803effec, 0x9020fa00, + 0x803effd0, 0x803effdc, 0x803effd8, 0x9020fe00, + 0x803effd4, 0x90400000, 0x804600a2, 0x90421800, + 0x804600a3, 0x80132000, 0x98000040, 0x800600a6, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x80070000, 0x001f23f9, 0x801e4b0c, + 0x001f210c, 0x80070001, 0x001f2324, 0x80070800, + 0x001f600f, 0x001fb0cb, 0x001fb010, 0x801efff0, + 0x98004000, 0x001f600e, 0x83e4011b, 0x80070000, + 0x801e4b14, 0x800500a0, 0xb0000001, 0xb4000009, + 0x80070001, 0x800600a0, 0x80050080, 0x98000020, + 0x80060080, 0x9400ffdf, 0x80060080, 0x80070000, + 0x800600a0, 0x80074000, 0x801e4b04, 0x81df0004, + 0x801bfff0, 0x00000000, 0x940000ff, 0xb0000000, + 0xb4200033, 0x003f400e, 0x94010010, 0xb0000000, + 0xb400fff7, 0x003f0013, 0xb0010001, 0xb420001f, + 0x803bffe8, 0x801bffec, 0x805b4b04, 0x00000000, + 0x3001b800, 0xb4600001, 0x9021a000, 0x0421b800, + 0x3001b802, 0xb460000d, 0x80050086, 0x005f9044, + 0x0420b802, 0xb00101e0, 0xb4a0ffe5, 0x001fb010, + 0x001f010c, 0xb0000001, 0xb400ffe1, 0x80070001, + 0x001f210c, 0x83e400e8, 0xb500ffdd, 0x8007001f, + 0x94000003, 0x5810b800, 0x83e719ec, 0x1bffb800, + 0x003f9008, 0x1821b800, 0x00ffb801, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671a14, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0x80070000, 0x001f210c, 0xb500ffc8, + 0x003f400e, 0xb0000086, 0xb4400051, 0xb0000084, + 0xb400003b, 0xb0000085, 0xb4000041, 0xb0000086, + 0xb4000043, 0xb0000083, 0xb4000000, 0x815bff7c, + 0x00000000, 0x940a0080, 0x5c07b800, 0xb0000001, + 0xb400006f, 0x81674b18, 0x940a0007, 0x5803b800, + 0x116bb800, 0x005bb80b, 0x916b0004, 0x001bb80b, + 0x806500d4, 0x1463b800, 0x1863b802, 0x806600d4, + 0x80073c21, 0x801e4b00, 0x800600a1, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x8013007f, + 0x9800ffff, 0x001fb040, 0x80070001, 0x001f2013, + 0x80070000, 0x001f2324, 0x001fb0cb, 0x001fb010, + 0x001fb041, 0x001fb042, 0x80073310, 0x001fb008, + 0x80071e40, 0x001fb009, 0x98214000, 0xb5000010, + 0x94011000, 0xb0001000, 0xb4200001, 0x9421efff, + 0x98210010, 0xb500000a, 0x80070000, 0x001fb0cb, + 0x83e40099, 0x003f400e, 0x9421ffef, 0xb5000004, + 0x83e40095, 0x003f400e, 0x98211000, 0x9421ffef, + 0x003f600e, 0x80070100, 0x801efff0, 0xb500ff74, + 0xb000008b, 0xb4000018, 0xb0000087, 0xb400ffee, + 0xb0000088, 0xb4000016, 0xb000008a, 0xb4000016, + 0xb000008c, 0xb4000017, 0xb0000089, 0xb4000019, + 0xb00000a0, 0xb400001b, 0xb00000a1, 0xb4000047, + 0xb00000a2, 0xb4000054, 0xb00000a3, 0xb400004c, + 0xb00000a4, 0xb4000056, 0xb00000a5, 0xb400005a, + 0xb00000a6, 0xb400005e, 0x803efff8, 0xb500ffe1, + 0x9421ffdf, 0xb500ffde, 0x80270100, 0x803efff8, + 0xb500ffdc, 0x803bffb0, 0x00000000, 0x003fb040, + 0xb500ffd8, 0x803bff80, 0x00000000, 0x003f6001, + 0xb500ffd4, 0x003f90ba, 0x803efff8, 0xb500ffd1, + 0x81674b18, 0x940a0007, 0x5803b800, 0x116bb800, + 0x005bb80b, 0x916b0004, 0x001bb80b, 0x806500d4, + 0x1463b800, 0x1863b802, 0x806600d4, 0x80130001, + 0x98003d21, 0x800600a1, 0x801e4b00, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x80070001, + 0x001f2013, 0x80070000, 0x001f2324, 0x001fb0cb, + 0x001fb010, 0x80073b00, 0x001fb008, 0x800742f0, + 0x001fb009, 0x98214000, 0xb500ffa5, 0x80270000, + 0x8047fef0, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x81df0000, 0x00000000, 0x00000000, 0x8364042b, + 0x81df0004, 0xb500ff97, 0x81df0000, 0x00000000, + 0x00000000, 0x836403d5, 0x81df0004, 0xb500ff91, + 0x81df0000, 0x00000000, 0x00000000, 0x83640390, + 0x81df0004, 0xb500ff8b, 0x81df0000, 0x00000000, + 0x00000000, 0x834402f3, 0x81df0004, 0xb500ff85, + 0x81df0000, 0x00000000, 0x00000000, 0x834402d8, + 0x81df0004, 0xb500ff7f, 0x80070000, 0x80470000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002003, + 0xb6003002, 0x001eb802, 0x90420004, 0x80171000, + 0x8057ffff, 0xb6002002, 0xb6001801, 0x001fa020, + 0x81df0004, 0x00ffb81f, 0x83a70000, 0x8057ffff, + 0x80770000, 0x8073007d, 0x98636d4a, 0x0207b803, + 0x81df0000, 0x00000000, 0x00000000, 0x80171000, + 0xb6000007, 0x003fc020, 0x005fc7e0, 0x40c1b810, + 0x4102b810, 0x001fe026, 0x001fe0a8, 0x4210b803, + 0x81df0004, 0x80270000, 0x003f2013, 0x8007001f, + 0x94000003, 0x5810b800, 0x83671e1c, 0x1b7bb800, + 0x003f9009, 0x1821b800, 0x00ffb801, 0x003f0013, + 0xb0010001, 0xb420fff3, 0x93bd0001, 0xb01d0004, + 0xb480ffe3, 0x00ffb81f, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717f4, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00060, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x8384024e, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6001811, 0xb6002010, 0x14618000, + 0x6068b803, 0x40c4b803, 0x14608000, 0x00c8b806, + 0x5870b803, 0x6068b803, 0x4104b803, 0x58c8b806, + 0x0108b808, 0x14c6b801, 0x00000000, 0x00000000, + 0x5d08b808, 0x1508b800, 0x1806a028, 0x81df0004, + 0x80670400, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x808f0000, 0x801b4b14, 0x80270001, + 0xb0000001, 0xb4000002, 0x802600a0, 0x803e4b14, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813e4b0c, 0x80270001, 0x003f2013, 0x80050086, + 0x001fb044, 0x00ffb81b, 0x00000000, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009c, 0x96b48000, 0xb0158000, + 0xb4000191, 0x96b40100, 0xb0150100, 0xb40001ad, + 0x96b40400, 0xb0150400, 0xb40001bf, 0x96b40001, + 0xb0150001, 0xb400000c, 0x96b40008, 0xb0150008, + 0xb400019a, 0x96b44000, 0xb0154000, 0xb40001be, + 0x96b40002, 0xb0150002, 0xb400015e, 0x00000000, + 0x00000000, 0xb50001d0, 0x02bf9017, 0x92b50001, + 0x02bfb017, 0x82850082, 0x83050081, 0x82a5009a, + 0x96b50001, 0xb0150001, 0xb4200014, 0x82a70000, + 0x02bfb017, 0x96b41840, 0xb0150800, 0xb420000c, + 0x96b40008, 0x5aa9b815, 0x96d46000, 0x5ec3b816, + 0x82f3000f, 0x9af7c00f, 0x1718b817, 0x1ab5b818, + 0x1ab5b816, 0x9ab50340, 0x82a60081, 0xb500013d, + 0x9b180180, 0x83060081, 0xb500013a, 0x82a5009a, + 0x96b50002, 0xb0150002, 0xb420001b, 0x82a70000, + 0x02bfb017, 0x96b41800, 0xb0151800, 0xb4000013, + 0x96b40040, 0xb0150040, 0xb4200004, 0xa3180c00, + 0x9b180340, 0x83060081, 0xb500012a, 0x96b40008, + 0x5aa9b815, 0x96d46000, 0x5ec3b816, 0x82f3000f, + 0x9af7c00f, 0x1718b817, 0x1ab5b818, 0x1ab5b816, + 0x9ab50340, 0x82a60081, 0xb500011e, 0x9b180180, + 0x83060081, 0xb500011b, 0x82a500c1, 0x96b5000f, + 0xb015000b, 0xb420000e, 0x96b40020, 0xb0150020, + 0xb400000b, 0x96b40200, 0xb0150200, 0xb4000008, + 0x82c50086, 0x82e50094, 0x3016b817, 0xb4400004, + 0x06f7b816, 0xb017ff00, 0xb4400001, 0xb5000109, + 0x96b46000, 0xb0156000, 0xb4000011, 0x96b41820, + 0xb0150820, 0xb4200004, 0x9b391000, 0x82a5009a, + 0x96b5feff, 0x82a6009a, 0x96b40040, 0xb0150040, + 0xb4200001, 0x9739efff, 0x96b91000, 0xb0151000, + 0xb4200003, 0x82a5009a, 0x9ab50100, 0x82a6009a, + 0x96b40040, 0xb0150040, 0xb4200019, 0x96b41800, + 0xb0151800, 0xb4200006, 0x96b98000, 0xb0158000, + 0xb4200003, 0x9b180180, 0x83060081, 0xb50000e9, + 0x96d80c00, 0x82b300ff, 0x9ab5f3ff, 0x1718b815, + 0xb0160c00, 0xb4000007, 0x82e50098, 0x96f70400, + 0xb0170400, 0xb4200002, 0x82c70c00, 0xb5000001, + 0xa2d60c00, 0x1b18b816, 0x9b180340, 0xb50000cf, + 0x96b40220, 0xb0150000, 0xb4e00033, 0x82a5009d, + 0x82f3ffff, 0x16b5b817, 0x82f3000e, 0x3015b817, + 0xb420002d, 0x96f98000, 0xb0178000, 0xb400002a, + 0x82a70000, 0x02bfb017, 0x82c50081, 0x9ab60020, + 0x82a60081, 0x82a50086, 0x92b50bb8, 0x82a60094, + 0x82c60081, 0x82c5009d, 0x96d6ffff, 0x82b30032, + 0x9ab58001, 0x82e500c1, 0x96f7000f, 0xb017000b, + 0xb4000002, 0x82b30022, 0x9ab58001, 0x1ab5b816, + 0x82c5009a, 0x96d60020, 0xb0160020, 0xb4200002, + 0x82b30032, 0x9ab58001, 0x82a6009d, 0x02ff9017, + 0x00000000, 0xb0170040, 0xb480000b, 0x96f41c00, + 0xb0171c00, 0xb4200008, 0x82e50086, 0x82c50094, + 0x92d63000, 0x3016b817, 0xb4400003, 0x9b180180, + 0x83060081, 0xb50000a3, 0x5eb5b814, 0x96b500f0, + 0x96f46000, 0x5eedb817, 0x1ab5b817, 0xb0170003, + 0xb4000004, 0x96b500ef, 0x96f70001, 0x5ae4b817, + 0x1ab5b817, 0x96d41800, 0xb0161800, 0xb400000a, + 0x96f900ff, 0x96b500ff, 0x9739ff00, 0x1b39b815, + 0x02a7b817, 0x96b500f3, 0x96d40008, 0x5ec1b816, + 0x1ab5b816, 0xb500000c, 0x96f98000, 0xb0178000, + 0xb4200007, 0x5efeb814, 0x96f70001, 0xb0170001, + 0xb4000003, 0x9b180180, 0x83060081, 0xb5000081, + 0x96b500f3, 0x9ab50008, 0x9739fff3, 0x96d40020, + 0xb0160020, 0xb4200017, 0x9b398000, 0x82c70000, + 0x02dfb017, 0x96d40010, 0x5ac8b816, 0x82f300ff, + 0x9af7cfff, 0x1718b817, 0x1b18b816, 0x9b180340, + 0x82c5009d, 0x96d6ffff, 0x82f3000e, 0x9af78001, + 0x1af7b816, 0x82c5009a, 0x96d60020, 0xb0160020, + 0xb4200002, 0x82f30032, 0x9af78001, 0x82e6009d, + 0xb500005a, 0x97397fff, 0x96b500ff, 0x5aaab815, + 0x82f300fc, 0x9af703ff, 0x1718b817, 0x1b18b815, + 0x9b180340, 0x82c5009a, 0x96d60010, 0xb0160010, + 0xb4200024, 0x82c70000, 0x02dfb017, 0x82c50086, + 0x92d60bb8, 0x82c60086, 0x82c50094, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4200002, 0x82e70bb8, + 0xb5000001, 0x82e70bb8, 0x12d6b817, 0x82e50081, + 0x9af70020, 0x82e60081, 0x82c60094, 0xa2f70020, + 0x82e60081, 0x82f30001, 0x16f7b818, 0x5ef0b817, + 0xb0170001, 0xb4000004, 0x96f84000, 0x5ee4b817, + 0x9718f3ff, 0x1b18b817, 0x82f3000a, 0x9af78000, + 0x82e6009d, 0x83060081, 0x83070001, 0x8306009f, + 0xb50000ad, 0x82c5009d, 0x82f3000e, 0x9af78001, + 0x3016b817, 0xb420000f, 0x82b30032, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b30022, 0x9ab58001, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b30032, 0x9ab58001, + 0x82a6009d, 0x82c5009a, 0x96d60080, 0xb0160080, + 0xb4000011, 0x02df9017, 0x00000000, 0xb0160010, + 0xb480000d, 0x82c500c1, 0x96d6000f, 0xb016000b, + 0xb4000009, 0x82c50087, 0x96d60080, 0x5ac7b816, + 0x96f84000, 0x3017b816, 0xb4200003, 0x033f400f, + 0x9b394000, 0xb500000b, 0x9739bfff, 0x82e50061, + 0x96f70008, 0xb0170008, 0xb4000005, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4000001, 0x9718ffff, + 0x83060081, 0x83070001, 0x8306009f, 0x00000000, + 0xb5000075, 0x82850083, 0x96b400ff, 0xb015003c, + 0xb4200019, 0x96b92000, 0xb0152000, 0xb4000002, + 0x9b392000, 0xb5000014, 0x9739d3ff, 0x82870000, + 0x82860087, 0x82870008, 0x82860083, 0x829bff78, + 0x82a7001f, 0xb0140400, 0xb4000001, 0x82a70010, + 0x82a600c9, 0x829bff78, 0x00000000, 0x828600cb, + 0x8285009d, 0x82b3ffff, 0x9ab5fffd, 0x1694b815, + 0x8286009d, 0xb5000000, 0x83070002, 0x8306009f, + 0x00000000, 0xb5000054, 0x96b90800, 0xb0150800, + 0xb4200009, 0x9739f7ff, 0x82a703fd, 0x82a600cb, + 0x82a7003c, 0x82a60083, 0x8285009d, 0x9a940002, + 0x8286009d, 0xb5000004, 0x82850087, 0x5a82b814, + 0xa2940200, 0x82860087, 0xb5000000, 0x83078000, + 0x8306009f, 0x00000000, 0xb500003f, 0x82850086, + 0x82a50094, 0x3015b814, 0xb4800002, 0x86b50bb8, + 0x82a60086, 0x83070008, 0x8306009f, 0x00000000, + 0xb5000035, 0x83050069, 0x9718003f, 0x82e50064, + 0x12f7b818, 0x86f70088, 0x82feff74, 0x02e7b86f, + 0x9af74000, 0x01ffb817, 0x96f7bfff, 0x01ffb817, + 0x83050081, 0x82f3001c, 0x9af703ff, 0x1718b817, + 0x9b180140, 0x83060081, 0x83070100, 0x8306009f, + 0x00000000, 0xb5000020, 0x83070000, 0x83050081, + 0x9b180180, 0x83060081, 0x83070400, 0x8306009f, + 0x00000000, 0xb5000018, 0x82870000, 0x82850082, + 0x5eb7b814, 0x96b500fc, 0x96d40006, 0x5ec1b816, + 0x1ab5b816, 0x5aacb815, 0x83050081, 0x82d3001c, + 0x9ad600ff, 0x1718b816, 0x1b18b815, 0x9b180e00, + 0x83060081, 0x83074000, 0x8306009f, 0x8305009d, + 0x82d300ff, 0x9ad6bfff, 0x1718b816, 0x8306009d, + 0x00000000, 0xb5000000, 0x029f9005, 0x01ffb814, + 0x033f600f, 0x029f900a, 0x02bf900b, 0x02df900c, + 0x02ff900d, 0x031f900e, 0x033f900f, 0x00ffb81e, + 0x02ff9010, 0x92f70b43, 0x02ffb010, 0x02ff90cb, + 0x82bbffdc, 0x829bffd8, 0x93150004, 0x3014b815, + 0xb4000010, 0x02dbb818, 0x029bb815, 0x3017b816, + 0xb480000c, 0x5a81b814, 0x029fb010, 0x82860095, + 0x8293001f, 0x9294fe00, 0x92b50008, 0x3015b814, + 0xb4800002, 0x82b3001f, 0x92b5fa00, 0x82beffdc, + 0xb500ffeb, 0x029f9010, 0x83250094, 0x06d4b819, + 0x02d6b816, 0xb016ffff, 0xb4a0000a, 0x8293000e, + 0x9a948001, 0x82c5009d, 0x96d6ffff, 0x1a94b816, + 0x82c5009a, 0x96d60010, 0xb0160010, 0xb4000001, + 0x8286009d, 0x00ffb81c, 0x00000000, 0x00000000, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x803bff68, 0x8078ff6c, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x803bff68, + 0x8078ff6c, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x83840126, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e70228, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x80270180, 0x81e70120, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801b0220, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x80180224, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x819eff68, 0x817cff6c, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801b0220, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x80180224, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801b0220, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x80180224, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e7ff00, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270240, + 0x81e70000, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e70120, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x806f0007, + 0x80af0007, 0x80270280, 0x81e70100, 0x5de2b80f, + 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, + 0x01ff90bc, 0xb520ffff, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x829bff80, 0x80af001f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60020, 0x90210020, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6002005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb400008e, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb400001c, 0xb00a0003, + 0xb4000024, 0xb00a0004, 0xb4000052, 0xb00a0005, + 0xb400005b, 0xb00a0006, 0xb400007f, 0xb00a0007, + 0xb400007d, 0xb00a0008, 0xb400007b, 0x81df0000, + 0x00000000, 0x00000000, 0xb600800a, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x5c708028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x81df0004, 0xb500006b, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008004, 0x007f8028, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a400fa, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a400e5, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400d2, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6004005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a400cd, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a400b7, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x00000000, 0x00000000, + 0xb5000086, 0xb00a0001, 0xb400000e, 0xb00a0002, + 0xb4000017, 0xb00a0003, 0xb400001f, 0xb00a0004, + 0xb400004d, 0xb00a0005, 0xb4000056, 0xb00a0006, + 0xb400007a, 0xb00a0007, 0xb4000078, 0xb00a0008, + 0xb4000076, 0x81df0000, 0x00000000, 0x00000000, + 0xb6008005, 0x007f8028, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb500006b, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004004, + 0x007f8048, 0x019fa023, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000061, 0xb0130000, 0xb4000004, + 0xb0130001, 0xb4000009, 0xb0130002, 0xb400001a, + 0x83a40098, 0x80170f00, 0x007f8028, 0x001fa023, + 0x007f8028, 0x001fa023, 0xb5000054, 0x80170f00, + 0x00000000, 0x007f8020, 0x019fa023, 0x007f8000, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x83a40083, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000041, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40070, 0xb5000031, 0x81df0000, 0x00000000, + 0x00000000, 0xb6004005, 0x007f8008, 0x019fa023, + 0x007f8008, 0x019fa023, 0x019fa020, 0x81df0004, + 0xb5000026, 0xb0130000, 0xb4000008, 0xb0130001, + 0xb4000012, 0xb0130002, 0xb400001f, 0xb0130003, + 0xb400001d, 0xb0130004, 0xb400001b, 0x83a4006b, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x80170f00, + 0x007f8028, 0x001fa023, 0xb5000010, 0x80170f00, + 0x00000000, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x83a40055, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000001, 0xb5000000, 0x92730001, + 0x92520001, 0x3012b811, 0xb480fe89, 0x003f0324, + 0x90210001, 0xb0010006, 0xb4a00001, 0x80270001, + 0x003f2324, 0x2c8db811, 0x803bffe0, 0x805bffe4, + 0x5887b804, 0x1015b804, 0xad440003, 0x3000b802, + 0xb4800001, 0x8400a000, 0x801effec, 0x015f6193, + 0x809e4b04, 0x00ffb81f, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002a0c, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb600190f, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x81df0004, + 0x00ffb81d, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x829bff80, 0x80af001f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60020, 0x90210020, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6002005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb400008e, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb400001c, 0xb00a0003, + 0xb4000024, 0xb00a0004, 0xb4000052, 0xb00a0005, + 0xb400005b, 0xb00a0006, 0xb400007f, 0xb00a0007, + 0xb400007d, 0xb00a0008, 0xb400007b, 0x81df0000, + 0x00000000, 0x00000000, 0xb600800a, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x5c708028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x81df0004, 0xb500006b, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008004, 0x007f8028, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a400fa, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a400e5, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400d2, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6004005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a400cd, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a400b7, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x00000000, 0x00000000, + 0xb5000086, 0xb00a0001, 0xb400000e, 0xb00a0002, + 0xb4000017, 0xb00a0003, 0xb400001f, 0xb00a0004, + 0xb400004d, 0xb00a0005, 0xb4000056, 0xb00a0006, + 0xb400007a, 0xb00a0007, 0xb4000078, 0xb00a0008, + 0xb4000076, 0x81df0000, 0x00000000, 0x00000000, + 0xb6008005, 0x007f8028, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb500006b, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004004, + 0x007f8048, 0x019fa023, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000061, 0xb0130000, 0xb4000004, + 0xb0130001, 0xb4000009, 0xb0130002, 0xb400001a, + 0x83a40098, 0x80170f00, 0x007f8028, 0x001fa023, + 0x007f8028, 0x001fa023, 0xb5000054, 0x80170f00, + 0x00000000, 0x007f8020, 0x019fa023, 0x007f8000, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x83a40083, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000041, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40070, 0xb5000031, 0x81df0000, 0x00000000, + 0x00000000, 0xb6004005, 0x007f8008, 0x019fa023, + 0x007f8008, 0x019fa023, 0x019fa020, 0x81df0004, + 0xb5000026, 0xb0130000, 0xb4000008, 0xb0130001, + 0xb4000012, 0xb0130002, 0xb400001f, 0xb0130003, + 0xb400001d, 0xb0130004, 0xb400001b, 0x83a4006b, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x80170f00, + 0x007f8028, 0x001fa023, 0xb5000010, 0x80170f00, + 0x00000000, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x83a40055, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000001, 0xb5000000, 0x92730001, + 0x92520001, 0x3012b811, 0xb480fe89, 0x003f0324, + 0x90210001, 0xb0010006, 0xb4a00001, 0x80270001, + 0x003f2324, 0x2c8db811, 0x803bffe0, 0x805bffe4, + 0x5887b804, 0x1015b804, 0xad440003, 0x3000b802, + 0xb4800001, 0x8400a000, 0x801effec, 0x015f6193, + 0x809e4b04, 0x00ffb81f, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002a0c, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb600190f, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x81df0004, + 0x00ffb81d, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270bf4, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717f4, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00060, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x8384f922, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6001811, 0xb6002010, 0x14618000, + 0x6068b803, 0x40c4b803, 0x14608000, 0x00c8b806, + 0x5870b803, 0x6068b803, 0x4104b803, 0x58c8b806, + 0x0108b808, 0x14c6b801, 0x00000000, 0x00000000, + 0x5d08b808, 0x1508b800, 0x1806a028, 0x81df0004, + 0x80670400, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x808f0000, 0x801b4b14, 0x80270001, + 0xb0000001, 0xb4000002, 0x802600a0, 0x803e4b14, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813e4b0c, 0x80270001, 0x003f2013, 0x80050086, + 0x001fb044, 0x00ffb81b, 0x00000000, 0x00000000, +}; + +static u32 PCMUcode1f4b00[] = { + 0x00000000, 0x00000000, 0x00060504, 0x00000000, + 0x00000000, 0x00000000, 0x00300000, 0xffcfcfff, + 0x00302000, 0xffcfcfff, 0x00380000, 0xffc7c7ff, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/pcmi2s_240.h linux.20pre2-ac1/drivers/media/video/ls220/pcmi2s_240.h --- linux.20pre2/drivers/media/video/ls220/pcmi2s_240.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/pcmi2s_240.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,877 @@ +static u32 PCMI2S240Ucode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb500020b, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x029f9014, 0x829efef0, + 0x8286000f, 0x02bf0054, 0x82bcfef4, 0x82a6000e, + 0x80074000, 0x001f6193, 0x8013001f, 0x9020c000, + 0x003fb006, 0x803effe8, 0x803effec, 0x9020fa00, + 0x803effd0, 0x803effdc, 0x803effd8, 0x9020fe00, + 0x803effd4, 0x90400000, 0x804600a2, 0x90421800, + 0x804600a3, 0x80132000, 0x98000040, 0x800600a6, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x80070000, 0x001f23f9, 0x801e4b0c, + 0x001f210c, 0x80070001, 0x001f2324, 0x80070800, + 0x001f600f, 0x001fb0cb, 0x001fb010, 0x801efff0, + 0x98004000, 0x001f600e, 0x83e4011f, 0x80070000, + 0x801e4b14, 0x800500a0, 0xb0000001, 0xb4000009, + 0x80070001, 0x800600a0, 0x80050080, 0x98000020, + 0x80060080, 0x9400ffdf, 0x80060080, 0x80070000, + 0x800600a0, 0x80074000, 0x801e4b04, 0x81df0004, + 0x801bfff0, 0x00000000, 0x940000ff, 0xb0000000, + 0xb4200033, 0x003f400e, 0x94010010, 0xb0000000, + 0xb400fff7, 0x003f0013, 0xb0010001, 0xb420001f, + 0x803bffe8, 0x801bffec, 0x805b4b04, 0x00000000, + 0x3001b800, 0xb4600001, 0x9021a000, 0x0421b800, + 0x3001b802, 0xb460000d, 0x80050086, 0x005f9044, + 0x0420b802, 0xb00101e0, 0xb4a0ffe5, 0x001fb010, + 0x001f010c, 0xb0000001, 0xb400ffe1, 0x80070001, + 0x001f210c, 0x83e400ec, 0xb500ffdd, 0x8007001f, + 0x94000003, 0x5810b800, 0x83e719ec, 0x1bffb800, + 0x003f9008, 0x1821b800, 0x00ffb801, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671a14, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0x80070000, 0x001f210c, 0xb500ffc8, + 0x003f400e, 0xb0000086, 0xb4400055, 0xb0000084, + 0xb400003f, 0xb0000085, 0xb4000045, 0xb0000086, + 0xb4000047, 0xb0000083, 0xb4000000, 0x815bff7c, + 0x00000000, 0x940a0080, 0x5c07b800, 0xb0000001, + 0xb4000073, 0x81674b18, 0x940a0007, 0x5803b800, + 0x116bb800, 0x005bb80b, 0x916b0004, 0x001bb80b, + 0x80530030, 0x98422000, 0x8013ffcf, 0x9800cfff, + 0x806500d4, 0x1463b800, 0x1863b802, 0x806600d4, + 0x80073cfb, 0x801e4b00, 0x800600a1, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x8013007f, + 0x9800ffff, 0x001fb040, 0x80070001, 0x001f2013, + 0x80070000, 0x001f2324, 0x001fb0cb, 0x001fb010, + 0x001fb041, 0x001fb042, 0x800733b0, 0x001fb008, + 0x80071ea0, 0x001fb009, 0x98214000, 0xb5000010, + 0x94011000, 0xb0001000, 0xb4200001, 0x9421efff, + 0x98210010, 0xb500000a, 0x80070000, 0x001fb0cb, + 0x83e40099, 0x003f400e, 0x9421ffef, 0xb5000004, + 0x83e40095, 0x003f400e, 0x98211000, 0x9421ffef, + 0x003f600e, 0x80070100, 0x801efff0, 0xb500ff70, + 0xb000008b, 0xb4000018, 0xb0000087, 0xb400ffee, + 0xb0000088, 0xb4000016, 0xb000008a, 0xb4000016, + 0xb000008c, 0xb4000017, 0xb0000089, 0xb4000019, + 0xb00000a0, 0xb400001b, 0xb00000a1, 0xb4000047, + 0xb00000a2, 0xb4000054, 0xb00000a3, 0xb400004c, + 0xb00000a4, 0xb4000056, 0xb00000a5, 0xb400005a, + 0xb00000a6, 0xb400005e, 0x803efff8, 0xb500ffe1, + 0x9421ffdf, 0xb500ffde, 0x80270100, 0x803efff8, + 0xb500ffdc, 0x803bffb0, 0x00000000, 0x003fb040, + 0xb500ffd8, 0x803bff80, 0x00000000, 0x003f6001, + 0xb500ffd4, 0x003f90ba, 0x803efff8, 0xb500ffd1, + 0x81674b18, 0x940a0007, 0x5803b800, 0x116bb800, + 0x005bb80b, 0x916b0004, 0x001bb80b, 0x806500d4, + 0x1463b800, 0x1863b802, 0x806600d4, 0x80130001, + 0x98003d21, 0x800600a1, 0x801e4b00, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x80070001, + 0x001f2013, 0x80070000, 0x001f2324, 0x001fb0cb, + 0x001fb010, 0x80073bf0, 0x001fb008, 0x800743e0, + 0x001fb009, 0x98214000, 0xb500ffa5, 0x80270000, + 0x8047fef0, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x81df0000, 0x00000000, 0x00000000, 0x8364044f, + 0x81df0004, 0xb500ff97, 0x81df0000, 0x00000000, + 0x00000000, 0x836403f9, 0x81df0004, 0xb500ff91, + 0x81df0000, 0x00000000, 0x00000000, 0x836403b4, + 0x81df0004, 0xb500ff8b, 0x81df0000, 0x00000000, + 0x00000000, 0x83440317, 0x81df0004, 0xb500ff85, + 0x81df0000, 0x00000000, 0x00000000, 0x834402fc, + 0x81df0004, 0xb500ff7f, 0x80070000, 0x80470000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002003, + 0xb6003002, 0x001eb802, 0x90420004, 0x80171000, + 0x8057ffff, 0xb6002002, 0xb6001801, 0x001fa020, + 0x81df0004, 0x00ffb81f, 0x817bff7c, 0x00000000, + 0x956b0080, 0x5d67b80b, 0x83a70000, 0x8057ffff, + 0x80770000, 0x8073007a, 0x9863e7d2, 0xb00b0001, + 0xb4200002, 0x8073007d, 0x98636d4a, 0x0207b803, + 0x81df0000, 0x00000000, 0x00000000, 0xb00b0001, + 0xb400000a, 0x80171000, 0xb6008007, 0x003fc0c0, + 0x005fc740, 0x40c1b810, 0x4102b810, 0x001fe0c6, + 0x001fe0c8, 0x4210b803, 0xb5000009, 0x80171000, + 0xb6000007, 0x003fc020, 0x005fc7e0, 0x40c1b810, + 0x4102b810, 0x001fe026, 0x001fe0a8, 0x4210b803, + 0x81df0004, 0x80270000, 0x003f2013, 0x8007001f, + 0x94000003, 0x5810b800, 0x83671e7c, 0x1b7bb800, + 0x003f9009, 0x1821b800, 0x00ffb801, 0x003f0013, + 0xb0010001, 0xb420fff3, 0x93bd0001, 0xb01d0004, + 0xb480ffd7, 0x00ffb81f, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270be8, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717e8, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00059, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x8384025e, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0xb6002009, 0x58708000, + 0x6068b803, 0x40c4b803, 0x00000000, 0x00c8b806, + 0x00000000, 0x00000000, 0x00000000, 0x5807a026, + 0x81df0004, 0x80670400, 0x5d22b80a, 0x81df0000, + 0x00000000, 0x00000000, 0xb600180a, 0x00cfb803, + 0x013fb0bc, 0x5922b809, 0x01afb809, 0x013f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x91290020, 0x81df0004, 0x808f0000, 0x801b4b14, + 0x80270001, 0xb0000001, 0xb4000002, 0x802600a0, + 0x803e4b14, 0x81270c00, 0xb00a0000, 0xb4000001, + 0x81270000, 0x813e4b0c, 0x80270001, 0x003f2013, + 0x80050086, 0x001fb044, 0x00ffb81b, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009d, 0x82b30002, 0x9ab50040, + 0x1a94b815, 0x8286009d, 0x8285009c, 0x96b48000, + 0xb0158000, 0xb400019c, 0x96b40100, 0xb0150100, + 0xb40001b8, 0x96b40400, 0xb0150400, 0xb40001ca, + 0x96b40001, 0xb0150001, 0xb4000014, 0x96b40008, + 0xb0150008, 0xb40001a5, 0x96b44000, 0xb0154000, + 0xb40001c9, 0x96b40002, 0xb0150002, 0xb4000169, + 0x96b40040, 0xb0150040, 0xb40001dc, 0x82d30002, + 0x9ad60000, 0x16b6b814, 0x3015b816, 0xb40001da, + 0x00000000, 0x00000000, 0xb50001db, 0x02bf9017, + 0x92b50001, 0x02bfb017, 0x82850082, 0x83050081, + 0x82a5009a, 0x96b50001, 0xb0150001, 0xb4200014, + 0x82a70000, 0x02bfb017, 0x96b41840, 0xb0150800, + 0xb420000c, 0x96b40008, 0x5aa9b815, 0x96d46000, + 0x5ec3b816, 0x82f3000f, 0x9af7c00f, 0x1718b817, + 0x1ab5b818, 0x1ab5b816, 0x9ab50340, 0x82a60081, + 0xb5000140, 0x9b180180, 0x83060081, 0xb500013d, + 0x82a5009a, 0x96b50002, 0xb0150002, 0xb420001b, + 0x82a70000, 0x02bfb017, 0x96b41800, 0xb0151800, + 0xb4000013, 0x96b40040, 0xb0150040, 0xb4200004, + 0xa3180c00, 0x9b180340, 0x83060081, 0xb500012d, + 0x96b40008, 0x5aa9b815, 0x96d46000, 0x5ec3b816, + 0x82f3000f, 0x9af7c00f, 0x1718b817, 0x1ab5b818, + 0x1ab5b816, 0x9ab50340, 0x82a60081, 0xb5000121, + 0x9b180180, 0x83060081, 0xb500011e, 0x82a500c1, + 0x96b5000f, 0xb015000b, 0xb420000e, 0x96b40020, + 0xb0150020, 0xb400000b, 0x96b40200, 0xb0150200, + 0xb4000008, 0x82c50086, 0x82e50094, 0x3016b817, + 0xb4400004, 0x06f7b816, 0xb017ff00, 0xb4400001, + 0xb500010c, 0x96b46000, 0xb0156000, 0xb4000011, + 0x96b41820, 0xb0150820, 0xb4200004, 0x9b391000, + 0x82a5009a, 0x96b5feff, 0x82a6009a, 0x96b40040, + 0xb0150040, 0xb4200001, 0x9739efff, 0x96b91000, + 0xb0151000, 0xb4200003, 0x82a5009a, 0x9ab50100, + 0x82a6009a, 0x96b40040, 0xb0150040, 0xb4200019, + 0x96b41800, 0xb0151800, 0xb4200006, 0x96b98000, + 0xb0158000, 0xb4200003, 0x9b180180, 0x83060081, + 0xb50000ec, 0x96d80c00, 0x82b300ff, 0x9ab5f3ff, + 0x1718b815, 0xb0160c00, 0xb4000007, 0x82e50098, + 0x96f70400, 0xb0170400, 0xb4200002, 0x82c70c00, + 0xb5000001, 0xa2d60c00, 0x1b18b816, 0x9b180340, + 0xb50000d2, 0x96b40220, 0xb0150000, 0xb4e00033, + 0x82a5009d, 0x82f3ffff, 0x16b5b817, 0x82f33802, + 0x3015b817, 0xb420002d, 0x96f98000, 0xb0178000, + 0xb400002a, 0x82a70000, 0x02bfb017, 0x82c50081, + 0x9ab60020, 0x82a60081, 0x82a50086, 0x92b50bb8, + 0x82a60094, 0x82c60081, 0x82c5009d, 0x96d6ffff, + 0x82b3c802, 0x9ab50041, 0x82e500c1, 0x96f7000f, + 0xb017000b, 0xb4000002, 0x82b38802, 0x9ab50041, + 0x1ab5b816, 0x82c5009a, 0x96d60020, 0xb0160020, + 0xb4200002, 0x82b3c802, 0x9ab50041, 0x82a6009d, + 0x02ff9017, 0x00000000, 0xb0170040, 0xb480000b, + 0x96f41c00, 0xb0171c00, 0xb4200008, 0x82e50086, + 0x82c50094, 0x92d63000, 0x3016b817, 0xb4400003, + 0x9b180180, 0x83060081, 0xb50000a6, 0x5eb5b814, + 0x96b500f0, 0x96f46000, 0x5eedb817, 0x1ab5b817, + 0xb0170003, 0xb4000004, 0x96b500ef, 0x96f70001, + 0x5ae4b817, 0x1ab5b817, 0x96d41800, 0xb0161800, + 0xb400000a, 0x96f900ff, 0x96b500ff, 0x9739ff00, + 0x1b39b815, 0x02a7b817, 0x96b500f3, 0x96d40008, + 0x5ec1b816, 0x1ab5b816, 0xb500000c, 0x96f98000, + 0xb0178000, 0xb4200007, 0x5efeb814, 0x96f70001, + 0xb0170001, 0xb4000003, 0x9b180180, 0x83060081, + 0xb5000084, 0x96b500f3, 0x9ab50008, 0x9739fff3, + 0x96d40020, 0xb0160020, 0xb4200017, 0x9b398000, + 0x82c70000, 0x02dfb017, 0x96d40010, 0x5ac8b816, + 0x82f300ff, 0x9af7cfff, 0x1718b817, 0x1b18b816, + 0x9b180340, 0x82c5009d, 0x96d6ffff, 0x82f33802, + 0x9af70041, 0x1af7b816, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82f3c802, 0x9af70041, + 0x82e6009d, 0xb500005d, 0x97397fff, 0x96b500ff, + 0x5aaab815, 0x82f300fc, 0x9af703ff, 0x1718b817, + 0x1b18b815, 0x9b180340, 0x82c5009a, 0x96d60010, + 0xb0160010, 0xb4200024, 0x82c70000, 0x02dfb017, + 0x82c50086, 0x92d60bb8, 0x82c60086, 0x82c50094, + 0x5eefb818, 0x96f70003, 0xb0170003, 0xb4200002, + 0x82e70bb8, 0xb5000001, 0x82e70bb8, 0x12d6b817, + 0x82e50081, 0x9af70020, 0x82e60081, 0x82c60094, + 0xa2f70020, 0x82e60081, 0x82f30001, 0x16f7b818, + 0x5ef0b817, 0xb0170001, 0xb4000004, 0x96f84000, + 0x5ee4b817, 0x9718f3ff, 0x1b18b817, 0x82f32802, + 0x9af70040, 0x82e6009d, 0x83060081, 0x83070001, + 0x8306009f, 0xb50000b8, 0x82c5009d, 0x82f33802, + 0x9af70041, 0x3016b817, 0xb420000f, 0x82b3c802, + 0x9ab50041, 0x82e500c1, 0x96f7000f, 0xb017000b, + 0xb4000002, 0x82b38802, 0x9ab50041, 0x82c5009a, + 0x96d60020, 0xb0160020, 0xb4200002, 0x82b3c802, + 0x9ab50041, 0x82a6009d, 0x82c5009a, 0x96d60080, + 0xb0160080, 0xb4000014, 0x02df9017, 0x00000000, + 0xb0160010, 0xb4800010, 0x82c500c1, 0x96d6000f, + 0xb016000b, 0xb400000c, 0x82c50087, 0x96d60080, + 0x5ac7b816, 0x82c50098, 0x96d60800, 0x5ac3b816, + 0x96f84000, 0x3017b816, 0xb4200003, 0x033f400f, + 0x9b394000, 0xb500000b, 0x9739bfff, 0x82e50061, + 0x96f70008, 0xb0170008, 0xb4000005, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4000001, 0x9718ffff, + 0x83060081, 0x83070001, 0x8306009f, 0x00000000, + 0xb500007d, 0x82850083, 0x96b400ff, 0xb015003c, + 0xb4200019, 0x96b92000, 0xb0152000, 0xb4000002, + 0x9b392000, 0xb5000014, 0x9739d3ff, 0x82870000, + 0x82860087, 0x82870008, 0x82860083, 0x829bff78, + 0x82a7001f, 0xb0140400, 0xb4000001, 0x82a70010, + 0x82a600c9, 0x829bff78, 0x00000000, 0x828600cb, + 0x8285009d, 0x82b3ffff, 0x9ab5fffd, 0x1694b815, + 0x8286009d, 0xb5000000, 0x83070002, 0x8306009f, + 0x00000000, 0xb500005c, 0x96b90800, 0xb0150800, + 0xb4200009, 0x9739f7ff, 0x82a703fd, 0x82a600cb, + 0x82a7003c, 0x82a60083, 0x8285009d, 0x9a940002, + 0x8286009d, 0xb5000004, 0x82850087, 0x5a82b814, + 0xa2940200, 0x82860087, 0xb5000000, 0x83078000, + 0x8306009f, 0x00000000, 0xb5000047, 0x82850086, + 0x82a50094, 0x3015b814, 0xb4800002, 0x86b50bb8, + 0x82a60086, 0x83070008, 0x8306009f, 0x00000000, + 0xb500003d, 0x83050069, 0x9718003f, 0x82e50064, + 0x12f7b818, 0x86f70088, 0x82feff74, 0x02e7b86f, + 0x9af74000, 0x01ffb817, 0x96f7bfff, 0x01ffb817, + 0x83050081, 0x82f3001c, 0x9af703ff, 0x1718b817, + 0x9b180140, 0x83060081, 0x83070100, 0x8306009f, + 0x00000000, 0xb5000028, 0x83070000, 0x83050081, + 0x9b180180, 0x83060081, 0x83070400, 0x8306009f, + 0x00000000, 0xb5000020, 0x82870000, 0x82850082, + 0x5eb7b814, 0x96b500fc, 0x96d40006, 0x5ec1b816, + 0x1ab5b816, 0x5aacb815, 0x83050081, 0x82d3001c, + 0x9ad600ff, 0x1718b816, 0x1b18b815, 0x9b180e00, + 0x83060081, 0x83074000, 0x8306009f, 0x8305009d, + 0x82d3ffff, 0x9ad6bfff, 0x1718b816, 0x8306009d, + 0x00000000, 0xb5000008, 0xb5000007, 0x83070040, + 0x8306009f, 0xb5000004, 0x83130002, 0x9b180000, + 0x8306009f, 0xb5000000, 0x029f9005, 0x01ffb814, + 0x033f600f, 0x029f900a, 0x02bf900b, 0x02df900c, + 0x02ff900d, 0x031f900e, 0x033f900f, 0x00ffb81e, + 0x02ff9010, 0x92f70b43, 0x02ffb010, 0x02ff90cb, + 0x82bbffdc, 0x829bffd8, 0x93150004, 0x3014b815, + 0xb4000010, 0x02dbb818, 0x029bb815, 0x3017b816, + 0xb480000c, 0x5a81b814, 0x029fb010, 0x82860095, + 0x8293001f, 0x9294fe00, 0x92b50008, 0x3015b814, + 0xb4800002, 0x82b3001f, 0x92b5fa00, 0x82beffdc, + 0xb500ffeb, 0x029f9010, 0x83250094, 0x06d4b819, + 0x02d6b816, 0xb016ffff, 0xb4a0000a, 0x82933802, + 0x9a940041, 0x82c5009d, 0x96d6ffff, 0x1a94b816, + 0x82c5009a, 0x96d60010, 0xb0160010, 0xb4000001, + 0x8286009d, 0x00ffb81c, 0x00000000, 0x00000000, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x803bff68, 0x8078ff6c, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x803bff68, + 0x8078ff6c, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x83840126, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e70228, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x80270180, 0x81e70120, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801b0220, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x80180224, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x819eff68, 0x817cff6c, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801b0220, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x80180224, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801b0220, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x80180224, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e7ff00, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270240, + 0x81e70000, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e70120, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x806f0007, + 0x80af0007, 0x80270280, 0x81e70100, 0x5de2b80f, + 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, + 0x01ff90bc, 0xb520ffff, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x829bff80, 0x80af000f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60010, 0x90210010, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6001005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6001018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6002004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb4000099, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb4000022, 0xb00a0003, + 0xb400002f, 0xb00a0004, 0xb400005d, 0xb00a0005, + 0xb4000066, 0xb00a0006, 0xb400008a, 0xb00a0007, + 0xb4000088, 0xb00a0008, 0xb4000086, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004010, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x5c708028, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000070, 0x81df0000, 0x00000000, 0x00000000, + 0x8027ffff, 0xb6004008, 0x14618008, 0x019fa023, + 0x019fa020, 0x019fa020, 0x5c708028, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb5000061, + 0xb0130000, 0xb4000004, 0xb0130001, 0xb4000009, + 0xb0130002, 0xb400001a, 0x83a40102, 0x80170f00, + 0x007f8028, 0x001fa023, 0x007f8028, 0x001fa023, + 0xb5000054, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8000, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400ed, + 0x80170f00, 0x007f8028, 0x001fa023, 0xb5000041, + 0x80170f00, 0x00000000, 0x007f8020, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x83a400da, 0xb5000031, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002005, + 0x007f8008, 0x019fa023, 0x007f8008, 0x019fa023, + 0x019fa020, 0x81df0004, 0xb5000026, 0xb0130000, + 0xb4000008, 0xb0130001, 0xb4000012, 0xb0130002, + 0xb400001f, 0xb0130003, 0xb400001d, 0xb0130004, + 0xb400001b, 0x83a400d5, 0x007f8028, 0x019fa023, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000010, 0x80170f00, 0x00000000, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x83a400bf, + 0x80170f00, 0x007f8028, 0x001fa023, 0xb5000001, + 0xb5000000, 0x00000000, 0x00000000, 0xb500008e, + 0xb00a0001, 0xb400000e, 0xb00a0002, 0xb400001a, + 0xb00a0003, 0xb4000027, 0xb00a0004, 0xb4000055, + 0xb00a0005, 0xb400005e, 0xb00a0006, 0xb4000082, + 0xb00a0007, 0xb4000080, 0xb00a0008, 0xb400007e, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004008, + 0x007f8028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000070, 0x81df0000, 0x00000000, + 0x00000000, 0x8027ffff, 0xb6002008, 0x14618008, + 0x019fa023, 0x019fa020, 0x019fa020, 0x5c708048, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a40098, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40083, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a40070, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a4006b, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a40055, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x92730001, 0x92520001, + 0x3012b811, 0xb480fe76, 0x003f0324, 0x90210001, + 0xb0010006, 0xb4a00001, 0x80270001, 0x003f2324, + 0x2c8db811, 0x803bffe0, 0x805bffe4, 0x5886b804, + 0x1015b804, 0xad440003, 0x3000b802, 0xb4800001, + 0x8400a000, 0x801effec, 0x015f6193, 0x809e4b04, + 0x00ffb81f, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002a0c, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x81df0004, 0x00ffb81d, 0x81df0000, 0x00000000, + 0x00000000, 0xb600190f, 0x007f8028, 0x019fa023, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x81df0004, 0x00ffb81d, 0x00000000, + 0x829bff80, 0x80af001f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60020, 0x90210020, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6002005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb400008e, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb400001c, 0xb00a0003, + 0xb4000024, 0xb00a0004, 0xb4000052, 0xb00a0005, + 0xb400005b, 0xb00a0006, 0xb400007f, 0xb00a0007, + 0xb400007d, 0xb00a0008, 0xb400007b, 0x81df0000, + 0x00000000, 0x00000000, 0xb600800a, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x5c708028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x81df0004, 0xb500006b, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008004, 0x007f8028, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a400fa, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a400e5, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400d2, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6004005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a400cd, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a400b7, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x00000000, 0x00000000, + 0xb5000086, 0xb00a0001, 0xb400000e, 0xb00a0002, + 0xb4000017, 0xb00a0003, 0xb400001f, 0xb00a0004, + 0xb400004d, 0xb00a0005, 0xb4000056, 0xb00a0006, + 0xb400007a, 0xb00a0007, 0xb4000078, 0xb00a0008, + 0xb4000076, 0x81df0000, 0x00000000, 0x00000000, + 0xb6008005, 0x007f8028, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb500006b, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004004, + 0x007f8048, 0x019fa023, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000061, 0xb0130000, 0xb4000004, + 0xb0130001, 0xb4000009, 0xb0130002, 0xb400001a, + 0x83a40098, 0x80170f00, 0x007f8028, 0x001fa023, + 0x007f8028, 0x001fa023, 0xb5000054, 0x80170f00, + 0x00000000, 0x007f8020, 0x019fa023, 0x007f8000, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x83a40083, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000041, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40070, 0xb5000031, 0x81df0000, 0x00000000, + 0x00000000, 0xb6004005, 0x007f8008, 0x019fa023, + 0x007f8008, 0x019fa023, 0x019fa020, 0x81df0004, + 0xb5000026, 0xb0130000, 0xb4000008, 0xb0130001, + 0xb4000012, 0xb0130002, 0xb400001f, 0xb0130003, + 0xb400001d, 0xb0130004, 0xb400001b, 0x83a4006b, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x80170f00, + 0x007f8028, 0x001fa023, 0xb5000010, 0x80170f00, + 0x00000000, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x83a40055, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000001, 0xb5000000, 0x92730001, + 0x92520001, 0x3012b811, 0xb480fe89, 0x003f0324, + 0x90210001, 0xb0010006, 0xb4a00001, 0x80270001, + 0x003f2324, 0x2c8db811, 0x803bffe0, 0x805bffe4, + 0x5887b804, 0x1015b804, 0xad440003, 0x3000b802, + 0xb4800001, 0x8400a000, 0x801effec, 0x015f6193, + 0x809e4b04, 0x00ffb81f, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002a0c, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb600190f, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x81df0004, + 0x00ffb81d, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270be8, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717e8, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00060, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x8384f90e, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6001811, 0xb6002010, 0x14618000, + 0x6068b803, 0x40c4b803, 0x14608000, 0x00c8b806, + 0x5870b803, 0x6068b803, 0x4104b803, 0x58c8b806, + 0x0108b808, 0x14c6b801, 0x00000000, 0x00000000, + 0x5d08b808, 0x1508b800, 0x1806a028, 0x81df0004, + 0x80670400, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x808f0000, 0x801b4b14, 0x80270001, + 0xb0000001, 0xb4000002, 0x802600a0, 0x803e4b14, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813e4b0c, 0x80270001, 0x003f2013, 0x80050086, + 0x001fb044, 0x00ffb81b, 0x00000000, 0x00000000, +}; + +static u32 PCMI2S240Ucode1f4b00[] = { + 0x00000000, 0x00000000, 0x00060504, 0x00000000, + 0x00000000, 0x00000000, 0x00300000, 0xffcfcfff, + 0x00302000, 0xffcfcfff, 0x00380000, 0xffc7c7ff, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; + +static u32 PCMI2S240Ucode1fff00[] = { + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/ls220/pcmi2s.h linux.20pre2-ac1/drivers/media/video/ls220/pcmi2s.h --- linux.20pre2/drivers/media/video/ls220/pcmi2s.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/ls220/pcmi2s.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,801 @@ +static u32 PCMI2SUcode1f1800[] = { + 0xb500000f, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xb500020b, 0x00000000, 0x00000000, 0x00000000, + 0x820f001f, 0x802f001f, 0x029f9014, 0x829efef0, + 0x8286000f, 0x02bf0054, 0x82bcfef4, 0x82a6000e, + 0x80074000, 0x001f6193, 0x8013001f, 0x9020c000, + 0x003fb006, 0x803effe8, 0x803effec, 0x9020fa00, + 0x803effd0, 0x803effdc, 0x803effd8, 0x9020fe00, + 0x803effd4, 0x90400000, 0x804600a2, 0x90421800, + 0x804600a3, 0x80132000, 0x98000040, 0x800600a6, + 0x80050080, 0x98000002, 0x80060080, 0x80070001, + 0x001f2013, 0x80070000, 0x001f23f9, 0x801e4b0c, + 0x001f210c, 0x80070001, 0x001f2324, 0x80070800, + 0x001f600f, 0x001fb0cb, 0x001fb010, 0x801efff0, + 0x98004000, 0x001f600e, 0x83e4011f, 0x80070000, + 0x801e4b14, 0x800500a0, 0xb0000001, 0xb4000009, + 0x80070001, 0x800600a0, 0x80050080, 0x98000020, + 0x80060080, 0x9400ffdf, 0x80060080, 0x80070000, + 0x800600a0, 0x80074000, 0x801e4b04, 0x81df0004, + 0x801bfff0, 0x00000000, 0x940000ff, 0xb0000000, + 0xb4200033, 0x003f400e, 0x94010010, 0xb0000000, + 0xb400fff7, 0x003f0013, 0xb0010001, 0xb420001f, + 0x803bffe8, 0x801bffec, 0x805b4b04, 0x00000000, + 0x3001b800, 0xb4600001, 0x9021a000, 0x0421b800, + 0x3001b802, 0xb460000d, 0x80050086, 0x005f9044, + 0x0420b802, 0xb00101e0, 0xb4a0ffe5, 0x001fb010, + 0x001f010c, 0xb0000001, 0xb400ffe1, 0x80070001, + 0x001f210c, 0x83e400ec, 0xb500ffdd, 0x8007001f, + 0x94000003, 0x5810b800, 0x83e719ec, 0x1bffb800, + 0x003f9008, 0x1821b800, 0x00ffb801, 0x80270000, + 0x003f2013, 0x8007001f, 0x94000003, 0x5810b800, + 0x83671a14, 0x1b7bb800, 0x003f9009, 0x1821b800, + 0x00ffb801, 0x80070000, 0x001f210c, 0xb500ffc8, + 0x003f400e, 0xb0000086, 0xb4400055, 0xb0000084, + 0xb400003f, 0xb0000085, 0xb4000045, 0xb0000086, + 0xb4000047, 0xb0000083, 0xb4000000, 0x815bff7c, + 0x00000000, 0x940a0080, 0x5c07b800, 0xb0000001, + 0xb4000073, 0x81674b18, 0x940a0007, 0x5803b800, + 0x116bb800, 0x005bb80b, 0x916b0004, 0x001bb80b, + 0x80530030, 0x98422000, 0x8013ffcf, 0x9800cfff, + 0x806500d4, 0x1463b800, 0x1863b802, 0x806600d4, + 0x80073cfb, 0x801e4b00, 0x800600a1, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x8013007f, + 0x9800ffff, 0x001fb040, 0x80070001, 0x001f2013, + 0x80070000, 0x001f2324, 0x001fb0cb, 0x001fb010, + 0x001fb041, 0x001fb042, 0x80073350, 0x001fb008, + 0x80071ea0, 0x001fb009, 0x98214000, 0xb5000010, + 0x94011000, 0xb0001000, 0xb4200001, 0x9421efff, + 0x98210010, 0xb500000a, 0x80070000, 0x001fb0cb, + 0x83e40099, 0x003f400e, 0x9421ffef, 0xb5000004, + 0x83e40095, 0x003f400e, 0x98211000, 0x9421ffef, + 0x003f600e, 0x80070100, 0x801efff0, 0xb500ff70, + 0xb000008b, 0xb4000018, 0xb0000087, 0xb400ffee, + 0xb0000088, 0xb4000016, 0xb000008a, 0xb4000016, + 0xb000008c, 0xb4000017, 0xb0000089, 0xb4000019, + 0xb00000a0, 0xb400001b, 0xb00000a1, 0xb4000047, + 0xb00000a2, 0xb4000054, 0xb00000a3, 0xb400004c, + 0xb00000a4, 0xb4000056, 0xb00000a5, 0xb400005a, + 0xb00000a6, 0xb400005e, 0x803efff8, 0xb500ffe1, + 0x9421ffdf, 0xb500ffde, 0x80270100, 0x803efff8, + 0xb500ffdc, 0x803bffb0, 0x00000000, 0x003fb040, + 0xb500ffd8, 0x803bff80, 0x00000000, 0x003f6001, + 0xb500ffd4, 0x003f90ba, 0x803efff8, 0xb500ffd1, + 0x81674b18, 0x940a0007, 0x5803b800, 0x116bb800, + 0x005bb80b, 0x916b0004, 0x001bb80b, 0x806500d4, + 0x1463b800, 0x1863b802, 0x806600d4, 0x80130001, + 0x98003d21, 0x800600a1, 0x801e4b00, 0x80074000, + 0x801e4b04, 0x8013001f, 0x98405000, 0x805effe0, + 0x005fb006, 0x805effe8, 0x805effec, 0x9042a000, + 0x805effe4, 0x9040fa00, 0x805effd0, 0x805effdc, + 0x805effd8, 0x9040fe00, 0x805effd4, 0x80070001, + 0x001f2013, 0x80070000, 0x001f2324, 0x001fb0cb, + 0x001fb010, 0x80073b90, 0x001fb008, 0x80074380, + 0x001fb009, 0x98214000, 0xb500ffa5, 0x80270000, + 0x8047fef0, 0x003eb802, 0x90420004, 0x003eb802, + 0x90420004, 0x003eb802, 0x90420004, 0x003eb802, + 0x81df0000, 0x00000000, 0x00000000, 0x83640437, + 0x81df0004, 0xb500ff97, 0x81df0000, 0x00000000, + 0x00000000, 0x836403e1, 0x81df0004, 0xb500ff91, + 0x81df0000, 0x00000000, 0x00000000, 0x8364039c, + 0x81df0004, 0xb500ff8b, 0x81df0000, 0x00000000, + 0x00000000, 0x834402ff, 0x81df0004, 0xb500ff85, + 0x81df0000, 0x00000000, 0x00000000, 0x834402e4, + 0x81df0004, 0xb500ff7f, 0x80070000, 0x80470000, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002003, + 0xb6003002, 0x001eb802, 0x90420004, 0x80171000, + 0x8057ffff, 0xb6002002, 0xb6001801, 0x001fa020, + 0x81df0004, 0x00ffb81f, 0x817bff7c, 0x00000000, + 0x956b0080, 0x5d67b80b, 0x83a70000, 0x8057ffff, + 0x80770000, 0x8073007a, 0x9863e7d2, 0xb00b0001, + 0xb4200002, 0x8073007d, 0x98636d4a, 0x0207b803, + 0x81df0000, 0x00000000, 0x00000000, 0xb00b0001, + 0xb400000a, 0x80171000, 0xb6008007, 0x003fc0c0, + 0x005fc740, 0x40c1b810, 0x4102b810, 0x001fe0c6, + 0x001fe0c8, 0x4210b803, 0xb5000009, 0x80171000, + 0xb6000007, 0x003fc020, 0x005fc7e0, 0x40c1b810, + 0x4102b810, 0x001fe026, 0x001fe0a8, 0x4210b803, + 0x81df0004, 0x80270000, 0x003f2013, 0x8007001f, + 0x94000003, 0x5810b800, 0x83671e7c, 0x1b7bb800, + 0x003f9009, 0x1821b800, 0x00ffb801, 0x003f0013, + 0xb0010001, 0xb420fff3, 0x93bd0001, 0xb01d0004, + 0xb480ffd7, 0x00ffb81f, 0x00000000, 0x00000000, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270be8, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717e8, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00059, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x83840246, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0xb6002009, 0x58708000, + 0x6068b803, 0x40c4b803, 0x00000000, 0x00c8b806, + 0x00000000, 0x00000000, 0x00000000, 0x5807a026, + 0x81df0004, 0x80670400, 0x5d22b80a, 0x81df0000, + 0x00000000, 0x00000000, 0xb600180a, 0x00cfb803, + 0x013fb0bc, 0x5922b809, 0x01afb809, 0x013f90bc, + 0x0047b86f, 0xb0020001, 0xb4c0fffd, 0x90630020, + 0x91290020, 0x81df0004, 0x808f0000, 0x801b4b14, + 0x80270001, 0xb0000001, 0xb4000002, 0x802600a0, + 0x803e4b14, 0x81270c00, 0xb00a0000, 0xb4000001, + 0x81270000, 0x813e4b0c, 0x80270001, 0x003f2013, + 0x80050086, 0x001fb044, 0x00ffb81b, 0x00000000, + 0x029fb00a, 0x02bfb00b, 0x02dfb00c, 0x02ffb00d, + 0x031fb00e, 0x033fb00f, 0x033f400f, 0x0287b86f, + 0x029fb005, 0x8285009c, 0x96b48000, 0xb0158000, + 0xb4000191, 0x96b40100, 0xb0150100, 0xb40001ad, + 0x96b40400, 0xb0150400, 0xb40001bf, 0x96b40001, + 0xb0150001, 0xb400000c, 0x96b40008, 0xb0150008, + 0xb400019a, 0x96b44000, 0xb0154000, 0xb40001be, + 0x96b40002, 0xb0150002, 0xb400015e, 0x00000000, + 0x00000000, 0xb50001d0, 0x02bf9017, 0x92b50001, + 0x02bfb017, 0x82850082, 0x83050081, 0x82a5009a, + 0x96b50001, 0xb0150001, 0xb4200014, 0x82a70000, + 0x02bfb017, 0x96b41840, 0xb0150800, 0xb420000c, + 0x96b40008, 0x5aa9b815, 0x96d46000, 0x5ec3b816, + 0x82f3000f, 0x9af7c00f, 0x1718b817, 0x1ab5b818, + 0x1ab5b816, 0x9ab50340, 0x82a60081, 0xb500013d, + 0x9b180180, 0x83060081, 0xb500013a, 0x82a5009a, + 0x96b50002, 0xb0150002, 0xb420001b, 0x82a70000, + 0x02bfb017, 0x96b41800, 0xb0151800, 0xb4000013, + 0x96b40040, 0xb0150040, 0xb4200004, 0xa3180c00, + 0x9b180340, 0x83060081, 0xb500012a, 0x96b40008, + 0x5aa9b815, 0x96d46000, 0x5ec3b816, 0x82f3000f, + 0x9af7c00f, 0x1718b817, 0x1ab5b818, 0x1ab5b816, + 0x9ab50340, 0x82a60081, 0xb500011e, 0x9b180180, + 0x83060081, 0xb500011b, 0x82a500c1, 0x96b5000f, + 0xb015000b, 0xb420000e, 0x96b40020, 0xb0150020, + 0xb400000b, 0x96b40200, 0xb0150200, 0xb4000008, + 0x82c50086, 0x82e50094, 0x3016b817, 0xb4400004, + 0x06f7b816, 0xb017ff00, 0xb4400001, 0xb5000109, + 0x96b46000, 0xb0156000, 0xb4000011, 0x96b41820, + 0xb0150820, 0xb4200004, 0x9b391000, 0x82a5009a, + 0x96b5feff, 0x82a6009a, 0x96b40040, 0xb0150040, + 0xb4200001, 0x9739efff, 0x96b91000, 0xb0151000, + 0xb4200003, 0x82a5009a, 0x9ab50100, 0x82a6009a, + 0x96b40040, 0xb0150040, 0xb4200019, 0x96b41800, + 0xb0151800, 0xb4200006, 0x96b98000, 0xb0158000, + 0xb4200003, 0x9b180180, 0x83060081, 0xb50000e9, + 0x96d80c00, 0x82b300ff, 0x9ab5f3ff, 0x1718b815, + 0xb0160c00, 0xb4000007, 0x82e50098, 0x96f70400, + 0xb0170400, 0xb4200002, 0x82c70c00, 0xb5000001, + 0xa2d60c00, 0x1b18b816, 0x9b180340, 0xb50000cf, + 0x96b40220, 0xb0150000, 0xb4e00033, 0x82a5009d, + 0x82f3ffff, 0x16b5b817, 0x82f3000e, 0x3015b817, + 0xb420002d, 0x96f98000, 0xb0178000, 0xb400002a, + 0x82a70000, 0x02bfb017, 0x82c50081, 0x9ab60020, + 0x82a60081, 0x82a50086, 0x92b50bb8, 0x82a60094, + 0x82c60081, 0x82c5009d, 0x96d6ffff, 0x82b30032, + 0x9ab58001, 0x82e500c1, 0x96f7000f, 0xb017000b, + 0xb4000002, 0x82b30022, 0x9ab58001, 0x1ab5b816, + 0x82c5009a, 0x96d60020, 0xb0160020, 0xb4200002, + 0x82b30032, 0x9ab58001, 0x82a6009d, 0x02ff9017, + 0x00000000, 0xb0170040, 0xb480000b, 0x96f41c00, + 0xb0171c00, 0xb4200008, 0x82e50086, 0x82c50094, + 0x92d63000, 0x3016b817, 0xb4400003, 0x9b180180, + 0x83060081, 0xb50000a3, 0x5eb5b814, 0x96b500f0, + 0x96f46000, 0x5eedb817, 0x1ab5b817, 0xb0170003, + 0xb4000004, 0x96b500ef, 0x96f70001, 0x5ae4b817, + 0x1ab5b817, 0x96d41800, 0xb0161800, 0xb400000a, + 0x96f900ff, 0x96b500ff, 0x9739ff00, 0x1b39b815, + 0x02a7b817, 0x96b500f3, 0x96d40008, 0x5ec1b816, + 0x1ab5b816, 0xb500000c, 0x96f98000, 0xb0178000, + 0xb4200007, 0x5efeb814, 0x96f70001, 0xb0170001, + 0xb4000003, 0x9b180180, 0x83060081, 0xb5000081, + 0x96b500f3, 0x9ab50008, 0x9739fff3, 0x96d40020, + 0xb0160020, 0xb4200017, 0x9b398000, 0x82c70000, + 0x02dfb017, 0x96d40010, 0x5ac8b816, 0x82f300ff, + 0x9af7cfff, 0x1718b817, 0x1b18b816, 0x9b180340, + 0x82c5009d, 0x96d6ffff, 0x82f3000e, 0x9af78001, + 0x1af7b816, 0x82c5009a, 0x96d60020, 0xb0160020, + 0xb4200002, 0x82f30032, 0x9af78001, 0x82e6009d, + 0xb500005a, 0x97397fff, 0x96b500ff, 0x5aaab815, + 0x82f300fc, 0x9af703ff, 0x1718b817, 0x1b18b815, + 0x9b180340, 0x82c5009a, 0x96d60010, 0xb0160010, + 0xb4200024, 0x82c70000, 0x02dfb017, 0x82c50086, + 0x92d60bb8, 0x82c60086, 0x82c50094, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4200002, 0x82e70bb8, + 0xb5000001, 0x82e70bb8, 0x12d6b817, 0x82e50081, + 0x9af70020, 0x82e60081, 0x82c60094, 0xa2f70020, + 0x82e60081, 0x82f30001, 0x16f7b818, 0x5ef0b817, + 0xb0170001, 0xb4000004, 0x96f84000, 0x5ee4b817, + 0x9718f3ff, 0x1b18b817, 0x82f3000a, 0x9af78000, + 0x82e6009d, 0x83060081, 0x83070001, 0x8306009f, + 0xb50000ad, 0x82c5009d, 0x82f3000e, 0x9af78001, + 0x3016b817, 0xb420000f, 0x82b30032, 0x9ab58001, + 0x82e500c1, 0x96f7000f, 0xb017000b, 0xb4000002, + 0x82b30022, 0x9ab58001, 0x82c5009a, 0x96d60020, + 0xb0160020, 0xb4200002, 0x82b30032, 0x9ab58001, + 0x82a6009d, 0x82c5009a, 0x96d60080, 0xb0160080, + 0xb4000011, 0x02df9017, 0x00000000, 0xb0160010, + 0xb480000d, 0x82c500c1, 0x96d6000f, 0xb016000b, + 0xb4000009, 0x82c50087, 0x96d60080, 0x5ac7b816, + 0x96f84000, 0x3017b816, 0xb4200003, 0x033f400f, + 0x9b394000, 0xb500000b, 0x9739bfff, 0x82e50061, + 0x96f70008, 0xb0170008, 0xb4000005, 0x5eefb818, + 0x96f70003, 0xb0170003, 0xb4000001, 0x9718ffff, + 0x83060081, 0x83070001, 0x8306009f, 0x00000000, + 0xb5000075, 0x82850083, 0x96b400ff, 0xb015003c, + 0xb4200019, 0x96b92000, 0xb0152000, 0xb4000002, + 0x9b392000, 0xb5000014, 0x9739d3ff, 0x82870000, + 0x82860087, 0x82870008, 0x82860083, 0x829bff78, + 0x82a7001f, 0xb0140400, 0xb4000001, 0x82a70010, + 0x82a600c9, 0x829bff78, 0x00000000, 0x828600cb, + 0x8285009d, 0x82b3ffff, 0x9ab5fffd, 0x1694b815, + 0x8286009d, 0xb5000000, 0x83070002, 0x8306009f, + 0x00000000, 0xb5000054, 0x96b90800, 0xb0150800, + 0xb4200009, 0x9739f7ff, 0x82a703fd, 0x82a600cb, + 0x82a7003c, 0x82a60083, 0x8285009d, 0x9a940002, + 0x8286009d, 0xb5000004, 0x82850087, 0x5a82b814, + 0xa2940200, 0x82860087, 0xb5000000, 0x83078000, + 0x8306009f, 0x00000000, 0xb500003f, 0x82850086, + 0x82a50094, 0x3015b814, 0xb4800002, 0x86b50bb8, + 0x82a60086, 0x83070008, 0x8306009f, 0x00000000, + 0xb5000035, 0x83050069, 0x9718003f, 0x82e50064, + 0x12f7b818, 0x86f70088, 0x82feff74, 0x02e7b86f, + 0x9af74000, 0x01ffb817, 0x96f7bfff, 0x01ffb817, + 0x83050081, 0x82f3001c, 0x9af703ff, 0x1718b817, + 0x9b180140, 0x83060081, 0x83070100, 0x8306009f, + 0x00000000, 0xb5000020, 0x83070000, 0x83050081, + 0x9b180180, 0x83060081, 0x83070400, 0x8306009f, + 0x00000000, 0xb5000018, 0x82870000, 0x82850082, + 0x5eb7b814, 0x96b500fc, 0x96d40006, 0x5ec1b816, + 0x1ab5b816, 0x5aacb815, 0x83050081, 0x82d3001c, + 0x9ad600ff, 0x1718b816, 0x1b18b815, 0x9b180e00, + 0x83060081, 0x83074000, 0x8306009f, 0x8305009d, + 0x82d300ff, 0x9ad6bfff, 0x1718b816, 0x8306009d, + 0x00000000, 0xb5000000, 0x029f9005, 0x01ffb814, + 0x033f600f, 0x029f900a, 0x02bf900b, 0x02df900c, + 0x02ff900d, 0x031f900e, 0x033f900f, 0x00ffb81e, + 0x02ff9010, 0x92f70b43, 0x02ffb010, 0x02ff90cb, + 0x82bbffdc, 0x829bffd8, 0x93150004, 0x3014b815, + 0xb4000010, 0x02dbb818, 0x029bb815, 0x3017b816, + 0xb480000c, 0x5a81b814, 0x029fb010, 0x82860095, + 0x8293001f, 0x9294fe00, 0x92b50008, 0x3015b814, + 0xb4800002, 0x82b3001f, 0x92b5fa00, 0x82beffdc, + 0xb500ffeb, 0x029f9010, 0x83250094, 0x06d4b819, + 0x02d6b816, 0xb016ffff, 0xb4a0000a, 0x8293000e, + 0x9a948001, 0x82c5009d, 0x96d6ffff, 0x1a94b816, + 0x82c5009a, 0x96d60010, 0xb0160010, 0xb4000001, + 0x8286009d, 0x00ffb81c, 0x00000000, 0x00000000, + 0x001f9012, 0x001fb100, 0x001f004c, 0x001f2404, + 0x801bfef0, 0x8058fef4, 0x803bff68, 0x8078ff6c, + 0x2000b801, 0x2042b803, 0x001fb104, 0x005f2414, + 0x82e70001, 0x83640048, 0x029fb014, 0x829efef0, + 0x8286000f, 0x02bf2054, 0x82bcfef4, 0x82a6000e, + 0x00ffb81a, 0x80e70001, 0x801336e3, 0x9800eb76, + 0x001fb100, 0x800700ab, 0x001f2404, 0x801bc3e8, + 0x8058c3ec, 0x83640024, 0x82e70000, 0x83640036, + 0x029fb300, 0x029fb100, 0x02bf2c04, 0x02bf2404, + 0x801bc000, 0x8058c004, 0x8364001b, 0x82e70000, + 0x8364002d, 0x001f9300, 0x3000b814, 0xb420000a, + 0x001f0c04, 0x3000b815, 0xb4200007, 0x829efef0, + 0x82bcfef4, 0x029fb012, 0x02bf204c, 0x82870001, + 0x829cfef5, 0x00ffb81a, 0xb0070000, 0xb4000007, + 0x80e70000, 0x801399fa, 0x9800c92e, 0x001fb100, + 0x800700af, 0x001f2404, 0xb500ffdc, 0x82870000, + 0x829cfef5, 0x00ffb81a, 0x80c700ff, 0x803bff68, + 0x8078ff6c, 0x14a0b806, 0x2063b805, 0x007f2414, + 0x2021b802, 0x58c8b806, 0x14a0b806, 0x58b0b805, + 0x2021b805, 0x58c8b806, 0x14a0b806, 0x2021b805, + 0x58c8b806, 0x14a0b806, 0x5cb0b805, 0x2021b805, + 0x003fb104, 0x00ffb81b, 0x82c70000, 0x83070400, + 0x83270005, 0x8197040c, 0x81d7ffff, 0x83840126, + 0x83840001, 0x00ffb81b, 0x808f0000, 0x806f001f, + 0x80af001f, 0x80270140, 0x81e70228, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x80270180, 0x81e70120, 0x5de2b80f, + 0xb6000208, 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, + 0x01cfb80f, 0x01ff90bc, 0xb520ffff, 0x91ef0020, + 0x90210020, 0x8057ffff, 0x80170430, 0x80070410, + 0x80270408, 0xb6000509, 0x005ff000, 0x90420500, + 0x007ff001, 0x90630600, 0x009ff002, 0x00bff003, + 0x2004a025, 0x90000001, 0x90210001, 0x80070414, + 0x80d7ffff, 0x8097045c, 0x8017043c, 0xb6000404, + 0x005ff000, 0x007f87e0, 0x84000001, 0x2082a7e3, + 0x80970460, 0x80170440, 0x2082b803, 0x007f8000, + 0x2083a004, 0x80170430, 0x80970450, 0x80270408, + 0xb6000508, 0x005f8024, 0x90420500, 0x007ff001, + 0x90630600, 0x009ff002, 0x00bff003, 0x2004a025, + 0x90210001, 0x80170440, 0x00000000, 0x02bf87e0, + 0x80970460, 0x82870000, 0xb6000404, 0x005f87e4, + 0x5a88b814, 0x204287e0, 0x1a94b802, 0x00ffb81c, + 0x001f0a49, 0x001f2709, 0x001f0a41, 0x001f2708, + 0x001f0a46, 0x001f2707, 0x001f0a48, 0x001f2706, + 0x001f0a42, 0x001f2705, 0x001f0a47, 0x001f2704, + 0x001f0a45, 0x001f2703, 0x001f0a43, 0x001f2702, + 0x001f0a40, 0x001f2701, 0x001f0a44, 0x001f2700, + 0x001f0c25, 0xa020000c, 0x94400001, 0x94600002, + 0x94810004, 0x94a10008, 0x94c00010, 0x5943b802, + 0x5861b803, 0x5882b804, 0x5ca2b805, 0x5cc4b806, + 0x194ab803, 0x194ab804, 0x194ab805, 0x194ab806, + 0x015f2738, 0x801b0220, 0x003f91c1, 0x5c28b801, + 0x005f91c2, 0x5858b802, 0x1821b802, 0x2000b801, + 0x001fb1c4, 0x80180224, 0x003f0709, 0x2000b801, + 0x001f2714, 0x82c70001, 0x82e70001, 0x83070710, + 0x8327001e, 0x81970735, 0x8384009f, 0x02df0738, + 0x82170a30, 0x838400f1, 0x819efef0, 0x817cfef4, + 0x819eff68, 0x817cff6c, 0x00ffb81b, 0x820f001f, + 0x8018fef8, 0x8057ffff, 0x001f2709, 0x8018fef6, + 0x80d7ffff, 0x001f2708, 0x8018fefa, 0x8157ffff, + 0x001f2707, 0x8018fefd, 0x81d7ffff, 0x001f2706, + 0x8018fefb, 0x802f001f, 0x001f2705, 0x8018fefe, + 0x00000000, 0x001f2704, 0x8018fef9, 0x00000000, + 0x001f2703, 0x8018feff, 0x00000000, 0x001f2702, + 0x8018fef7, 0x00000000, 0x001f2701, 0x8018fefc, + 0x00000000, 0x001f2700, 0x001f0c25, 0xa0200011, + 0x94410001, 0x94600002, 0x94800004, 0x94a00008, + 0x94c10010, 0x5941b802, 0x5861b803, 0x5c82b804, + 0x58a1b805, 0x5cc1b806, 0x194ab803, 0x194ab804, + 0x194ab805, 0x194ab806, 0x015f2738, 0x801b0220, + 0x003f91c1, 0x5c28b801, 0x005f91c2, 0x5858b802, + 0x1821b802, 0x2000b801, 0x001fb1c4, 0x80180224, + 0x003f0709, 0x2000b801, 0x001f2714, 0x82c70001, + 0x82e70001, 0x83070710, 0x8327001e, 0x81970735, + 0x83840055, 0x02df0738, 0x82170a20, 0x838400a7, + 0x819efef0, 0x817cfef4, 0x5ac8b80c, 0x02ff0a44, + 0x1ad6b817, 0x02dfb291, 0x5ed8b80c, 0x5968b80b, + 0x1ad6b80b, 0x02df6524, 0x00ffb81b, 0x820f001f, + 0x8018fefe, 0x8057ffff, 0x001f2709, 0x8018fefa, + 0x80d7ffff, 0x001f2708, 0x8018fefc, 0x8157ffff, + 0x001f2707, 0x8018feff, 0x81d7ffff, 0x001f2706, + 0x8018fef8, 0x802f001f, 0x001f2705, 0x8018fefb, + 0x00000000, 0x001f2704, 0x8018fefd, 0x00000000, + 0x001f2703, 0x8018fef6, 0x00000000, 0x001f2702, + 0x8018fef9, 0x00000000, 0x001f2701, 0x8018fef7, + 0x00000000, 0x001f2700, 0x801b0220, 0x003f91c1, + 0x5c28b801, 0x005f91c2, 0x5858b802, 0x1821b802, + 0x2000b801, 0x001fb1c4, 0x80180224, 0x003f0709, + 0x2000b801, 0x001f2714, 0x82c70001, 0x82e70001, + 0x83070710, 0x8327001e, 0x81970735, 0x83840016, + 0x83270000, 0x831bfef0, 0x82f8fef4, 0x02c7b819, + 0x82170a28, 0x83840065, 0x300cb818, 0xb4200002, + 0x300bb817, 0xb4000006, 0x93390001, 0xb0190020, + 0xb480fff6, 0x83270000, 0x833cfef5, 0x00ffb81b, + 0x019fb290, 0x017f2a44, 0x033f2c25, 0x83270001, + 0x833cfef5, 0x00ffb81b, 0x0007b818, 0x90000003, + 0x00000000, 0x015ff000, 0x90000001, 0x5949b80a, + 0x013ff000, 0x194ab809, 0x84000002, 0x994a0100, + 0x017ff000, 0x958b00f8, 0x5981b80c, 0x956b0007, + 0x198cb80b, 0x84000002, 0x998c0008, 0x017ff000, + 0x90000001, 0x5971b80b, 0x198cb80b, 0x017ff000, + 0x5969b80b, 0x198cb80b, 0x81a70000, 0x94d90003, + 0x82a70000, 0xb6260019, 0xb6000818, 0x5df0b80a, + 0x5e02b80a, 0x21efb810, 0x95ef0001, 0x5941b80a, + 0x194ab80f, 0x21efb816, 0x5e18b80c, 0x5e35b80c, + 0x5e54b80c, 0x5e6cb80c, 0x2210b811, 0x2252b813, + 0x2210b812, 0x96100001, 0x5981b80c, 0x198cb810, + 0x2210b817, 0x10afb810, 0x10a5b80d, 0x5da1b805, + 0x94a50001, 0x5aa1b815, 0x1ab5b805, 0x019fa7f5, + 0x5cc2b819, 0xb626001c, 0x82870000, 0xb6000419, + 0xb6000818, 0x5df0b80a, 0x5e02b80a, 0x21efb810, + 0x95ef0001, 0x5941b80a, 0x194ab80f, 0x21efb816, + 0x5e18b80c, 0x5e35b80c, 0x5e54b80c, 0x5e6cb80c, + 0x2210b811, 0x2252b813, 0x2210b812, 0x96100001, + 0x5981b80c, 0x198cb810, 0x2210b817, 0x10afb810, + 0x10a5b80d, 0x5da1b805, 0x94a50001, 0x5a81b814, + 0x1a94b805, 0x019fa7f4, 0x00ffb81c, 0x8257ffff, + 0x808f0000, 0x806f001f, 0x80af001f, 0x80270200, + 0x81e7ff00, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270240, + 0x81e70000, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x80270180, + 0x81e70120, 0x5de2b80f, 0xb6000208, 0x00cfb801, + 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, 0x01ff90bc, + 0xb520ffff, 0x91ef0020, 0x90210020, 0x806f0007, + 0x80af0007, 0x80270280, 0x81e70100, 0x5de2b80f, + 0x00cfb801, 0x01ffb0bc, 0x59e2b80f, 0x01cfb80f, + 0x01ff90bc, 0xb520ffff, 0x91ef0020, 0x90210020, + 0x80170760, 0x001f0700, 0x001fa020, 0x001f0701, + 0x001fa020, 0x001f0702, 0x001fa020, 0x001f0703, + 0x001fa020, 0x001f0704, 0x001fa000, 0x80970750, + 0x81170770, 0x82a70735, 0x83a40060, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4005c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a70730, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40050, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a4004c, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a7072b, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a40040, 0x83a4004e, + 0xb6000407, 0x86b50001, 0x83a4003c, 0x001f8004, + 0x003f87e8, 0x2080a001, 0x83a40047, 0x00000000, + 0x80970770, 0x80170750, 0x81170750, 0x81970740, + 0x82a70726, 0x001f800c, 0x003f8008, 0x2100a001, + 0x83a4002e, 0x83a4003c, 0xb6000407, 0x86b50001, + 0x83a4002a, 0x001f8004, 0x003f87e8, 0x2080a001, + 0x83a40035, 0x00000000, 0x80970750, 0x80170770, + 0x81170770, 0x81970760, 0x82a70721, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4001c, 0x001f87e4, + 0xb6000405, 0x86b50001, 0x83a40018, 0x001f8004, + 0x003f87e8, 0x2080a7e1, 0x80970770, 0x80170750, + 0x81170750, 0x81970740, 0x82a7071c, 0x001f800c, + 0x003f8008, 0x2100a001, 0x83a4000c, 0x017f87e4, + 0x81870000, 0xb6000406, 0x86b50001, 0x83a40007, + 0x001f87e4, 0x200087e8, 0x5988b80c, 0x198cb800, + 0x021fa02c, 0x021fa00b, 0x00ffb81c, 0x005ff015, + 0x90420600, 0x003f87e0, 0x001ff002, 0x2060b801, + 0x90630800, 0x90960a00, 0x001ff003, 0x003ff004, + 0x20a0b801, 0x90a50900, 0x00000000, 0x001ff005, + 0x009fa000, 0x00ffb81d, 0x001f8004, 0x5c21b800, + 0x5847b800, 0x1821b802, 0x942100ff, 0x2080a7e1, + 0x00ffb81d, 0x00000000, 0x00000000, 0x00000000, + 0x829bff80, 0x80af000f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60010, 0x90210010, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6001005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6001018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6002004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb4000099, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb4000022, 0xb00a0003, + 0xb400002f, 0xb00a0004, 0xb400005d, 0xb00a0005, + 0xb4000066, 0xb00a0006, 0xb400008a, 0xb00a0007, + 0xb4000088, 0xb00a0008, 0xb4000086, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004010, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x5c708028, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000070, 0x81df0000, 0x00000000, 0x00000000, + 0x8027ffff, 0xb6004008, 0x14618008, 0x019fa023, + 0x019fa020, 0x019fa020, 0x5c708028, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb5000061, + 0xb0130000, 0xb4000004, 0xb0130001, 0xb4000009, + 0xb0130002, 0xb400001a, 0x83a40102, 0x80170f00, + 0x007f8028, 0x001fa023, 0x007f8028, 0x001fa023, + 0xb5000054, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8000, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400ed, + 0x80170f00, 0x007f8028, 0x001fa023, 0xb5000041, + 0x80170f00, 0x00000000, 0x007f8020, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x83a400da, 0xb5000031, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002005, + 0x007f8008, 0x019fa023, 0x007f8008, 0x019fa023, + 0x019fa020, 0x81df0004, 0xb5000026, 0xb0130000, + 0xb4000008, 0xb0130001, 0xb4000012, 0xb0130002, + 0xb400001f, 0xb0130003, 0xb400001d, 0xb0130004, + 0xb400001b, 0x83a400d5, 0x007f8028, 0x019fa023, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000010, 0x80170f00, 0x00000000, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x83a400bf, + 0x80170f00, 0x007f8028, 0x001fa023, 0xb5000001, + 0xb5000000, 0x00000000, 0x00000000, 0xb500008e, + 0xb00a0001, 0xb400000e, 0xb00a0002, 0xb400001a, + 0xb00a0003, 0xb4000027, 0xb00a0004, 0xb4000055, + 0xb00a0005, 0xb400005e, 0xb00a0006, 0xb4000082, + 0xb00a0007, 0xb4000080, 0xb00a0008, 0xb400007e, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004008, + 0x007f8028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x019fa020, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000070, 0x81df0000, 0x00000000, + 0x00000000, 0x8027ffff, 0xb6002008, 0x14618008, + 0x019fa023, 0x019fa020, 0x019fa020, 0x5c708048, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a40098, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40083, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a40070, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a4006b, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a40055, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x92730001, 0x92520001, + 0x3012b811, 0xb480fe76, 0x003f0324, 0x90210001, + 0xb0010006, 0xb4a00001, 0x80270001, 0x003f2324, + 0x2c8db811, 0x803bffe0, 0x805bffe4, 0x5886b804, + 0x1015b804, 0xad440003, 0x3000b802, 0xb4800001, + 0x8400a000, 0x801effec, 0x015f6193, 0x809e4b04, + 0x00ffb81f, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002a0c, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x81df0004, 0x00ffb81d, 0x81df0000, 0x00000000, + 0x00000000, 0xb600190f, 0x007f8028, 0x019fa023, + 0x007f8028, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x81df0004, 0x00ffb81d, 0x00000000, + 0x829bff80, 0x80af001f, 0x808f0000, 0x806f0000, + 0x82bbffec, 0x82fbffe4, 0x00000000, 0x82beffb8, + 0x95540700, 0x5d48b80a, 0x914a0001, 0x0227b80a, + 0x94343000, 0x5c2cb801, 0xb0010000, 0xb4000001, + 0x5a21b811, 0x9574c000, 0x5d6eb80b, 0x918b4b08, + 0x01b8b80c, 0x96d5ffff, 0x5ec2b816, 0x96f7ffff, + 0x5ee2b817, 0x8057ffff, 0x80d7ffff, 0x8157ffff, + 0x81d7ffff, 0x81f3ff00, 0x99efff00, 0x821300ff, + 0x9a1000ff, 0x81971000, 0x82670000, 0x82470000, + 0x80270280, 0x81df0000, 0x00000000, 0x00000000, + 0xb62d000d, 0x3016b817, 0xb4800001, 0x86d62800, + 0x00cfb801, 0x02dfb0bc, 0x5ac2b816, 0x01cfb816, + 0x02df90bc, 0x0067b86f, 0xb0030001, 0xb4c0fffd, + 0x92d60020, 0x90210020, 0x81df0004, 0x80170a00, + 0x81df0000, 0x00000000, 0x00000000, 0xb62d0006, + 0xb6002005, 0x146f8000, 0x14908000, 0x5c68b803, + 0x5888b804, 0x1803a024, 0x81df0004, 0x80170a00, + 0x80970d00, 0xb00b0000, 0xb4000004, 0xb00b0001, + 0xb400000a, 0xb00b0002, 0xb4000027, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008002, 0x007f8020, + 0x009fa023, 0x81df0004, 0xb5000029, 0x80d3ffff, + 0x81df0000, 0x00000000, 0x00000000, 0xb6002018, + 0x5c648000, 0x9463ffff, 0x5c888020, 0x58b88000, + 0x1884b805, 0x1484b806, 0x1883a024, 0x5c6c8020, + 0x9463ffff, 0x58908000, 0x1883a024, 0x5c748020, + 0x588c8000, 0x1863b804, 0x9463ffff, 0x58888000, + 0x1484b806, 0x1883a024, 0x5c7c8020, 0x58848000, + 0x1863b804, 0x9463ffff, 0x14868020, 0x1883a024, + 0x81df0004, 0xb500000a, 0x80d3ffff, 0x81df0000, + 0x00000000, 0x00000000, 0xb6004004, 0x007f8020, + 0x009fa023, 0x007f8040, 0x009fa023, 0x81df0004, + 0x00000000, 0x81170d00, 0x80070000, 0x94343000, + 0x5c2cb801, 0xb0010001, 0xb400008e, 0xb00a0001, + 0xb400000e, 0xb00a0002, 0xb400001c, 0xb00a0003, + 0xb4000024, 0xb00a0004, 0xb4000052, 0xb00a0005, + 0xb400005b, 0xb00a0006, 0xb400007f, 0xb00a0007, + 0xb400007d, 0xb00a0008, 0xb400007b, 0x81df0000, + 0x00000000, 0x00000000, 0xb600800a, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x019fa020, + 0x5c708028, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x019fa020, 0x81df0004, 0xb500006b, 0x81df0000, + 0x00000000, 0x00000000, 0xb6008004, 0x007f8028, + 0x019fa023, 0x019fa020, 0x019fa020, 0x81df0004, + 0xb5000061, 0xb0130000, 0xb4000004, 0xb0130001, + 0xb4000009, 0xb0130002, 0xb400001a, 0x83a400fa, + 0x80170f00, 0x007f8028, 0x001fa023, 0x007f8028, + 0x001fa023, 0xb5000054, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8000, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708020, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a400e5, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000041, 0x80170f00, 0x00000000, 0x007f8020, + 0x019fa023, 0x007f8008, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x019fa020, 0x83a400d2, + 0xb5000031, 0x81df0000, 0x00000000, 0x00000000, + 0xb6004005, 0x007f8008, 0x019fa023, 0x007f8008, + 0x019fa023, 0x019fa020, 0x81df0004, 0xb5000026, + 0xb0130000, 0xb4000008, 0xb0130001, 0xb4000012, + 0xb0130002, 0xb400001f, 0xb0130003, 0xb400001d, + 0xb0130004, 0xb400001b, 0x83a400cd, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000010, 0x80170f00, 0x00000000, + 0x5c708020, 0x58908008, 0x1983a024, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x83a400b7, 0x80170f00, 0x007f8028, 0x001fa023, + 0xb5000001, 0xb5000000, 0x00000000, 0x00000000, + 0xb5000086, 0xb00a0001, 0xb400000e, 0xb00a0002, + 0xb4000017, 0xb00a0003, 0xb400001f, 0xb00a0004, + 0xb400004d, 0xb00a0005, 0xb4000056, 0xb00a0006, + 0xb400007a, 0xb00a0007, 0xb4000078, 0xb00a0008, + 0xb4000076, 0x81df0000, 0x00000000, 0x00000000, + 0xb6008005, 0x007f8028, 0x9463ffff, 0x019fa023, + 0x019fa020, 0x019fa020, 0x81df0004, 0xb500006b, + 0x81df0000, 0x00000000, 0x00000000, 0xb6004004, + 0x007f8048, 0x019fa023, 0x019fa020, 0x019fa020, + 0x81df0004, 0xb5000061, 0xb0130000, 0xb4000004, + 0xb0130001, 0xb4000009, 0xb0130002, 0xb400001a, + 0x83a40098, 0x80170f00, 0x007f8028, 0x001fa023, + 0x007f8028, 0x001fa023, 0xb5000054, 0x80170f00, + 0x00000000, 0x007f8020, 0x019fa023, 0x007f8000, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708020, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x83a40083, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000041, 0x80170f00, 0x00000000, + 0x007f8020, 0x019fa023, 0x007f8008, 0x9463ffff, + 0x019fa023, 0x019fa020, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x019fa020, + 0x83a40070, 0xb5000031, 0x81df0000, 0x00000000, + 0x00000000, 0xb6004005, 0x007f8008, 0x019fa023, + 0x007f8008, 0x019fa023, 0x019fa020, 0x81df0004, + 0xb5000026, 0xb0130000, 0xb4000008, 0xb0130001, + 0xb4000012, 0xb0130002, 0xb400001f, 0xb0130003, + 0xb400001d, 0xb0130004, 0xb400001b, 0x83a4006b, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x80170f00, + 0x007f8028, 0x001fa023, 0xb5000010, 0x80170f00, + 0x00000000, 0x5c708020, 0x58908008, 0x1983a024, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x83a40055, 0x80170f00, 0x007f8028, + 0x001fa023, 0xb5000001, 0xb5000000, 0x92730001, + 0x92520001, 0x3012b811, 0xb480fe89, 0x003f0324, + 0x90210001, 0xb0010006, 0xb4a00001, 0x80270001, + 0x003f2324, 0x2c8db811, 0x803bffe0, 0x805bffe4, + 0x5887b804, 0x1015b804, 0xad440003, 0x3000b802, + 0xb4800001, 0x8400a000, 0x801effec, 0x015f6193, + 0x809e4b04, 0x00ffb81f, 0x81df0000, 0x00000000, + 0x00000000, 0xb6002a0c, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x019fa020, + 0x5c708028, 0x58908008, 0x1983a024, 0x5c708028, + 0x019fa023, 0x019fa020, 0x81df0004, 0x00ffb81d, + 0x81df0000, 0x00000000, 0x00000000, 0xb600190f, + 0x007f8028, 0x019fa023, 0x007f8028, 0x019fa023, + 0x007f8008, 0x9463ffff, 0x019fa023, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x019fa023, 0x81df0004, + 0x00ffb81d, 0x81df0000, 0x00000000, 0x00000000, + 0xb6002a0c, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x019fa020, 0x5c708028, + 0x58908008, 0x1983a024, 0x5c708028, 0x019fa023, + 0x019fa020, 0x81df0004, 0x00ffb81d, 0x81df0000, + 0x00000000, 0x00000000, 0xb600190f, 0x007f8028, + 0x019fa023, 0x007f8028, 0x019fa023, 0x007f8008, + 0x9463ffff, 0x019fa023, 0x5c708028, 0x58908008, + 0x1983a024, 0x5c708028, 0x58908008, 0x1983a024, + 0x5c708028, 0x019fa023, 0x81df0004, 0x00ffb81d, + 0x003f03f9, 0x009f0324, 0x84840001, 0xb0010000, + 0xb4000011, 0x815b4b0c, 0x81070000, 0x81270be8, + 0xb00a0000, 0xb4000002, 0x81070c00, 0x812717e8, + 0x802500a5, 0x806500a5, 0x3001b803, 0xb420fffc, + 0x9421ffff, 0x3001b808, 0xb480000b, 0x3001b809, + 0xb4a00060, 0xb5000008, 0xb0040000, 0xb4200003, + 0x802717ff, 0x81470000, 0xb5000003, 0x80270001, + 0x003f23f9, 0x81470c00, 0xb0040000, 0xb4200006, + 0x039f4193, 0x5b81b81c, 0x003f90cb, 0x1021b81c, + 0x003fb0cb, 0x8384f90e, 0x829bff80, 0x801300e0, + 0x1434b800, 0x5c35b801, 0x8013001f, 0x1454b800, + 0x5c50b802, 0x8073007f, 0x9863ffff, 0xb002000f, + 0xb4800001, 0x90210001, 0x84210004, 0xb0010000, + 0xb4a00001, 0x6861b803, 0x005f9040, 0x4082b803, + 0x80af001f, 0x808f0000, 0x806f0000, 0x8007ffff, + 0x8033ffff, 0x80171000, 0x81df0000, 0x00000000, + 0x00000000, 0xb6001811, 0xb6002010, 0x14618000, + 0x6068b803, 0x40c4b803, 0x14608000, 0x00c8b806, + 0x5870b803, 0x6068b803, 0x4104b803, 0x58c8b806, + 0x0108b808, 0x14c6b801, 0x00000000, 0x00000000, + 0x5d08b808, 0x1508b800, 0x1806a028, 0x81df0004, + 0x80670400, 0x5d22b80a, 0x81df0000, 0x00000000, + 0x00000000, 0xb600180a, 0x00cfb803, 0x013fb0bc, + 0x5922b809, 0x01afb809, 0x013f90bc, 0x0047b86f, + 0xb0020001, 0xb4c0fffd, 0x90630020, 0x91290020, + 0x81df0004, 0x808f0000, 0x801b4b14, 0x80270001, + 0xb0000001, 0xb4000002, 0x802600a0, 0x803e4b14, + 0x81270c00, 0xb00a0000, 0xb4000001, 0x81270000, + 0x813e4b0c, 0x80270001, 0x003f2013, 0x80050086, + 0x001fb044, 0x00ffb81b, 0x00000000, 0x00000000, +}; + +static u32 PCMI2SUcode1f4b00[] = { + 0x00000000, 0x00000000, 0x00060504, 0x00000000, + 0x00000000, 0x00000000, 0x00300000, 0xffcfcfff, + 0x00302000, 0xffcfcfff, 0x00380000, 0xffc7c7ff, + 0xcbcecdc4, 0xcfcac9c8, 0xc3c6c5cc, 0xc7c2c1c0, + 0x1b1e1d14, 0x1f1a1918, 0x1316151c, 0x17121110, + 0x2b2e2d24, 0x2f2a2928, 0x2326252c, 0x27222120, + 0x3b3e3d34, 0x3f3a3938, 0x3336353c, 0x37323130, + 0x0b0e0d04, 0x0f0a0908, 0x0306050c, 0x07020100, + 0xdbdeddd4, 0xdfdad9d8, 0xd3d6d5dc, 0xd7d2d1d0, + 0xebeeede4, 0xefeae9e8, 0xe3e6e5ec, 0xe7e2e1e0, + 0xfbfefdf4, 0xfffaf9f8, 0xf3f6f5fc, 0xf7f2f1f0, + 0x4b4e4d44, 0x4f4a4948, 0x4346454c, 0x47424140, + 0x9b9e9d94, 0x9f9a9998, 0x9396959c, 0x97929190, + 0xabaeada4, 0xafaaa9a8, 0xa3a6a5ac, 0xa7a2a1a0, + 0xbbbebdb4, 0xbfbab9b8, 0xb3b6b5bc, 0xb7b2b1b0, + 0x8b8e8d84, 0x8f8a8988, 0x8386858c, 0x87828180, + 0x5b5e5d54, 0x5f5a5958, 0x5356555c, 0x57525150, + 0x6b6e6d64, 0x6f6a6968, 0x6366656c, 0x67626160, + 0x7b7e7d74, 0x7f7a7978, 0x7376757c, 0x77727170, + 0x341424c4, 0x3e1e2ece, 0x3d1d2dcd, 0x3b1b2bcb, + 0xb494a444, 0xbe9eae4e, 0xbd9dad4d, 0xbb9bab4b, + 0xf4d4e404, 0xfedeee0e, 0xfddded0d, 0xfbdbeb0b, + 0x74546484, 0x7e5e6e8e, 0x7d5d6d8d, 0x7b5b6b8b, + 0x3c1c2ccc, 0x361626c6, 0x351525c5, 0x331323c3, + 0xbc9cac4c, 0xb696a646, 0xb595a545, 0xb393a343, + 0xfcdcec0c, 0xf6d6e606, 0xf5d5e505, 0xf3d3e303, + 0x7c5c6c8c, 0x76566686, 0x75556585, 0x73536383, + 0x381828c8, 0x3a1a2aca, 0x391929c9, 0x3f1f2fcf, + 0xb898a848, 0xba9aaa4a, 0xb999a949, 0xbf9faf4f, + 0xf8d8e808, 0xfadaea0a, 0xf9d9e909, 0xffdfef0f, + 0x78586888, 0x7a5a6a8a, 0x79596989, 0x7f5f6f8f, + 0x301020c0, 0x321222c2, 0x311121c1, 0x371727c7, + 0xb090a040, 0xb292a242, 0xb191a141, 0xb797a747, + 0xf0d0e000, 0xf2d2e202, 0xf1d1e101, 0xf7d7e707, + 0x70506080, 0x72526282, 0x71516181, 0x77576787, + 0x05040100, 0x15141110, 0x25242120, 0x35343130, + 0x85848180, 0x95949190, 0xa5a4a1a0, 0xb5b4b1b0, + 0xc0408000, 0xe060a020, 0xd0509010, 0xf070b030, + 0xc8488808, 0xe868a828, 0xd8589818, 0xf878b838, + 0xc4448404, 0xe464a424, 0xd4549414, 0xf474b434, + 0xcc4c8c0c, 0xec6cac2c, 0xdc5c9c1c, 0xfc7cbc3c, + 0xc2428202, 0xe262a222, 0xd2529212, 0xf272b232, + 0xca4a8a0a, 0xea6aaa2a, 0xda5a9a1a, 0xfa7aba3a, + 0xc6468606, 0xe666a626, 0xd6569616, 0xf676b636, + 0xce4e8e0e, 0xee6eae2e, 0xde5e9e1e, 0xfe7ebe3e, + 0xc1418101, 0xe161a121, 0xd1519111, 0xf171b131, + 0xc9498909, 0xe969a929, 0xd9599919, 0xf979b939, + 0xc5458505, 0xe565a525, 0xd5559515, 0xf575b535, + 0xcd4d8d0d, 0xed6dad2d, 0xdd5d9d1d, 0xfd7dbd3d, + 0xc3438303, 0xe363a323, 0xd3539313, 0xf373b333, + 0xcb4b8b0b, 0xeb6bab2b, 0xdb5b9b1b, 0xfb7bbb3b, + 0xc7478707, 0xe767a727, 0xd7579717, 0xf777b737, + 0xcf4f8f0f, 0xef6faf2f, 0xdf5f9f1f, 0xff7fbf3f, + 0x1045a3e2, 0x000000f4, 0x263b7333, 0x766b2363, + 0x2b367e3e, 0x7b662e6e, 0x06db93d3, 0x964b0343, + 0x0bd69ede, 0x9b460e4e, 0x825f1757, 0x12cf87c7, + 0x8f521a5a, 0x1fc28aca, 0x00d199d9, 0x90410949, + 0x01d098d8, 0x91400848, 0x24357d3d, 0x74652d6d, + 0x25347c3c, 0x75642c6c, 0x04d59ddd, 0x94450d4d, + 0x05d49cdc, 0x95440c4c, 0x80511959, 0x10c189c9, + 0x81501858, 0x11c088c8, 0x02df97d7, 0x924f0747, + 0x0fd29ada, 0x9f420a4a, 0x865b1353, 0x16cb83c3, + 0x8b561e5e, 0x1bc68ece, 0xa6bbf3b3, 0xf6eba3e3, + 0xabb6febe, 0xfbe6aeee, 0x223f7737, 0x726f2767, + 0x2f327a3a, 0x7f622a6a, 0xa0b1f9b9, 0xf0e1a9e9, + 0xa1b0f8b8, 0xf1e0a8e8, 0x84551d5d, 0x14c58dcd, + 0x85541c5c, 0x15c48ccc, 0xa4b5fdbd, 0xf4e5aded, + 0xa5b4fcbc, 0xf5e4acec, 0x20317939, 0x70612969, + 0x21307838, 0x71602868, 0xa2bff7b7, 0xf2efa7e7, + 0xafb2faba, 0xffe2aaea, 0x00000000, 0x00000000, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/luxsonor.c linux.20pre2-ac1/drivers/media/video/luxsonor.c --- linux.20pre2/drivers/media/video/luxsonor.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/luxsonor.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,2123 @@ +/* + * Luxsonor LS220/LS240 series DVD/Mpeg card drivers + * + * (c) Copyright 2002 Red Hat + * + * 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 + * + * Made possible by Luxsonor's rather nice gesture of publishing their + * windows code to allow people to write new drivers based on it. + * + * The firmware is (c) Copyright Luxsonor and a seperate program run + * on the dsp not part of Linux itself. + * + * Note: the hardware css is not supported as Luxsonor decided not to + * document it even though the chip can do all the work. The citizens + * of free countries will need to use software decryption to play such + * films via the card. US citizens should simply report to the district + * attorney for termination. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * Firmware modules + */ + +#include "ls220/ac3.h" +#include "ls220/ac3_240.h" +#include "ls220/ac3i2s.h" +#include "ls220/ac3i2s_240.h" + +#include "ls220/mpg.h" +#include "ls220/mpg_240.h" +#include "ls220/mpgi2s.h" +#include "ls220/mpgi2s_240.h" + +#include "ls220/pcm.h" +#include "ls220/pcm_240.h" +#include "ls220/pcmi2s.h" +#include "ls220/pcmi2s_240.h" + +/* + * Board types + */ + +#define LS220C 0 +#define LS220D 1 +#define LS240 2 + +static char *lux_names[3] = { "LS220C", "LS220D", "LS240" }; + +/* + * TV encoder types + */ + +#define BT865 0 +#define BT864 1 +#define SAA7120 2 +#define SAA7121 3 +#define AD7175 4 +#define AD7176 5 +#define CS4953 6 +#define CS4952 7 +#define HS8171 8 +#define HS8170 9 + +static char *lux_tv_names[10] = { + "BT865", "BT864", "SAA7120", "SAA7121", "AD7175", + "AD7176", "CS4953", "CS4952", "HS8171", "HS8170" +}; + +/* + * EEPROM bytes + */ + +#define EPROM_REGION 0x4 +#define EPROM_REGION_COUNT 0x5 +#define EPROM_PARENTAL 0x6 +#define EPROM_BOARDTYPE 0x7 +#define EPROM_CLOCKTYPE 0x8 +#define EPROM_I2S 0x9 +#define EPROM_SPDIF_CH 0xa +#define EPROM_SPDIF_ONOFF 0xb +#define EPROM_TVOUT 0xc +#define EPROM_LEFT_CH_POL 0xf + +/* + * Registers + */ + +/* -- for field lock use -- */ +#define CHANGE_MPGVID_CONTROL +#define CHANGE_REG274 +#define DO_NOT_TOUCH_REG324 + + +#define LS220_DRAM_BASE 0x200000L +#define LS240_DRAM_BASE 0x400000L + +#define DRAM_BASE(dev) ((dev)->dram_base) + +#define VID_FIFO_OFF 0x1a3000L +#define VID_FIFO_LEN 0x3e000L +#define PTS_FIFO_OFF 0x1a2800L +#define PTS_FIFO_LEN 0x800L +#define SUB_FIFO_OFF 0x1e2000L +#define OSD_FIFO_OFF 0x1e1000L +#define OSD_FIFO_LEN 0x1000L +#define LS220_VID_FIFO(dev) (dev->dram_base+VID_FIFO_OFF) + +#define DSPMEM_BASE(dev) (dev->dram_base+0x1f0000L) +#define DSPPROG_BASE(dev) (DSPMEM_BASE(dev)-dev->dram_base) +#define DSPPROG_OFF 0x1800L +#define DSPPROG_SIZE 0x6000L + + +#define AUD_FIFO_LEN 0x2000L +#define AUD_FIFO_OFF 0x1fc000L +#define AUD_PTS_LEN 0x400L +#define AUD_PTS_OFF 0x1ffa00L + +/* Subpict definition */ +#define FIFO_SIZE 8 /* PTS FIFO entry count */ +#define HIGH_FIFO 32 /* HighLight Fifo size */ +#define SCRM_FIFO 0x800 /* Scramble buffer size */ +#define SPBLOCK ( 0xE000 - HIGH_FIFO - SCRM_FIFO ) /* 56K - 32 bytes - 2k */ +#define SubBLOCK 0xE00 /* PTS + DCI = 3.5K */ +#define DCIBLOCK ( SubBLOCK - 8*FIFO_SIZE ) +#define PxdBLOCK ( SPBLOCK - SubBLOCK ) +#define FStart 0x20 /* PTS FIFO Start Address */ + +#define SUBBASE(dev) ( DRAM_BASE(dev) + SUB_FIFO_OFF ) + +#define LS220_DSP_REG 0x100L +#define LS220_MPG_REG 0x180L +#define LS220_SYNC_REG 0x200L +#define LS220_PCM_REG 0x280L +#define LS220_VID_REG 0x300L + +/* SYNC REGS */ +#define SYNC_AUD_CONTROL (LS220_SYNC_REG+0x00) +#define SYNC_VID_CONTROL (LS220_SYNC_REG+0x04) +#define SYNC_WAIT_LINE (LS220_SYNC_REG+0x0c) +#define SYNC_FRAME_PERIOD (LS220_SYNC_REG+0x10) +#define SYNC_STC (LS220_SYNC_REG+0x18) +#define PTS_FIFO_START (LS220_SYNC_REG+0x20) +#define PTS_FIFO_END (LS220_SYNC_REG+0x24) +#define PTS_FIFO_WRITE (LS220_SYNC_REG+0x28) +#define PTS_FIFO_READ (LS220_SYNC_REG+0x2c) +#define SYNC_VIDEO_PTS (LS220_SYNC_REG+0x50) +#define SYNC_INT_CTRL (LS220_SYNC_REG+0x74) +#define SYNC_INT_FORCE (LS220_SYNC_REG+0x78) + +/* MPEG VIDEO REGS */ +#define MPGVID_CONTROL (LS220_MPG_REG+0x0) +#define MPGVID_SETUP (LS220_MPG_REG+0x4) +#define MPGVID_FIFO_START (LS220_MPG_REG+0x8) +#define MPGVID_FIFO_END (LS220_MPG_REG+0xc) +#define MPGVID_FIFO_POS (LS220_MPG_REG+0x10) +#define MPGVID_FIFO_FORCE (LS220_MPG_REG+0x14) +#define MPGVID_FIFO_ADDBLOCK (LS220_MPG_REG+0x18) +#define MPGVID_FIFO_BYTES (LS220_MPG_REG+0x1c) +#define MPGVID_FIFO_INTLEVEL (LS220_MPG_REG+0x20) +#define MPGVID_TOTAL_BYTES (LS220_MPG_REG+0x24) +#define MPGVID_ERROR (LS220_MPG_REG+0x28) +#define MPGVID_MB_WIDTH (LS220_MPG_REG+0x2c) +#define MPGVID_MB_HEIGHT (LS220_MPG_REG+0x30) +#define MPGVID_DEBUG1 (LS220_MPG_REG+0x38) +#define MPGVID_DEBUG2 (LS220_MPG_REG+0x3c) + +/* VID_REG */ +#define VIDP_GPIO (LS220_VID_REG+0x50) + +/* PCM REG */ +#define PCM_FREQ_CONTROL (LS220_PCM_REG+0x0) +#define PCM_OUTPUT_CONTROL (LS220_PCM_REG+0x4) +#define PCM_FIFO_START (LS220_PCM_REG+0x8) +#define PCM_FIFO_END (LS220_PCM_REG+0xc) + +/* DSP REGS */ +#define DSP_CODE_ADDR (LS220_DSP_REG+0x0) + +/* DSP INTERAL MEMORY */ + +#define DSPMEM_DRV_RET(dev) (DSPMEM_BASE(dev)+0xfef0L) +#define DSPMEM_ACC(dev) (DSPMEM_BASE(dev)+0xfef5L) +#define DSPMEM_ACC4(dev) (DSPMEM_BASE(dev)+0xfef4L) +#define DSPMEM_CHAL_KEY(dev) (DSPMEM_BASE(dev)+0xfef6L) + +#define DSPMEM_LOCK(dev) (DSPMEM_BASE(dev)+0xff78L) + +#define DSPMEM_AUDIO_CONF(dev) (DSPMEM_BASE(dev)+0xff7cL) +#define DSPMEM_AC3_CONF(dev) (DSPMEM_BASE(dev)+0xff80L) + +#define DSPMEM_KARAOKE(dev) (DSPMEM_BASE(dev)+0xff8c) + +#define DSPMEM_INT_MASK(dev) (DSPMEM_BASE(dev)+0xffa4L) +#define DSPMEM_INT_STATUS(dev) (DSPMEM_BASE(dev)+0xffa8L) +#define DSPMEM_INT_THREHOLD(dev) (DSPMEM_BASE(dev)+0xffacL) + +#define DSPMEM_VOLUME_LEVEL(dev) (DSPMEM_BASE(dev)+0xffb0L) + +#define DSPMEM_PTS_START(dev) (DSPMEM_BASE(dev)+0xffd0L) +#define DSPMEM_PTS_END(dev) (DSPMEM_BASE(dev)+0xffd4L) +#define DSPMEM_PTS_WR(dev) (DSPMEM_BASE(dev)+0xffd8L) +#define DSPMEM_PTS_RD(dev) (DSPMEM_BASE(dev)+0xffdcL) + +#define DSPMEM_FIFO_START(dev) (DSPMEM_BASE(dev)+0xffe0L) +#define DSPMEM_FIFO_END(dev) (DSPMEM_BASE(dev)+0xffe4L) +#define DSPMEM_FIFO_WR(dev) (DSPMEM_BASE(dev)+0xffe8L) +#define DSPMEM_FIFO_RD(dev) (DSPMEM_BASE(dev)+0xffecL) + + +#define DSPMEM_CMD(dev) (DSPMEM_BASE(dev)+0xfff0L) +#define DSPMEM_STATUS(dev) (DSPMEM_BASE(dev)+0xfff8L) + + +#define DSP_CMD_NOP 0x00 +#define DSP_CMD_AC3 0x80 +#define DSP_CMD_MPEG1 0x81 +#define DSP_CMD_MPEG2 0x82 +#define DSP_CMD_PCM 0x83 + +#define DSP_CMD_PLAY 0x84 +#define DSP_CMD_STOPF 0x85 +#define DSP_CMD_PAUSE 0x86 +#define DSP_CMD_MUTE 0x87 +#define DSP_CMD_UNMUTE 0x88 +#define DSP_CMD_CONFIG 0x89 +#define DSP_CMD_VER 0x8a +#define DSP_CMD_STATUS 0x8b + +#define DSP_CMD_VOLUME 0x8c +#define DSP_CMD_INITDONE 0x8d + +#define DSP_CMD_FRAME 0xa0 +#define DSP_CMD_CLRAUTH 0xa1 +#define DSP_CMD_DECAUTH 0xa2 +#define DSP_CMD_DRVAUTH 0xa3 +#define DSP_CMD_KEYSHARE 0xa4 +#define DSP_CMD_DISCKEY 0xa5 +#define DSP_CMD_TITLEKEY 0xa6 + + +#define I2C_CLIENTS_MAX 16 + + +struct ls220_dev +{ + struct ls220_dev *next; + struct pci_dev *pdev; + void *membase; + int type; + u8 eprom[16]; + int has_eprom; + int tvencoder; + + u32 dram_base; + + u32 audio_fifo_off; + u32 audio_fifo_len; + + u32 audio_m_vol; + u32 audio_m_adj; + int audio_mute; + int audio_ac3; + + u32 audio_pts; + u32 audio_ptscount; + u32 audio_m_total; + u32 audio_speed; + + int audio_spdif; + + int spdif_first_play; + int stop_read; + + /* Buffer management */ + u8 audio_buffer[2048]; + u8 *audio_p; + u8 *audio_cp; + u16 audio_dlen; + + int video_mode; +#define VIDEO_PAL 0 +#define VIDEO_NTSC 1 + int video_mpeg1; + int video_hw_wrap; + int video_letter; + int video_zoomin; + int video_speed; + int video_pts; + int video_total; + int video_remainder; + int video_wptr; + int vga_mode; + + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_rc; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; +}; + +/* FIXME - spinlock the list */ +static struct ls220_dev *ls_devs; + +static int old = 1; /* Old v new style board */ + +/* + * Hardware access + */ + +static void ls220_dv_write(struct ls220_dev *dev, u32 offset, u32 data) +{ + writel(data, dev->membase+offset); +} + +static u32 ls220_dv_read(struct ls220_dev *dev, u32 offset) +{ + return readl(dev->membase+offset); +} + +static void ls220_write_dram(struct ls220_dev *dev, u32 offset, u32 data) +{ + writel(data, dev->membase+offset); +} + +static u32 ls220_read_dram(struct ls220_dev *dev, u32 offset) +{ + return readl(dev->membase+offset); +} + +static void ls220_memsetl(struct ls220_dev *dev, u32 offset, u32 fill, int len) +{ + int i; + for(i=0;idstoff, f->length); + if(f->dstoff) + { + for(i=0; ilength; i++) + { + ls220_write_dram(dev, DRAM_BASE(dev) + f->dstoff + 4 * i, f->firmware[i]); + if(ls220_read_dram(dev, DRAM_BASE(dev) + f->dstoff + 4 * i)!=f->firmware[i]) + { + printk("luxsonor: firmware upload error.\n"); + printk("%d: Got 0x%X want 0x%X\n", + i, ls220_read_dram(dev, DRAM_BASE(dev) + f->dstoff + 4 * i), + f->firmware[i]); + return; + } + } + } +} + +static void load_firmware_set(struct ls220_dev *dev, int card, int mode) +{ + int i; + for(i=0;i<3;i++) + load_firmware_block(dev, &firmware[card][mode][i]); +} + +static void ls220_load_firmware(struct ls220_dev *dev, int format) +{ + int card = 0; + if(dev->type==LS240) + card = 1; + + if(dev->eprom[EPROM_I2S]==0x03) + format += 3; /* Second table for i2s */ + + format--; /* Numbered 1 to 3 */ + + load_firmware_set(dev, card, format); +} + +/* + * LS220 I2C bus implementation + */ + +static void ls220_i2c_init(struct ls220_dev *dev) +{ + if(!dev->eprom[EPROM_BOARDTYPE]) + ls220_dv_write(dev, 0x350, 0x4f70100); + else + ls220_dv_write(dev, 0x350, 0x4f70f00); + ls220_dv_write(dev, 0x364, 0xff031f); +} + +static void ls220_bit_setscl(void *data, int state) +{ + struct ls220_dev *dev = data; + u32 reg; + + reg = ls220_dv_read(dev, 0x350); + reg &= 0x7FFFFF; + if(state == 0) + reg |= 0x00800000; + ls220_dv_write(dev, 0x350, reg); +// printk("SCL = %d\n", state); + ls220_dv_read(dev, 0x350); +} + +static void ls220_bit_setsda(void *data, int state) +{ + struct ls220_dev *dev = data; + u32 reg; + + reg = ls220_dv_read(dev, 0x350); + reg &= 0xBFFFFF; + if(state == 0) + reg |= 0x00400000; + ls220_dv_write(dev, 0x350, reg); +// printk("SDA = %d\n", state); + ls220_dv_read(dev, 0x350); +} + +static int ls220_bit_getsda(void *data) +{ + struct ls220_dev *dev = data; + if(ls220_dv_read(dev, 0x350)&0x40) + { +// printk("get SDA=0\n"); + return 0; + } +// printk("get SDA=1\n"); + return 1; +} + +static void ls220_i2c_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} + +static void ls220_i2c_unuse(struct i2c_adapter *adap) +{ + MOD_DEC_USE_COUNT; +} + +static int ls220_attach_inform(struct i2c_client *client) +{ + struct ls220_dev *dev = client->adapter->data; + return 0; +} + +static int ls220_detach_inform(struct i2c_client *client) +{ + struct ls220_dev *dev = client->adapter->data; + return 0; +} + +static int ls220_call_i2c_clients(struct ls220_dev *dev, unsigned int cmd, void *arg) +{ + return 0; +} + +/* + * Structures to define our hardware with the i2c core code. It + * will do all the i2c bus management and locking for us. + */ + +static struct i2c_algo_bit_data ls220_i2c_algo_template = { + setsda: ls220_bit_setsda, + setscl: ls220_bit_setscl, + getsda: ls220_bit_getsda, + udelay: 30, + mdelay: 10, + timeout: 200, +}; + +static struct i2c_adapter ls220_i2c_adap_template = { + name: "ls220", + id: I2C_HW_B_BT848, /* FIXME */ + inc_use: ls220_i2c_use, + dec_use: ls220_i2c_unuse, + client_register: ls220_attach_inform, + client_unregister: ls220_detach_inform, +}; + +static struct i2c_client ls220_i2c_client_template = { + name: "ls220 internal", + id: -1, +}; + +/* + * Register our i2c bus + */ + +static int ls220_i2c_register(struct ls220_dev *dev) +{ + /* Copy template */ + memcpy(&dev->i2c_adap, &ls220_i2c_adap_template, sizeof(struct i2c_adapter)); + memcpy(&dev->i2c_algo, &ls220_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); + memcpy(&dev->i2c_client, &ls220_i2c_client_template, sizeof(struct i2c_client)); + /* Device backlinks */ + dev->i2c_algo.data = dev; + dev->i2c_adap.data = dev; + /* Fix up links */ + dev->i2c_adap.algo_data = &dev->i2c_algo; + dev->i2c_client.adapter = &dev->i2c_adap; + /* Set up */ + ls220_bit_setscl(dev, 1); + ls220_bit_setsda(dev, 1); + dev->i2c_rc = i2c_bit_add_bus(&dev->i2c_adap); + return dev->i2c_rc; +} + +/* + * I2C read interfaces + */ + +static int ls220_new_i2c_read(struct ls220_dev *dev, u8 addr) +{ + u8 buffer; + + if(dev->i2c_rc == -1) + BUG(); + printk("i2c recv from 0x%02X\n", addr); + + dev->i2c_client.addr = addr>>1; + if(i2c_master_recv(&dev->i2c_client, &buffer, 1)) + { + printk("i2c - read error.\n"); + return -EIO; + } + printk("Received %d\n", buffer); + return buffer; +} + +static int ls220_new_i2c_probe(struct ls220_dev *dev, u8 addr) +{ + u8 buffer; + int err; + + if(dev->i2c_rc == -1) + BUG(); + printk("i2c probe for 0x%02X\n", addr); + + dev->i2c_client.addr = addr>>1; + if((err=i2c_master_send(&dev->i2c_client, &buffer, 0))) + { + printk(" - probe failed (%d).\n", err); + return 0; + } + printk(" - found.\n"); + return 1; +} + +/*=================----------------*/ + +/* + * Old built in i2c code - this is here until I find why the generic + * kernel code won't play + */ + +static void iic_delay(struct ls220_dev *dev) +{ + udelay(30); +} + +static void iic_startcode(struct ls220_dev *dev) +{ + u32 tmp; + + tmp = ls220_dv_read(dev, 0x350) & 0x3fffffL; + ls220_dv_write(dev, 0x350, tmp); // both = 1 + iic_delay(dev); + + ls220_dv_write(dev, 0x350, tmp | 0x400000L); // SDA = 0 + + iic_delay(dev); + + ls220_dv_write(dev, 0x350, tmp | 0xc00000L); // SCL = 0 + iic_delay(dev); +} + +////////////////////////////////////////////////////////////////////////// + +static void iic_dataxfer(struct ls220_dev *dev, u8 val) +{ + u32 tmp; + u8 data; + int i; + + data = ~val; + for (i = 0; i < 8; i++) { + tmp = ls220_dv_read(dev, 0x350) & 0xbfffffL; + tmp |= (u32) ((data >> (7 - i)) & 0x1) << 22; // set SDA + ls220_dv_write(dev, 0x350, tmp); + iic_delay(dev); + tmp = ls220_dv_read(dev, 0x350); + ls220_dv_write(dev, 0x350, tmp & 0x7fffffL); // set SCL = 1 + iic_delay(dev); + ls220_dv_write(dev, 0x350, tmp | 0x800000L); // set SCL = 0 + iic_delay(dev); + } +} + +////////////////////////////////////////////////////////////////////////// + +static int iic_ack(struct ls220_dev *dev) +{ + u32 tmp, ack; + + tmp = ls220_dv_read(dev, 0x350); + ls220_dv_write(dev, 0x350, tmp & 0xbfffffL); // disable SDA = 1 + iic_delay(dev); + ack = ls220_dv_read(dev, 0x350) & 0x40; + ls220_dv_write(dev, 0x350, tmp & 0x3fffffL); // SCL = 1 + iic_delay(dev); + tmp = ls220_dv_read(dev, 0x350); + ls220_dv_write(dev, 0x350, tmp | 0x800000L); // set SCL = 0 + iic_delay(dev); + + if (!ack) + return 1; + else + return 0; +} + +////////////////////////////////////////////////////////////////////////// + +static void iic_endcode(struct ls220_dev *dev) +{ + u32 tmp; + + tmp = ls220_dv_read(dev, 0x350); + ls220_dv_write(dev, 0x350, tmp | 0x400000L); // SDA = 0 + iic_delay(dev); + tmp = ls220_dv_read(dev, 0x350); + ls220_dv_write(dev, 0x350, tmp & 0x7fffffL); // set SCL = 1 + iic_delay(dev); + ls220_dv_write(dev, 0x350, tmp & 0x3fffffL); // SDA = 1 + iic_delay(dev); +} + +////////////////////////////////////////////////////////////////////////// + +static u8 iic_dataget(struct ls220_dev *dev) +{ + u8 val, i; + u32 tmp; + + val = 0; + for (i = 0; i < 8; i++) { + iic_delay(dev); + tmp = ls220_dv_read(dev, 0x350); + val <<= 1; + if (tmp & 0x40) + val = val | 0x1; + + tmp = tmp & 0x3fffffL; + ls220_dv_write(dev, 0x350, tmp); // set SCL = 1 + iic_delay(dev); + ls220_dv_write(dev, 0x350, tmp | 0x800000L); // set SCL = 0 + iic_delay(dev); + } + + return val; +} + +////////////////////////////////////////////////////////////////////////// + +static void send_ack(struct ls220_dev *dev) +{ + u32 tmp; + + tmp = ls220_dv_read(dev, 0x350); + tmp = tmp | 0xc00000L; // SCLK SDA + ls220_dv_write(dev, 0x350, tmp); // set 00 + iic_delay(dev); + tmp = tmp & 0x7fffffL; + ls220_dv_write(dev, 0x350, tmp); // set 10 + iic_delay(dev); + tmp = tmp | 0xc00000L; + ls220_dv_write(dev, 0x350, tmp); // set 00 + iic_delay(dev); + tmp = tmp & 0xb00000L; + ls220_dv_write(dev, 0x350, tmp); // set 01 + iic_delay(dev); +} + +static int i2c_readeprom(struct ls220_dev *dev, u8 addr, u8 subaddr, u8 num, u8 * pb) +{ + u8 val; + int i; + + iic_startcode(dev); + iic_dataxfer(dev, addr); // write command + iic_ack(dev); + iic_dataxfer(dev, subaddr); + iic_ack(dev); + iic_startcode(dev); + iic_dataxfer(dev, (u8) (addr | 0x1)); // read command + iic_ack(dev); + + for (i = 0; i < num; i++) { + pb[i] = iic_dataget(dev); // load array here + if (i < (num - 1)) + send_ack(dev); + else + iic_endcode(dev); + } + return 1; +} + +static int ls220_i2c_probe(struct ls220_dev *dev, u8 addr) +{ + int val; +// return ls220_new_i2c_probe(dev,addr); + iic_startcode(dev); + iic_dataxfer(dev, addr); // write command + val = iic_ack(dev); + iic_endcode(dev); + return val; +} + +////////////////////////////////////////////////////////////////////////// + +static int read_i2c(struct ls220_dev *dev, u8 addr) +{ + u32 tmp, val; + u32 dwcnt = 0; + + val = 0xff; + tmp = ls220_dv_read(dev, 0x350); + ls220_dv_write(dev, 0x350, tmp | 0x4000000); // set bit 26=1 + iic_delay(dev); + ls220_dv_write(dev, 0x354, addr << 24 | 0x1000000L); + iic_delay(dev); + + while (!(ls220_dv_read(dev, 0x368) & 0x1000)) { + iic_delay(dev); + if (dwcnt++ > 0xffff) + break; + } + val = (u8) ls220_dv_read(dev, 0x36c); + ls220_dv_write(dev, 0x350, tmp); + iic_delay(dev); + return val; +} + +static void send_i2c(struct ls220_dev *dev, u8 addr,u8 subaddr,u8 data) +{ + iic_startcode(dev); + iic_dataxfer(dev, addr); + iic_ack(dev); + iic_dataxfer(dev, subaddr); + iic_ack(dev); + iic_dataxfer(dev, data); + iic_ack(dev); + iic_endcode(dev); +} + +/*=================----------------*/ + +static int ls220_i2c_read(struct ls220_dev *dev, u8 addr) +{ +// return ls220_new_i2c_read(dev, addr); + return read_i2c(dev, addr); +} + + +static int ls220_i2c_write(struct ls220_dev *dev, u8 addr, u8 b1, u8 b2, int both) +{ + u8 buffer[2]; + int bytes = both ? 2 : 1; + if(dev->i2c_rc == -1) + BUG(); + +// printk("Write to i2c client 0x%02X - 0x%2X (0x%02X, %d)\n", addr, b1, b2, both); + dev->i2c_client.addr = addr >> 1; + buffer[0] = b1; + buffer[1] = b2; + if(i2c_master_send(&dev->i2c_client, buffer, bytes)!=bytes) + { + printk(KERN_ERR "i2c write failed.\n"); + return -EIO; + } + return 0; +} + +static int ls220_load_eeprom(struct ls220_dev *dev, u8 addr, u8 subaddr, u8 len, u8 *buf) +{ + int i; + + i2c_readeprom(dev, addr, subaddr, len, buf); +#if 0 + if(ls220_i2c_write(dev, addr, subaddr, -1, 0)<0) + return -EIO; + dev->i2c_client.addr = addr >> 1; + + if(i2c_master_recv(&dev->i2c_client, buf, 16)!=16) + return -EIO; +#endif +#if 0 + printk("luxsonor: EEPROM "); + for(i=0;i<16;i++) + printk("%02X ", buf[i]); + printk("\n"); +#endif + return 0; +} + +static int ls220_detect_tvencoder(struct ls220_dev *dev) +{ + int type; + u8 id; + + if(ls220_i2c_write(dev, 0x00, 0x0f, 0x40, 1)) + printk("i2c_write failed.\n"); + if(ls220_i2c_probe(dev, 0x80)) + { + u8 id; + ls220_load_eeprom(dev, 0x80, 0x3d, 1, &id); + if(id & 0xf0) + type = CS4953; + else + type = CS4952; + return type; + } + if(ls220_i2c_probe(dev, 0x8A)) + { + id = ls220_i2c_read(dev, 0x8A); + if(((id>>5)&7) == 5) + type = BT865; + else + type = BT864; + return type; + } + if(ls220_i2c_probe(dev, 0x42)) + { + ls220_load_eeprom(dev, 0x42, 0x00, 1, &id); + if(id & 0x0f) + type = HS8171; + else + type = HS8170; + return type; + } + if(ls220_i2c_probe(dev, 0x8c)) + return SAA7120; + if(ls220_i2c_probe(dev, 0xd4)) + return AD7175; + if(ls220_i2c_probe(dev, 0x54)) + return AD7176; + printk("No TV encoder ??\n"); + return -ENODEV; +} + +/* + * The LS220 also has some other i2c like stuff on the same + * registers, so we have to watch our locking. + * + * FIXME:pci posting.. + */ + +#define G_EN 0x60000 +#define G_SC 0x0200 +#define G_SD 0x0400 + +static void ls220_gpio_startcode(struct ls220_dev *dev) +{ + u32 r350 = ls220_dv_read(dev, 0x350); + r350&=0xFF000000; + r350|=G_EN; + ls220_dv_write(dev, 0x350, r350|G_SC|G_SD); + udelay(100); + ls220_dv_write(dev, 0x350, r350|G_SC); + udelay(100); + ls220_dv_write(dev, 0x350, r350); + udelay(100); +} + +static void ls220_gpio_endcode(struct ls220_dev *dev) +{ + u32 r350 = ls220_dv_read(dev, 0x350); + r350&=0xFF000000; + r350|=G_EN; + ls220_dv_write(dev, 0x350, r350); + udelay(10); + ls220_dv_write(dev, 0x350, r350|G_SC); + udelay(10); + ls220_dv_write(dev, 0x350, r350); + udelay(10); + ls220_dv_write(dev, 0x350, r350|G_SC); + udelay(10); + ls220_dv_write(dev, 0x350, r350|G_SC|G_SD); +} + +static void ls220_gpio_addr(struct ls220_dev *dev, u8 addr) +{ + int i; + int sd; + u32 r350 = ls220_dv_read(dev, 0x350); + r350&=0xFF000000; + r350|=G_EN; + + for(i=2;i>=0;i--) + { + if(addr&(1<=0;i--) + { + if(data&(1<type == LS240) + { + ls220_dv_write(dev, 0x10, 1); + ls220_dv_write(dev, 0x10, 0x30); + ls220_dv_write(dev, 0x300, 0); + ls220_dv_write(dev, 0x84, 0x04400000); + udelay(10); + ls220_dv_write(dev, 0x80, 0x66a428ec); + udelay(10); + ls220_dv_write(dev, 0x84, 0x80400000); + ls220_dv_write(dev, 0x30, 0x12c5); + } + else + { + ls220_dv_write(dev, 0x10, 1); + ls220_dv_write(dev, 0x10, 0); + } + + ls220_i2c_init(dev); +} + +/* + * LS220 Audio drivers + */ + +static void ls240_dsp_poke(struct ls220_dev *dev) +{ + if(dev->type == LS240) + { + u32 reg = ls220_dv_read(dev, 0x10); + reg &= ~8; + reg |= 0x30; + ls220_dv_write(dev, 0x10,reg); + } +} + +static int ls220_dsp_wait(struct ls220_dev *dev) +{ + int count; + + ls240_dsp_poke(dev); + + ls220_dv_read(dev, 0x250); + + for(count = 0; count < 4096; count ++) + { + if(ls220_read_dram(dev, DSPMEM_CMD(dev)) == 0x100) + return 0; + ls240_dsp_poke(dev); + udelay(50); + } + printk(KERN_ERR "ls220: dsp not responding.\n"); + return -ETIMEDOUT; +} + +static u32 vol_table[16] = { + 0x7fffff, 0x6046c5, 0x4c79a0, 0x3cbf0f, + 0x3040a5, 0x26540e, 0x1e71fe, 0x182efd, + 0x1335ad, 0xf4240, 0xc1ed8, 0x9a0ad, + 0x7a5c3, 0x6131b, 0x4d343, 0x0 +}; + +static void ls220_audio_set_volume(struct ls220_dev *dev, int vol) +{ + if(dev->audio_mute) + return; + if(vol == 0xFF) + { + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_MUTE); + ls220_dsp_wait(dev); + vol = 0; + } + else + dev->audio_m_vol = vol; + if(vol > 15 || vol < 0) + BUG(); + ls220_write_dram(dev, DSPMEM_VOLUME_LEVEL(dev), vol_table[15-vol]); + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_VOLUME); +} + +static void ls220_dsp_init(struct ls220_dev *dev, int type) +{ + ls220_write_dram(dev, DSPMEM_AC3_CONF(dev) ,0x3400); + + if(type == 1) /* AC3 */ + { + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_AC3); + dev->audio_m_adj = 0x600; + } + else if(type == 0) /* PCM */ + { + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_PCM); + dev->audio_m_adj = 0x600; + } + else if(type == 2) /* MPG1 */ + { + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_MPEG1); + dev->audio_m_adj = 0x0; + } + ls220_dsp_wait(dev); + ls220_audio_set_volume(dev, dev->audio_m_vol); + + dev->audio_fifo_off = ls220_read_dram(dev, DSPMEM_FIFO_START(dev)); + dev->audio_fifo_len = ls220_read_dram(dev, DSPMEM_FIFO_END(dev)) - dev->audio_fifo_off; +// printk("FIFO at 0x%X, size %d.\n", dev->audio_fifo_off, dev->audio_fifo_len); +} + +static void ls220_audio_init(struct ls220_dev *dev, int type) +{ + dev->audio_mute = 0; + dev->audio_m_vol = 15; + dev->audio_ac3 = 1; + dev->audio_m_total = 0; + dev->audio_pts = 0; + dev->audio_ptscount = 0; + dev->audio_speed = 1000; + dev->stop_read = 0; + ls220_dv_write(dev, 0x24, 0); + + if(old) + { + ls220_dv_write(dev, 0x104, 0); + ls220_dv_write(dev, 0x100, 0x7C600); + ls220_dv_write(dev, 0x104, 1); + udelay(200); + ls220_write_dram(dev, DSPMEM_FIFO_WR(dev), AUD_FIFO_OFF); + ls220_write_dram(dev, DSPMEM_FIFO_RD(dev), AUD_FIFO_OFF); + ls220_write_dram(dev, DSPMEM_PTS_WR(dev), AUD_PTS_OFF); + ls220_write_dram(dev, DSPMEM_PTS_RD(dev), AUD_PTS_OFF); + } + ls220_dsp_init(dev, type); + dev->audio_m_total = 0; + dev->audio_pts = 0; + dev->audio_ptscount = 0; + + if(type == 2) /* Mpeg audio */ + dev->audio_ptscount = 1; +} + +static void ls240_audiopcm_enable_tristate(struct ls220_dev *dev) +{ + ls220_dv_write(dev, 0x284, ls220_dv_read(dev, 0x284)|0x200000); +} + +static void ls220_audio_set_info(struct ls220_dev *dev) +{ + u16 clock_chip; /* clock chip defition */ + u16 left_ch; /* left channel polarity */ + u16 pcm_size; /* PCM ( output ) size */ + u16 i2s_pin; /* I2S pin */ + + clock_chip = (u16)dev->eprom[EPROM_CLOCKTYPE]; + left_ch = (u16)dev->eprom[EPROM_LEFT_CH_POL]<<3; + pcm_size = 0; + + if(dev->eprom[EPROM_I2S] == 0x3) + i2s_pin = 0x40; + else + i2s_pin = 0; + + ls220_write_dram(dev, DSPMEM_AUDIO_CONF(dev), i2s_pin|pcm_size|left_ch|clock_chip); +} + +static void ls220_audio_set_spdif(struct ls220_dev *dev, int onoff) +{ + u32 data; + + dev->audio_spdif = onoff; + + data = ls220_read_dram(dev, DSPMEM_AUDIO_CONF(dev)); + data &= 0x7F; + if(onoff) + data |= 0x80; + ls220_write_dram(dev, DSPMEM_AUDIO_CONF(dev), data); +} + +static int ls220_audio_write(struct ls220_dev *dev, const char *buf, int len) +{ + return 0; +} + +static void ls220_play_audio(struct ls220_dev *dev, int speed) +{ + dev->audio_speed = speed; + if(speed == 1000) + { + /* + * Normal speed - engage hardware synchronization + */ + if(dev->type == LS240) + { + ls220_dv_write(dev, 0x280, 0x8); + ls220_dv_write(dev, 0x280, 0x9); + ls220_dv_write(dev, 0x29C, 0x30008235); + ls220_dv_write(dev, 0x200, 0x419); + ls220_dv_write(dev, 0x200, 0x3b); + } + else + { + u32 tmp = ls220_dv_read(dev, SYNC_AUD_CONTROL); + ls220_dv_write(dev, SYNC_AUD_CONTROL, tmp|0x20); + } + ls220_dv_write(dev, DSPMEM_CMD(dev), DSP_CMD_PLAY); + ls220_dsp_wait(dev); + /* Locking needed on 0x350 */ + if(dev->eprom[EPROM_BOARDTYPE] == 3 && !dev->audio_spdif) + ls220_dv_write(dev, 0x350, ls220_dv_read(dev, 0x350)|0x010100); + if(!(dev->eprom[EPROM_SPDIF_CH]&0x02) && dev->audio_spdif && dev->spdif_first_play) + { + dev->spdif_first_play = 0; + ls220_dv_write(dev, DSPMEM_CMD(dev), DSP_CMD_INITDONE); + ls220_dsp_wait(dev); + } + } +} + +static void ls220_audio_set_speed(struct ls220_dev *dev, int speed) +{ + dev->audio_speed = speed; +} + +static void ls220_audio_set_config(struct ls220_dev *dev, int sixchannel) +{ + if(dev->audio_ac3) + { + if(sixchannel && !(dev->eprom[EPROM_SPDIF_CH]&0x1)) + ls220_write_dram(dev, DSPMEM_AC3_CONF(dev), 0x340F); + else + { + switch(sixchannel) + { + case 0: /* Want prologic */ + case 1: /* Board doesnt do 6 */ + case 3: /* Default to prologic */ + ls220_write_dram(dev, DSPMEM_AC3_CONF(dev), 0x3400); + break; + case 2: /* No six channels but use 2 channel scheme */ + ls220_write_dram(dev, DSPMEM_AC3_CONF(dev), 0x3402); + break; + } + } + } + else + { + /* PCM mode */ + if(sixchannel > 1) + ls220_write_dram(dev, DSPMEM_AC3_CONF(dev), sixchannel); + } +} + +static void ls220_audio_set_type(struct ls220_dev *dev, int type) +{ + dev->audio_ac3 = type; +} + + +static void ls220_audio_stop(struct ls220_dev *dev) +{ + dev->stop_read = 0; + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_MUTE); + ls220_dsp_wait(dev); + ls220_write_dram(dev, DSPMEM_PTS_WR(dev), AUD_PTS_OFF); + ls220_write_dram(dev, DSPMEM_PTS_RD(dev), AUD_PTS_OFF); + + if(dev->audio_ac3 == 1) + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_AC3); + else if(dev->audio_ac3 == 0) + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_PCM); + else if(dev->audio_ac3 == 2) + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_MPEG1); + ls220_dsp_wait(dev); + ls220_audio_set_volume(dev, dev->audio_m_vol); + + dev->audio_m_total = 0; + dev->audio_pts = 0; + dev->audio_ptscount = 0; + if(dev->audio_ac3 == 2) + dev->audio_ptscount = 1; +} + +static void ls220_audio_mute(struct ls220_dev *dev) +{ + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_STOPF); + ls220_dsp_wait(dev); +} + +static void ls220_audio_pause(struct ls220_dev *dev) +{ + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_PAUSE); + ls220_dsp_wait(dev); +} + +static void ls220_audio_continue(struct ls220_dev *dev) +{ + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_PLAY); + ls220_dsp_wait(dev); +} + +static u32 ls220_audio_report_frame(struct ls220_dev *dev) +{ + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_FRAME); + ls220_dsp_wait(dev); + return ls220_read_dram(dev, DSPMEM_STATUS(dev)); +} + +static u32 ls220_audio_report_status(struct ls220_dev *dev) +{ + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_STATUS); + ls220_dsp_wait(dev); + return ls220_read_dram(dev, DSPMEM_STATUS(dev)); +} + +static void ls220_audio_onoff(struct ls220_dev *dev, int onoff) +{ + dev->audio_mute = onoff; + if(!dev->audio_mute) + ls220_audio_set_volume(dev, dev->audio_m_vol); + else + { + ls220_write_dram(dev, DSPMEM_VOLUME_LEVEL(dev), vol_table[15]); + ls220_write_dram(dev, DSPMEM_CMD(dev), DSP_CMD_VOLUME); + ls220_dsp_wait(dev); + } +} + +static void ls220_audio_after_seek(struct ls220_dev *dev) +{ + if(old) + { + ls220_write_dram(dev, DSPMEM_FIFO_WR(dev), AUD_FIFO_OFF); + ls220_write_dram(dev, DSPMEM_FIFO_RD(dev), AUD_FIFO_OFF); + } + ls220_write_dram(dev, DSPMEM_FIFO_WR(dev), dev->audio_fifo_off); + ls220_write_dram(dev, DSPMEM_FIFO_RD(dev), dev->audio_fifo_off); + ls220_write_dram(dev, DSPMEM_PTS_WR(dev), AUD_PTS_OFF); + ls220_write_dram(dev, DSPMEM_PTS_RD(dev), AUD_PTS_OFF); +} + +int ls220_audio_write_pts(struct ls220_dev *dev, u32 pts, u16 aoff) +{ + u32 rdptr; + u32 wrptr; + u32 space; + u32 val; + + rdptr = ls220_dv_read(dev, DSPMEM_PTS_RD(dev)); + wrptr = ls220_dv_read(dev, DSPMEM_PTS_WR(dev)); + space = (wrptr > rdptr) ? (AUD_PTS_LEN + rdptr - wrptr) : (rdptr - wrptr); + + if(space < 0x8) + return 0; + + if(dev->type != LS240) + { + if(!dev->audio_pts) + { + val = ls220_dv_read(dev, 0x200); + ls220_dv_write(dev, 0x200, val&0xFBF); /* Audio master */ + } + } + ls220_write_dram(dev, DRAM_BASE(dev)+wrptr, pts); + wrptr+=4; + ls220_write_dram(dev, DRAM_BASE(dev)+wrptr, dev->audio_m_total+aoff); + wrptr+=4; + if(wrptr >= AUD_PTS_OFF+AUD_PTS_LEN) + wrptr -= AUD_PTS_LEN; + ls220_dv_write(dev, DSPMEM_PTS_WR(dev), wrptr); + dev->audio_pts = pts; + return 1; +} + +static void ls220_audio_stop_dsp(struct ls220_dev *dev) +{ + ls220_dv_write(dev, 0x104, 0); + ls220_dv_write(dev, SYNC_INT_CTRL, 0x8000); +} + +static void ls220_audio_enable_dsp(struct ls220_dev *dev) +{ + ls220_dv_write(dev, 0x100, 0x7c600); + ls220_dv_write(dev, 0x104, 0x1); + udelay(100); + if(dev->type == LS240) + ls220_dv_write(dev, SYNC_INT_CTRL, 0x38000001); + else + ls220_dv_write(dev, SYNC_INT_CTRL, 0xE8001); +} + +static void ls220_audio_setuclock(struct ls220_dev *dev, int type) +{ + if(!old) + return; +#if 0 + if(type && dev->eprom[EPROM_CLOCKTYPE]==1) + ls220_write_dram(dev, DSPMEM_UCLOCK(dev), 1); + else + ls220_write_dram(dev, DSPMEM_UCLOCK(dev), 0); +#endif +} + +static void ls220_audio_set_karaoke(struct ls220_dev *dev, int mode) +{ + if(mode < 0 || mode > 3) + BUG(); + /* bit 0 = vocal 1 enable bit 1 = vocal 2 enable */ + ls220_write_dram(dev, DSPMEM_KARAOKE(dev), mode); +} + +static u32 ls220_audio_send_data(struct ls220_dev *dev, u8 *p, u32 len, u16 pts, int scramble, u16 aoff) +{ + if(dev->audio_speed != 1000) + return len; + /* TODO */ + return 0; +} + +static u32 ls220_audio_mpeg_packet(struct ls220_dev *dev, u8 *mbuf, u8 *pp, u32 used) +{ + /* mbuf is a 2K packet, pp is a pes len ptr */ + u8 aid; + u16 pes_len; + u32 curpts = 0; + u8 scramble; + int m_ext = 0; + u16 ext_pes_len = 0; + int m_exthead = 0; + + memcpy(dev->audio_buffer, mbuf, 2048); + dev->audio_p = dev->audio_buffer + (pp - mbuf); + + aid = dev->audio_p[-1]&7; + + if(dev->stop_read) + { + dev->audio_p+=2; + scramble = dev->audio_p[0]&0x30; + pes_len = dev->audio_p[2]; + dev->audio_p+=3; + if((dev->audio_p[0] & 0xf0)==0x20 && pes_len > 0) /* Found PTS */ + { + curpts = dev->audio_p[1]<<8 | dev->audio_p[2]; + curpts = (curpts << 14) | ((dev->audio_p[3]<<8 | dev->audio_p[4])>>2); + curpts |= (dev->audio_p[0] & 0xE) << 28; + } + dev->audio_p += pes_len; + goto tryit; + } + if((dev->audio_p[-1]&0xF0) == 0xD0) + { + m_exthead = 1; + m_ext = 1; + } + dev->audio_dlen = dev->audio_p[0]<<8 | dev->audio_p[1]; + dev->audio_p+=2; + dev->audio_cp = dev->audio_p+dev->audio_dlen; /* Find A_PKT end */ + if (dev->audio_cp < dev->audio_buffer + 0x0800) + { + if((((dev->audio_cp[0]<<8) | dev->audio_cp[1])&0xFFFFFFF0) != 0x01c0) + m_ext = 1; + } + scramble = dev->audio_p[0]&0x30; + pes_len = dev->audio_p[2]; + dev->audio_p+=3; + + dev->audio_dlen = dev->audio_dlen -3 - pes_len; + + if(((*dev->audio_p & 0xf0) == 0x20) && (pes_len > 0)) + { + curpts = dev->audio_p[1]<<8|dev->audio_p[2]; + curpts <<= 14; + curpts |= (dev->audio_p[3]<< 8 | dev->audio_p[4])>>2; + curpts |= (dev->audio_p[0]&0x0E)<<28; + } + + dev->audio_p+=pes_len; + + if(m_exthead) + { + dev->audio_cp = dev->audio_p; + dev->audio_dlen = 0; + curpts = 0; + } + + if(m_ext) + { + dev->audio_p = dev->audio_cp; + while(dev->audio_p < dev->audio_buffer + 0x800) + { + while(((dev->audio_p[0]<<8 | dev->audio_p[1]) & 0xFFFF00) != 0x100) + { + if(dev->audio_p++ >= dev->audio_buffer + 0x800) + goto tryit; + } + + if((dev->audio_p[3]&0xF0) != 0xC0) + { + dev->audio_p += 4; + ext_pes_len = dev->audio_p[0]<<8 | dev->audio_p[1]; + dev->audio_p += ext_pes_len; + continue; + } + if((((dev->audio_p[0]<<24)|(dev->audio_p[1]<<1)|(dev->audio_p[2]<<8)|dev->audio_p[3]) & 0xFFFFFFF0) != 0x1c0) + { + dev->audio_p+=4; + ext_pes_len = dev->audio_p[0] << 8 | dev->audio_p[1]; + dev->audio_p+=2; + pes_len = dev->audio_p[2]; + dev->audio_p+=3; + ext_pes_len = ext_pes_len - 3 - pes_len; + + if(m_exthead) + { + if((dev->audio_p[0]&0xF0) == 0x20 && pes_len > 0) + { + curpts = dev->audio_p[1]<<8|dev->audio_p[2]; + curpts <<= 14; + curpts |= dev->audio_p[3]<<8|dev->audio_p[4]; + curpts |= (dev->audio_p[0]&0xE)<<28; + } + m_exthead = 0; + } + + dev->audio_p += pes_len; + + memmove(dev->audio_cp, dev->audio_p, ext_pes_len); + dev->audio_dlen += ext_pes_len; + dev->audio_cp += ext_pes_len; + dev->audio_p += ext_pes_len; + } + } + } +tryit: + if(dev->audio_dlen == 0) + { + dev->stop_read = 0; + return used; + } + if(ls220_audio_send_data(dev, dev->audio_p, dev->audio_dlen, curpts, scramble, 0)) + { + dev->stop_read = 0; + return used; + } + else + { + dev->stop_read = 1; + return 0; + } +} + +/* + * Video side drivers + */ + +static void ls240_zoomvideo_enable_tristate(struct ls220_dev *dev) +{ + ls220_dv_write(dev, 0x37c, ls220_dv_read(dev, 0x37c)&0xe0ffffff); +} + +static void ls220_video_set_vpm(struct ls220_dev *dev, int type) +{ + /* TODO */ +} + +static void ls220_configure_tvout(struct ls220_dev *dev, int tvmode) +{ + static u8 bt865_pal[]={ + 0x00, 0x60, 0x7e, 0xfe, 0x54, 0x01, 0xff, 0x01, + 0xd5, 0x73, 0xa8, 0x22, 0x55, 0xa4, 0x05, 0x55, + 0x27, 0x40 + }; + int i; + + switch(dev->tvencoder) + { + case BT865: + for(i=0;i<18;i++) + send_i2c(dev, 0x8A, 0xD8+2*i, bt865_pal[i]); + break; + default: + printk("Sorry only PAL BT865 is supported right now.\n"); + } +} + +/* + * Video gamma table from Luxsonor + */ + +static u32 gamma[][8] = { + {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}, + {0x0,0x0,0x1000000,0x05040302,0x07070606,0x0b0a0908,0x0b0c0b0b,0xe0e0d}, + {0x0,0x03020200,0x07060505,0x0a090808,0x0b0b0b0a,0x0d0d0c0c,0x0e0e0e0d,0x010f0f0f}, + {0x03000000,0x09080706,0x0c0b0b0b,0x0e0e0d0d,0x0f0f0f0f,0x10100f0f,0x1010100f,0x010f1010}, + {0x08050100,0x0e0d0d0b,0x11101010,0x12121112,0x12121212,0x12121212,0x11111111,0x020f1011}, + {0x0d0a0500,0x13121210,0x15151515,0x16161616,0x15151616,0x14141415,0x12131313,0x020f1112}, + {0x120e0900,0x18171615,0x19191919,0x1919191a,0x17181919,0x16161617,0x13141415,0x020f1212}, + {0x16130d00,0x1c1c1b19,0x1d1d1d1e,0x1d1d1d1e,0x1a1b1c1c,0x1818191a,0x14151616,0x020f1213}, + {0x1b171000,0x21201f1e,0x21212122,0x20202021,0x1c1d1e1f,0x191a1a1c,0x15161718,0x020f1314}, + {0x1f1b1400,0x24242322,0x24252525,0x22232324,0x1e1f2121,0x1b1c1c1e,0x16171819,0x020f1315} +}; + +/* + * U chroma values from Luxsonor + */ + +static u32 chroma_U[][7] = { + {0x2,0x0,0x0,0x0,0x0,0x0,0x0}, + {0x3f3f3f02,0x3f3f3f3f,0x0,0x0,0x0,0x01010100,0x02020201}, + {0x3e3d3d02,0x3e3e3e3e,0x3f3f3f3f,0x0,0x01000000,0x03020201,0x04040403}, + {0x3c3c3b02,0x3d3d3d3c,0x3f3e3e3e,0x3f3f,0x02010000,0x04040302,0x07060605}, + {0x3b3a3a02,0x3c3c3c3b,0x3e3e3d3d,0x3f3f,0x02010000,0x06050403,0x09080807}, + {0x39393a02,0x3b3b3a3a,0x3e3d3d3c,0x3f3f3e,0x03020100,0x07060504,0x0c0b0a08}, + {0x38373a02,0x3a3a3938,0x3d3c3c3b,0x3f3e3e,0x04020100,0x09080605,0x0e0d0c0a}, + {0x36363a02,0x39393837,0x3d3c3b3a,0x3f3e3d,0x04030100,0x0a090706,0x100f0e0c}, + {0x35343a02,0x38383736,0x3c3b3a39,0x3f3e3d,0x05030100,0x0c0a0807,0x1011100e}, + {0x33323a02,0x37363534,0x3b3a3938,0x3f3e3d3c,0x06040200,0x0e0c0a08,0x10141210} +}; + +/* + * V chroma values from Luxsonor (remember mpeg is YUV) + */ +static u32 chroma_V[][7] = { + {0x023a0202,0x02020202,0x02020202,0x02020202,0x02020202,0x02020202,0x02020202}, + {0x380002,0x0,0x01010101,0x02020101,0x03030202,0x04040303,0x05050404}, + {0x3f3e3e07,0x3f3f,0x01000000,0x02020101,0x04040302,0x06060505,0x08080707}, + {0x3d3c3c0a,0x3f3e3e3d,0x3f,0x02020101,0x06050403,0x09080706,0x0c0b0a0a}, + {0x3b3a3a0a,0x3e3d3c3c,0x3f3e,0x02020100,0x07060503,0x0b0a0908,0x0f0e0d0c}, + {0x39383a0a,0x3d3c3b3a,0x3f3e3d,0x02020100,0x08070603,0x0e0c0b0a,0x1012100f}, + {0x373e3a0a,0x3b3a3938,0x3f3e3d3c,0x03020100,0x0a080604,0x100e0d0b,0x10151312}, + {0x363c3a0a,0x3a393837,0x3f3e3d3b,0x03020000,0x0b090704,0x12100f0d,0x10181614}, + {0x343a3a0a,0x39383635,0x3e3d3c3a,0x03020000,0x0c0a0804,0x1513100e,0x10181917}, + {0x323a3a0a,0x38363533,0x3e3c3b39,0x0302003f,0x0e0b0905,0x17151210,0x10181c1a} +}; + +static void ls220_video_clear_screen(struct ls220_dev *dev) +{ + ls220_dv_write(dev, 0x3D0, 0); /* Wipe OSD */ + if(dev->video_mode == VIDEO_NTSC || dev->video_mpeg1) + { + ls220_memsetl(dev, 0x200000, 0x0, 0x54600); + ls220_memsetl(dev, 0x254600, 0x80808080, 0x2a300); + ls220_memsetl(dev, 0x27e900, 0x0, 0x54600); + ls220_memsetl(dev, 0x2d2f00, 0x80808080, 0x2a300); + ls220_memsetl(dev, 0x2fd200, 0x0, 0x54600); + ls220_memsetl(dev, 0x351800, 0x80808080, 0x2a300); + } + else + { + ls220_memsetl(dev, 0x200000, 0x0, 0x65400); + ls220_memsetl(dev, 0x265400, 0x80808080, 0x32a00); + ls220_memsetl(dev, 0x297e00, 0x0, 0x65400); + ls220_memsetl(dev, 0x2fd200, 0x80808080, 0x32a00); + ls220_memsetl(dev, 0x32fc00, 0x0, 0x65400); + ls220_memsetl(dev, 0x395000, 0x80808080, 0x32a00); + } +} + +static void ls220_video_init(struct ls220_dev *dev) +{ + dev->video_hw_wrap = 0xF00000; +// ls220_video_set(dev); + ls220_video_clear_screen(dev); +// ls220_video_set_gamma(dev, 1); +} + +static void ls220_video_reset(struct ls220_dev *dev) +{ +// FILL ME IN +} + +static void ls220_video_set_letter(struct ls220_dev *dev, int onoff) +{ +} + +static void ls220_video_set_speed(struct ls220_dev *dev, int speed) +{ +} + +static void ls220_video_release(struct ls220_dev *dev) +{ + ls220_video_clear_screen(dev); + ls220_video_reset(dev); +} + +static void ls220_video_still(struct ls220_dev *dev) +{ + u32 r180; + + ls220_dv_write(dev, 0x200, 0x7b); + r180 = ls220_dv_read(dev, MPGVID_CONTROL) & 0x1E0; + ls220_dv_write(dev, MPGVID_CONTROL, r180|4); /* Start pointer */ + ls220_video_set_vpm(dev, dev->vga_mode); + ls220_video_set_letter(dev, dev->video_letter); + if(dev->type == LS240) + ls220_dv_write(dev, SYNC_INT_CTRL, 0x88004401); + else + ls220_dv_write(dev, SYNC_INT_CTRL, 0x224401); + ls220_dv_write(dev, 0x278, 0x4000); +} + +static void ls220_video_play(struct ls220_dev *dev, int speed) +{ + u32 reg; + + if(dev->type < LS240) /* might be wrong */ + { + if(/* ?? MENU ?> */ !dev->video_mpeg1) + { + if(ls220_dv_read(dev, 0x145fc) == 0x01) + ls220_dv_write(dev, 0x145fc, 0x02); + } + } + + reg = ls220_dv_read(dev, 0x200); + ls220_dv_write(dev, 0x200, reg |0x01); + + reg = ls220_dv_read(dev, MPGVID_CONTROL); + reg &= 0x1E0; + ls220_dv_write(dev, MPGVID_CONTROL, reg|6); + + ls220_video_set_vpm(dev, dev->vga_mode); + + if(!dev->video_zoomin) + { + ls220_video_set_letter(dev, dev->video_letter); + if(dev->type == LS240) + ls220_dv_write(dev, SYNC_INT_CTRL, 0x38000001); + else + ls220_dv_write(dev, SYNC_INT_CTRL, 0x0e8001); + } + else + { + if(dev->type == LS240) + ls220_dv_write(dev, SYNC_INT_CTRL, 0xc8000001); + else + ls220_dv_write(dev, SYNC_INT_CTRL, 0x328001); + } + ls220_video_set_speed(dev, dev->video_speed); +} + +static void ls220_video_stop(struct ls220_dev *dev) +{ + u32 reg; + + reg = ls220_dv_read(dev, SYNC_INT_CTRL); + + if(dev->type == LS240) + ls220_dv_write(dev, SYNC_INT_CTRL, reg&0xFFFFFFFE); + else + ls220_dv_write(dev, SYNC_INT_CTRL, reg&0xFFFFFE); + + reg = ls220_dv_read(dev, 0x200); + ls220_dv_write(dev, 0x200, reg & 0xFFFE); + + reg = ls220_dv_read(dev, MPGVID_CONTROL); + ls220_dv_write(dev, MPGVID_CONTROL, reg & 0x1E0); + + ls220_dv_write(dev, 0x194, VID_FIFO_OFF); + + dev->video_total = 0; + dev->video_remainder = 0; + dev->video_wptr = VID_FIFO_OFF; + dev->video_pts = 0; + + reg = ls220_dv_read(dev, MPGVID_CONTROL); + ls220_dv_write(dev, MPGVID_CONTROL, (reg&0x1E0) | 1); +} + +static void ls220_video_pause(struct ls220_dev *dev) +{ + u32 reg; + + if(dev->video_speed != 1000) + ls220_dv_write(dev, 0x19C, 0x02); + reg = ls220_dv_read(dev, 0x200); + ls220_dv_write(dev, 0x200, reg&0xFFFE); + ls220_dv_write(dev, SYNC_INT_CTRL, 0x28000); +} + +static unsigned long ls220_video_stc(struct ls220_dev *dev) +{ + return ls220_dv_read(dev, 0x218); +} + +static void ls220_video_fastforward(struct ls220_dev *dev) +{ + u32 reg; + + dev->video_speed = 2000; + if(dev->type == LS240) + { + ls220_dv_write(dev, 0x274, 0x28000001); + ls220_dv_write(dev, 0x268, (ls220_dv_read(dev, 0x268) & 0xA0)|1); + } + else + { + ls220_dv_write(dev, 0x274, 0xa8001); + ls220_dv_write(dev, 0x268, (ls220_dv_read(dev, 0x268) & 0x20)|1); + } +} + +/* + * Called when we reset and reload the DSP + */ +static void ls220_change_dsp(struct ls220_dev *dev, int audio, int vga) +{ + ls220_audio_init(dev, audio); + /* FIXME - reset video vars */ + ls220_video_reset(dev); + ls220_video_set_vpm(dev, vga); + ls220_load_firmware(dev, audio); + ls220_audio_set_info(dev); + + if(dev->eprom[EPROM_SPDIF_CH/*CHECK ME*/] && !(dev->eprom[EPROM_SPDIF_CH]&0x2)) + { + /* SPDIF */ + ls220_audio_set_spdif(dev, 1); + } + else + ls220_audio_set_spdif(dev, 0); + ls220_video_reset(dev); + ls220_video_init(dev); + ls220_audio_init(dev, 1); +} + +/* + * IRQ handling + */ + +static void ls220_intr(int irq, void *dev_id, struct pt_regs *unused) +{ + struct ls220_dev *dev = dev_id; + u32 r20, r14; + + r20 = ls220_dv_read(dev, 0x20); + if(r20 == 0) + return; + + r14 = ls220_dv_read(dev, 0x14); + if(!(r14 & 0x0104)) + return; + + ls220_dv_write(dev, 0x20, r20&0xfffffefb); + + if(r14 & 0x4) + { + ; /* User event */ + } + if(r14 & 0x100) + { + ; /* Video line reached */ + } + + /* Check - should we clear both bits or clear the r14 value ?? */ + ls220_dv_write(dev, 0x18, ls220_dv_read(dev, 0x18)|0x0104); + ls220_dv_write(dev, 0x20, r20 | 0x0104); +} + +/* + * Hardware setup + */ + +static int ls220_hw_init(struct ls220_dev *dev) +{ + /* Set up base registers */ + if(dev->type == LS240) + dev->dram_base = LS240_DRAM_BASE; + else + dev->dram_base = LS220_DRAM_BASE; + if(ls220_i2c_register(dev)) + return -ENODEV; + /* Initialise video side */ + if(ls220_i2c_probe(dev, 0xA0)) + ls220_load_eeprom(dev, 0xA0, 0, 16, dev->eprom); + ls220_video_reset(dev); + if((dev->tvencoder = ls220_detect_tvencoder(dev))<0) + { + i2c_bit_del_bus(&dev->i2c_adap); + return -ENODEV; + } + printk(KERN_INFO "luxsonor: Found attached %s TV encoder.\n", + lux_tv_names[dev->tvencoder]); + /* Initialise audio side */ + ls220_audio_init(dev, 1); + /* Now reset and bring up */ + ls220_reset(dev); + /* Set up the VMI */ + ls220_video_set_vpm(dev, 0/* For now.. */); + if(ls220_i2c_probe(dev, 0xA0)) + { + ls220_load_eeprom(dev, 0xA0, 0, 16, dev->eprom); + dev->has_eprom = 1; + if(dev->eprom[EPROM_BOARDTYPE] == 1) + { + ls220_send_gpio(dev, 6, 5); /* chrontel setup */ + ls220_send_gpio(dev, 3, 0xf); + } + } + else + { + dev->has_eprom = 0; + dev->eprom[EPROM_TVOUT] = 0; /* NTSC default */ + } + + ls220_load_firmware(dev, 1); /* Default Microcode */ + + ls220_audio_set_info(dev); + + if(dev->eprom[EPROM_SPDIF_CH/*CHECK ME*/] && !(dev->eprom[EPROM_SPDIF_CH]&0x2)) + { + /* SPDIF */ + ls220_audio_set_spdif(dev, 1); + } + else + ls220_audio_set_spdif(dev, 0); + /* Reset again */ + ls220_video_reset(dev); + ls220_audio_init(dev, 1); + ls220_configure_tvout(dev, 0); + return 0; +} + +static int ls220_init_one(struct pci_dev *pdev, const struct pci_device_id *ident) +{ + struct ls220_dev *dev = kmalloc(sizeof(struct ls220_dev), GFP_KERNEL); + if(dev == NULL) + return -ENOMEM; + memset(dev, 0, sizeof(*dev)); + dev->pdev = pdev; + dev->type = ident->driver_data; + + dev->i2c_rc = -1; + + if(pci_enable_device(pdev)<0) + { + kfree(pdev); + return -ENODEV; + } + + pci_set_drvdata(pdev, dev); + + if(request_irq(pdev->irq, ls220_intr, SA_SHIRQ, "ls220", dev)<0) + { + printk(KERN_ERR "ls220: unable to obtain interrupt.\n"); + pci_set_drvdata(pdev, NULL); + kfree(dev); + return -EBUSY; + } + dev->membase = ioremap(pdev->resource[0].start, pci_resource_len(pdev, 0)); + if(dev->membase == NULL) + { + printk(KERN_ERR "ls220: unable to map device.\n"); + free_irq(pdev->irq, dev); + pci_set_drvdata(pdev, NULL); + kfree(dev); + return -ENOMEM; + } + + pci_set_master(pdev); + + printk(KERN_INFO "luxsonor %s at 0x%lX for %ld bytes, IRQ %d.\n", + lux_names[dev->type], pdev->resource[0].start, + pci_resource_len(pdev, 0), pdev->irq); + + if(ls220_hw_init(dev) < 0) + { + free_irq(pdev->irq, dev); + if(dev->i2c_rc != -1) + i2c_bit_del_bus(&dev->i2c_adap); + pci_set_drvdata(pdev, NULL); + kfree(dev); + return -ENODEV; + } + if(dev->type == LS240) + { + ls240_zoomvideo_enable_tristate(dev); + ls240_audiopcm_enable_tristate(dev); + } + + + dev->next = ls_devs; + ls_devs = dev; + + return 0; +} + +static void __devexit ls220_remove_one(struct pci_dev *pdev) +{ + struct ls220_dev *dev = pci_get_drvdata(pdev); + free_irq(dev->pdev->irq, dev); + if(dev->i2c_rc != -1) + i2c_bit_del_bus(&dev->i2c_adap); + iounmap(dev->membase); + pci_disable_device(dev->pdev); +} + +/* + * This code and tables ensures we are notified if there is a + * luxsonor card, either at boot or in the event of a PCI hotplug + */ + +static struct pci_device_id luxsonor_table[] __devinitdata = { + { 0x1287, 0x001F, PCI_ANY_ID, PCI_ANY_ID, LS220C }, /* 220C */ + { 0x1287, 0x001E, PCI_ANY_ID, PCI_ANY_ID, LS220D }, /* 220D */ + { 0x1287, 0x0020, PCI_ANY_ID, PCI_ANY_ID, LS240 }, /* 240 */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, luxsonor_table); + +static struct pci_driver luxsonor_driver = +{ + name: "ls220", + id_table: luxsonor_table, + probe: ls220_init_one, + remove: __devexit_p(ls220_remove_one), + /* No power management yet */ +}; + +static int __init luxsonor_init_module(void) +{ + return pci_module_init(&luxsonor_driver); +} + +static void __exit luxsonor_cleanup_module(void) +{ + pci_unregister_driver(&luxsonor_driver); +} + +module_init(luxsonor_init_module); +module_exit(luxsonor_cleanup_module); + +MODULE_AUTHOR("Alan Cox "); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/Makefile linux.20pre2-ac1/drivers/media/video/Makefile --- linux.20pre2/drivers/media/video/Makefile 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/Makefile 2002-08-06 15:42:12.000000000 +0100 @@ -1,5 +1,5 @@ # -# Makefile for the kernel character device drivers. +# Makefile for the video capture/playback device drivers. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here @@ -16,10 +16,6 @@ obj-n := obj- := -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) - O_TARGET := video.o # All of the (potential) objects that export symbols. @@ -31,8 +27,16 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o +mod-subdirs := margi + obj-$(CONFIG_VIDEO_DEV) += videodev.o +ifeq ($(CONFIG_VIDEO_MARGI),y) + obj-y += margi/margi_cs.o +endif + +subdir-$(CONFIG_VIDEO_MARGI) += margi + obj-$(CONFIG_BUS_I2C) += i2c-old.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ tda7432.o tda9875.o tuner.o @@ -58,6 +62,7 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o +obj-$(CONFIG_VIDEO_LS220) += luxsonor.o # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. @@ -78,8 +83,6 @@ include $(TOPDIR)/Rules.make -fastdep: - zoran.o: zr36120.o zr36120_i2c.o zr36120_mem.o $(LD) $(LD_RFLAG) -r -o $@ zr36120.o zr36120_i2c.o zr36120_mem.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/audio.c linux.20pre2-ac1/drivers/media/video/margi/audio.c --- linux.20pre2/drivers/media/video/margi/audio.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/audio.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,248 @@ +/* + audio.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +// +// Audio Decoder +// +#define __NO_VERSION__ + +#include "audio.h" +#include "l64021.h" + +// mode=0 pause +// mode=1 normal speed play +// mode=2 fast play, 16/15 +// mode=3 slow play, 16/17 + +void AudioSetPlayMode(struct cvdv_cards *card, int mode) +{ + DecoderMaskByte(card, 0x163, 0x60, (mode & 0x03) << 5); + // audio decoder play mode + DecoderMaskByte(card, 0x164, 0x60, (((mode) ? 1 : 0) & 0x03) << 5); + // S/PDIF formatter play mode +} + +void AudioStartDecode(struct cvdv_cards *card) +{ + DecoderSetByte(card, 0x163, 0x80); +} + +// Stop Decode flushes the Audio ES channel buffer +void AudioStopDecode(struct cvdv_cards *card) +{ + DecoderDelByte(card, 0x163, 0x80); +} + +void AudioStartFormat(struct cvdv_cards *card) +{ + DecoderSetByte(card, 0x164, 0x80); +} + +void AudioStopFormat(struct cvdv_cards *card) +{ + DecoderDelByte(card, 0x164, 0x80); +} + +// Audio source: S/PDIF out: +// mode 0: MPEG IEC958 +// mode 1: AC3 IEC958 +// mode 2: MPEG MPEG +// mode 3: AC3 AC3 +// mode 4: PCM IEC958 (max. 48kHz) +// mode 5: PCM 96->48kHz IEC958 (48kHz) +// mode 6: CD Bypass S/PDIF Bypass +// mode 7: PCM FIFO PCM FIFO +void AudioSetMode(struct cvdv_cards *card, int mode) +{ + mode &= 0x07; + AudioSetPlayMode(card, MAUDIO_PAUSE); + AudioStopFormat(card); + DecoderMaskByte(card, 0x165, 0xE0, mode << 5); + if ((mode == 2) || (mode == 3)) + AudioStartFormat(card); +} + + +// volume: 0..255 +void AudioSetVolume(struct cvdv_cards *card, int volume) +{ + DecoderWriteByte(card, 0x16A, volume); // Set PCM scale to volume +} + +// mute=1: mute audio +void AudioMute(struct cvdv_cards *card, int mute) +{ + DecoderMaskByte(card, 0x166, 0x40, (mute ? 0x40 : 0x00)); + // mute PCM + DecoderMaskByte(card, 0x16E, 0x10, (mute ? 0x10 : 0x00)); + // mute S/PDIF +} + +// mode=0: stereo +// mode=1: surround +void AudioAC3Mode(struct cvdv_cards *card, int mode) +{ + DecoderMaskByte(card, 0x166, 0x10, (mode ? 0x10 : 0x00)); +} + +// mode=0: custom analog +// mode=1: custom digital +// mode=2: line-out (default) +// mode=3: RF mode +void AudioAC3Compression(struct cvdv_cards *card, int mode) +{ + DecoderMaskByte(card, 0x166, 0x03, mode & 0x03); +} + +// mode=0: AC3 +// mode=1: ES1 +void AudioAC3Formatter(struct cvdv_cards *card, int mode) +{ + DecoderMaskByte(card, 0x166, 0x03, mode & 0x03); +} + +// mode=0: Stereo +// mode=1: Right channel only +// mode=2: Left channel only +// mode=3: Mono Mix +void AudioDualMono(struct cvdv_cards *card, int mode) +{ + DecoderMaskByte(card, 0x166, 0x0C, (mode & 0x03) << 2); +} + +// swap=0: L->L, R->R +// swap=1: L->R, R->L +void AudioSwap(struct cvdv_cards *card, int swap) +{ + DecoderMaskByte(card, 0x16B, 0x04, (swap ? 0x00 : 0x04)); +} + +// select=0: use clock from ACLK_441 pin -> ACLK=44.1kHz*N +// select=1: use clock from ACLK_48 pin -> ACLK=48.0kHz*N +// select=2: use clock from ACLK_32 pin -> ACLK=32.0kHz*N +// Since the programmable sample rate generator of the PCM1723 is connected to +// all 3 of them, it doen't matter wich one you choose. +// divider=0: ACLK=768*Fs / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/12 / DAC-A_ACLK=ACLK/3 +// divider=1: ACLK=768*Fs / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/12 / DAC-A_ACLK=ACLK/2 +// divider=2: ACLK=512*Fs / S/PDIF-BCLK=ACLK/4 / DAC-BCLK=ACLK/8 / DAC-A_ACLK=ACLK/2 +// divider=3: ACLK=384*Fs / S/PDIF-BCLK=ACLK/3 / DAC-BCLK=ACLK/6 / DAC-A_ACLK=ACLK/1 +// divider=4: ACLK=256*Fs / S/PDIF-BCLK=ACLK/2 / DAC-BCLK=ACLK/4 / DAC-A_ACLK=ACLK/1 +// divider=5: ACLK=768*48kHz / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/6 / DAC-A_ACLK=ACLK/1 +// divider=6: ACLK=512*48kHz / S/PDIF-BCLK=ACLK/4 / DAC-BCLK=ACLK/4 / DAC-A_ACLK=ACLK/1 +// divider=C: ACLK=768*48kHz / S/PDIF-BCLK=ACLK/9 / DAC-BCLK=ACLK/18 / DAC-A_ACLK=ACLK/3 +// divider=D: ACLK=512*48kHz / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/12 / DAC-A_ACLK=ACLK/3 +// divider=E: ACLK=512*48kHz / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/12 / DAC-A_ACLK=ACLK/2 +// divider=F: ACLK=256*48kHz / S/PDIF-BCLK=ACLK/3 / DAC-BCLK=ACLK/6 / DAC-A_ACLK=ACLK/1 +// Fs is the audio sample frequency +// For the normal cases, (32, 44.1, and 48 kHz) select divider 0 through 4 and set +// sample frequency in PCM1723 accordingly +// For 96 kHz, select divider 5 or 6, and set PCM1723 to 48kHz*768 or *512 resp. +// Divider C through F are for 32 kHz sample frequency with a 48kHz*x ACLK +void AudioSetACLK(struct cvdv_cards *card, int select, int divider) +{ + DecoderMaskByte(card, 0x16B, 0x03, select & 0x03); + DecoderMaskByte(card, 0x16C, 0x0F, divider & 0x0F); +} + +int AudioOpen(struct cvdv_cards *card) +{ + // initialize the audio card + MDEBUG(1, ": -- AudioOpen\n"); + write_indexed_register(card, IIO_OSC_AUD, 0x10); + return 0; +} + +int AudioClose(struct cvdv_cards *card) +{ + MDEBUG(1, ": -- AudioClose\n"); + card->AudioInitialized = 0; + return 0; +} + +// audiorate: 16, 32, 64, 22(.05), 44(.1), 88(.2), 24, 48, 96 kHz +// surround=0: Stereo +// surround=1: Surround +int AudioInit(struct cvdv_cards *card, int audiorate, int surround) +{ + //if ((audiorate!=44) && (audiorate!=32)) audiorate=48; + MDEBUG(1, ": -- AudioInit %d\n", audiorate); + + DACSetFrequency(card, audiorate, 256); // put Fs*256 on ACLK inputs + + if (audiorate == 96) + AudioSetACLK(card, 1, 0x06); // 512*48kHz at ACLK + else + AudioSetACLK(card, 1, 0x04); // 256 times Fs at ACLK + + DecoderDelByte(card, 0x166, 80); // no mute on error + DecoderWriteByte(card, 0x168, 0xFF); // dynscalehigh + DecoderWriteByte(card, 0x169, 0xFF); // dynscalelow + DecoderWriteByte(card, 0x16A, 0xFF); // PCM scale + + // IEC958 Setup + DecoderDelByte(card, 0x16D, 0x20); // Overwrite Emphasis off + DecoderSetByte(card, 0x16D, 0x40); // Copyright Override + DecoderDelByte(card, 0x16D, 0x80); // Copyright Bit off + DecoderDelByte(card, 0x16E, 0x01); // Overwrite Category off + DecoderDelByte(card, 0x16E, 0x08); // Overwrite Quatization off + DecoderSetByte(card, 0x170, 0x08); // Musicam Stream Debug + + AudioAC3Mode(card, (surround ? 1 : 0)); + AudioAC3Compression(card, 2); + AudioAC3Formatter(card, 0); + + AudioDualMono(card, 0); + AudioSwap(card, 0); + + AudioMute(card, 0); +// AudioSetPlayMode(card,MAUDIO_PLAY); + + card->AudioInitialized = 1; + return 0; +} + + +// returns size of the Video ES Buffer in bytes or 0=error +u32 DecoderGetAudioESSize(struct cvdv_cards * card) +{ + if (!card->ChannelBuffersAllocated) + return 0; // buffer not initialised + return (u32) ((DecoderReadWord(card, 0x04E) & 0x3FFF) - + (DecoderReadWord(card, 0x04C) & 0x3FFF)) * 256; // bytes +} + +// returns level of fullness in bytes +u32 DecoderGetAudioESLevel(struct cvdv_cards * card) +{ + u32 items; + items = DecoderReadByte(card, 0x089); + items |= ((DecoderReadWord(card, 0x08A) & 0x07FF) << 8); + items *= 8; // 64 bit per item + return items; +} + +int DecoderKaraoke(struct cvdv_cards *card, int vocal1, int vocal2, + int melody) +{ + DecoderMaskByte(card, 0x18C, 0x40, ((vocal1) ? 0x40 : 0x00)); + DecoderMaskByte(card, 0x18C, 0x80, ((vocal2) ? 0x80 : 0x00)); + DecoderMaskByte(card, 0x18C, 0x20, ((melody) ? 0x20 : 0x00)); + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/audio.h linux.20pre2-ac1/drivers/media/video/margi/audio.h --- linux.20pre2/drivers/media/video/margi/audio.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/audio.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,136 @@ +/* + audio.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef CVDV_AUDIO_H +#define CVDV_AUDIO_H + + // + // Audio Decoder +// +#define __NO_VERSION__ + +#include "cardbase.h" + +#define MAUDIO_PAUSE 0 +#define MAUDIO_PLAY 1 +#define MAUDIO_FAST 2 +#define MAUDIO_SLOW 3 + +// mode=0 pause +// mode=1 normal speed play +// mode=2 fast play, 16/15 +// mode=3 slow play, 16/17 +void AudioSetPlayMode(struct cvdv_cards *card, int mode); + +void AudioStartDecode(struct cvdv_cards *card); + +// Stop Decode flushes the Audio ES channel buffer +void AudioStopDecode(struct cvdv_cards *card); + +void AudioStartFormat(struct cvdv_cards *card); + +void AudioStopFormat(struct cvdv_cards *card); + +// Audio source: S/PDIF out: +// mode 0: MPEG IEC958 +// mode 1: AC3 IEC958 +// mode 2: MPEG MPEG +// mode 3: AC3 AC3 +// mode 4: PCM IEC958 (max. 48kHz) +// mode 5: PCM 96->48kHz IEC958 (48kHz) +// mode 6: CD Bypass S/PDIF Bypass +// mode 7: PCM FIFO PCM FIFO +void AudioSetMode(struct cvdv_cards *card, int mode); + + +// volume: 0..255 +void AudioSetVolume(struct cvdv_cards *card, int volume); + +// mute=1: mute audio +void AudioMute(struct cvdv_cards *card, int mute); + +// mode=0: stereo +// mode=1: surround +void AudioAC3Mode(struct cvdv_cards *card, int mode); + +// mode=0: custom analog +// mode=1: custom digital +// mode=2: line-out (default) +// mode=3: RF mode +void AudioAC3Compression(struct cvdv_cards *card, int mode); + +// mode=0: AC3 +// mode=1: ES1 +void AudioAC3Formatter(struct cvdv_cards *card, int mode); + +// mode=0: Stereo +// mode=1: Right channel only +// mode=2: Left channel only +// mode=3: Mono Mix +void AudioDualMono(struct cvdv_cards *card, int mode); + +// swap=0: L->L, R->R +// swap=1: L->R, R->L +void AudioSwap(struct cvdv_cards *card, int swap); + +// select=0: use clock from ACLK_441 pin -> ACLK=44.1kHz*N +// select=1: use clock from ACLK_48 pin -> ACLK=48.0kHz*N +// select=2: use clock from ACLK_32 pin -> ACLK=32.0kHz*N +// Since the programmable sample rate generator of the PCM1723 is connected to +// all 3 of them, it doen't matter wich one you choose. +// divider=0: ACLK=768*Fs / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/12 / DAC-A_ACLK=ACLK/3 +// divider=1: ACLK=768*Fs / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/12 / DAC-A_ACLK=ACLK/2 +// divider=2: ACLK=512*Fs / S/PDIF-BCLK=ACLK/4 / DAC-BCLK=ACLK/8 / DAC-A_ACLK=ACLK/2 +// divider=3: ACLK=384*Fs / S/PDIF-BCLK=ACLK/3 / DAC-BCLK=ACLK/6 / DAC-A_ACLK=ACLK/1 +// divider=4: ACLK=256*Fs / S/PDIF-BCLK=ACLK/2 / DAC-BCLK=ACLK/4 / DAC-A_ACLK=ACLK/1 +// divider=5: ACLK=768*48kHz / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/6 / DAC-A_ACLK=ACLK/1 +// divider=6: ACLK=512*48kHz / S/PDIF-BCLK=ACLK/4 / DAC-BCLK=ACLK/4 / DAC-A_ACLK=ACLK/1 +// divider=C: ACLK=768*48kHz / S/PDIF-BCLK=ACLK/9 / DAC-BCLK=ACLK/18 / DAC-A_ACLK=ACLK/3 +// divider=D: ACLK=512*48kHz / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/12 / DAC-A_ACLK=ACLK/3 +// divider=E: ACLK=512*48kHz / S/PDIF-BCLK=ACLK/6 / DAC-BCLK=ACLK/12 / DAC-A_ACLK=ACLK/2 +// divider=F: ACLK=256*48kHz / S/PDIF-BCLK=ACLK/3 / DAC-BCLK=ACLK/6 / DAC-A_ACLK=ACLK/1 +// Fs is the audio sample frequency +// For the normal cases, (32, 44.1, and 48 kHz) select divider 0 through 4 and set +// sample frequency in PCM1723 accordingly +// For 96 kHz, select divider 5 or 6, and set PCM1723 to 48kHz*768 or *512 resp. +// Divider C through F are for 32 kHz sample frequency with a 48kHz*x ACLK +void AudioSetACLK(struct cvdv_cards *card, int select, int divider); + +int AudioOpen(struct cvdv_cards *card); + +int AudioClose(struct cvdv_cards *card); + +// audiorate: 16, 32, 64, 22(.05), 44(.1), 88(.2), 24, 48, 96 kHz +// surround=0: Stereo +// surround=1: Surround +int AudioInit(struct cvdv_cards *card, int audiorate, int surround); + + +// returns size of the Video ES Buffer in bytes or 0=error +u32 DecoderGetAudioESSize(struct cvdv_cards *card); + +// returns level of fullness in bytes +u32 DecoderGetAudioESLevel(struct cvdv_cards *card); + +int DecoderKaraoke(struct cvdv_cards *card, int vocal1, int vocal2, + int melody); + +#endif /* CVDV_AUDIO_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/AUTHORS linux.20pre2-ac1/drivers/media/video/margi/AUTHORS --- linux.20pre2/drivers/media/video/margi/AUTHORS 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/AUTHORS 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,6 @@ +Christian Wolff scarabaeus@convergence.de +Marcus Metzler mocm@convergence.de + +Many thanks to +Shigehiro Nomura s.nomura@mba.nifty.ne.jp +for his ZV-patches for Libretto diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/cardbase.c linux.20pre2-ac1/drivers/media/video/margi/cardbase.c --- linux.20pre2/drivers/media/video/margi/cardbase.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/cardbase.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,234 @@ +/* + cardbase.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define __NO_VERSION__ + +#include "cardbase.h" + +// List of pci cards in the system +struct cvdv_cards *first_card = NULL; +struct cvdv_cards *minorlist[MAXDEV]; + +u8 FlushPacket[32] = { + 0x00, 0x00, 0x01, 0xE0, // video stream start code + 0x00, 0x1a, // 26 more bytes + 0x81, 0xC1, // flags: copy=1, PTS_DTS=11, PES_extension=1 + 0x0D, // 13 more header bytes + 0x31, 0x00, 0x03, 0x5F, 0xEB, // PTS + 0x11, 0x00, 0x03, 0x48, 0x75, // DTS + 0x1E, // flags: P-STD_buffer=1, + 0x60, 0xE8, // P-STD_buffer_scale=1, P-STD_buffer_size=232(kByte) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void DecoderStreamReset(struct cvdv_cards *card) +{ + card->stream.valid = 0; + card->stream.sh.valid = 0; + card->stream.se.valid = 0; + card->stream.gop.valid = 0; + card->stream.MPEG2 = 0; + card->stream.audio.valid = 0; + memset(&card->stream.audio.mpeg,0,sizeof(struct AudioMPEG)); + memset(&card->stream.audio.ac3,0,sizeof(struct AudioAC3)); + memset(&card->stream.audio.pcm,0,sizeof(struct AudioPCM)); + card->AuxFifoExt = 0; + card->AuxFifoLayer = -1; +} +void PTSStoreInit(PTSStorage * store, int size) +{ + int i; + if (size > MAX_PTS) + size = MAX_PTS; + store->size = size; + store->begin = 0; + store->end = 0; + store->LastAddr = 0; + for (i = 0; i < store->size; i++) { + store->AddrB[i] = 0; + store->AddrE[i] = 0; + store->PTS[i] = 0; + } +} + +void DecoderCSSReset(struct cvdv_cards *card) +{ + card->css.status = 0; + card->css.ChallengeReady = 0; + card->css.ResponseReady = 0; + card->css.DiskKey = 0; + card->css.TitleKey = 0; + card->css.Error = 0; + card->css.TitleKeyDiff = 0; + card->LastAddr = 0; // last used address in PES buffer + card->VPTS = 0; + card->oldVPTS = 0; + card->VSCR = 0; + card->APTS = 0; + card->oldAPTS = 0; + card->ASCR = 0; + card->SyncTime = 0; + card->paused = 0; // pause status + card->lastvattr = 0; // last set dvd video attribute + card->lastaattr = 0; // last set dvd audio attribute + card->nonblock = 0; +} + +void DecoderSetupReset(struct cvdv_cards *card) +{ + card->DecoderOpen = 0; + card->closing = 0; + card->channelrun = 0; + card->setup.streamtype = stream_none; + card->setup.audioselect = audio_none; + card->setup.videoID = 0; + card->setup.audioID = 0; + card->setup.audioIDext = -1; + card->setup.SPDIFmode = 0; + card->startingV = 0; + card->startingA = 0; + card->startingDVDV = 0; + card->startingDVDA = 0; + card->videodelay = 0; + card->videodelay_last = 0; + card->videoslow_last = 0; + card->videoslow = 0; + card->videoffwd = 0; + card->videoffwd_last = 0; + card->videoskip = 0; + card->videoskip_last = 0; + card->videosync = 0; + card->paused = 0; + PTSStoreInit(&card->VideoPTSStore, MAX_PTS); + PTSStoreInit(&card->AudioPTSStore, MAX_PTS); +#ifdef DVB + card->audiostate.AVSyncState=true; +#endif +} + + + +void card_init(struct cvdv_cards *card, unsigned int minor) +{ + card->DRAMFirstBlock = NULL; + card->DRAMSize = 0; + card->OSD.open = 0; + card->DMAABusy = 0; + card->DMABBusy = 0; + card->IntInstalled = 0; + card->ChannelBuffersAllocated = 0; + card->VideoES = BLANK; + card->AudioES = BLANK; + card->VideoPES = BLANK; + card->DataDump = BLANK; + card->AudioPES = BLANK; + card->NaviBank = BLANK; + card->FrameBuffersAllocated = 0; + card->FrameStoreLuma1 = BLANK; + card->FrameStoreChroma1 = BLANK; + card->FrameStoreLuma2 = BLANK; + card->FrameStoreChroma2 = BLANK; + card->FrameStoreLumaB = BLANK; + card->FrameStoreChromaB = BLANK; + card->DecoderOpen = 0; + card->AuxFifoHead = 0; + card->AuxFifoTail = 0; + card->DataFifoHead = 0; + card->DataFifoTail = 0; + card->FifoALast = -1; + card->FifoBLast = -1; + //reset_stream(card); + DecoderStreamReset(card); + DecoderSetupReset(card); + card->AudioInitialized = 0; + card->AudioOldMode = -1; + card->closing = 0; + card->startingV = 0; + card->startingA = 0; + card->startingDVDV = 0; + card->startingDVDA = 0; + card->channelrun = 0; + card->fields = 0; + DecoderCSSReset(card); + card->NaviPackAddress = 0; + init_waitqueue_head(&card->wqA); + init_waitqueue_head(&card->wqB); + card->navihead = 0; // write pointer for navi ring buffer + card->navitail = 0; // read pointer for navi ring buffer + card->intdecodestatus = 0; // last status of decode interrupt + card->showvideo = 0; // show video instead black as soon as picture slice is there + card->videodelay = 0; // slow counter + card->videodelay_last = 0; // slow counter + card->videoffwd = 0; // fast playback + card->videoffwd_last = 0; // fast playback + card->videoskip = 0; // fast counter + card->videoskip_last = 0; // fast counter + card->videoslow_last = 0; + card->videoslow = 0; + card->videosync = 0; // do audio/video sync basen on PTS? + PTSStoreInit(&card->VideoPTSStore, MAX_PTS); + PTSStoreInit(&card->AudioPTSStore, MAX_PTS); + card->LastAddr = 0; // last used address in PES buffer + card->VPTS = 0; + card->oldVPTS = 0; + card->VSCR = 0; + card->APTS = 0; + card->oldAPTS = 0; + card->ASCR = 0; + card->SyncTime = 0; + card->paused = 0; // pause status + card->lastvattr = 0; // last set dvd video attribute + card->lastaattr = 0; // last set dvd audio attribute + card->reg08F = 0; // mirror of decoder registers + card->reg090 = 0; + card->reg091 = 0; + card->reg092 = 0; + card->reg093 = 0; + card->highlight_valid = 0; // SPU highlight info available for next BAV int + card->do_flush = 0; + + card->open = 0; + + card->VideoESSize = 0; + card->AudioESSize = 0; + card->VideoPESSize = 0; + card->DataDumpSize = 0; + card->AudioPESSize = 0; + card->NaviBankSize = 0; + card->currentType = -1; + card->rbufA.buffy = NULL; + card->rbufB.buffy = NULL; + card->use_ringA = 0; + card->use_ringB = 0; + card->minor = minor; + card->hasZV = 0; +#ifdef NOINT + init_timer(&card->timer); + spin_lock_init(&card->timelock); +#endif +#ifdef DVB + card->dvb_registered = 0; + card->audiostate.AVSyncState=true; + card->nonblock = 0; +#endif + card->svhs = 0; + card->composite = 0; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/cardbase.h linux.20pre2-ac1/drivers/media/video/margi/cardbase.h --- linux.20pre2/drivers/media/video/margi/cardbase.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/cardbase.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,454 @@ +/* + cardbase.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CARDBASE_H +#define CARDBASE_H + +#define __DVB_PACK__ +#define USE_OSD +#define NOINT +#define DVB +#define USE_ZV + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define MARGI_DEBUG (pc_debug) +#else +#define MARGI_DEBUG 2 +#endif + +// all the internal structs + +#include + +#include "ringbuffy.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DVB +#include "dvbdev.h" +#ifdef __DVB_PACK__ +#include "ost/video.h" +#include "ost/audio.h" +#include "ost/demux.h" +#include "ost/dmx.h" +#include "ost/sec.h" +#include "ost/frontend.h" +#include "ost/ca.h" +#include "ost/osd.h" +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_filter.h" +#endif +// List of pci cards in the system + +#include "cvdvtypes.h" + +#define DVERSION "0.6.0" +#define SHORTDEVNAME "ConvDVD" +#define MEDDEVNAME "convergence DVD" +#define LONGDEVNAME "convergence DVD Video Decoder" +#define LOGNAME "convdvd " +#define NBBUF 8 + + +#ifdef MARGI_DEBUG +#define MDEBUG(n, args...) if (MARGI_DEBUG>(n)) printk(KERN_ERR LOGNAME args) +#else +#define MDEBUG(n, args...) +#endif + + +#define VID_PAN_SCAN_PREF 0x01 /* Pan and Scan Display preferred */ +#define VID_VERT_COMP_PREF 0x02 /* Vertical compression display preferred */ +#define VID_VC_AND_PS_PREF 0x03 /* PanScan and vertical Compression if allowed */ +#define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ + + +// Character device definitions +// char dev name +#define CVDV_PROCNAME "msc" // Media Stream Consumer +// got to get another number +#define CVDV_MAJOR 200 // 0=dynamic assignment + +// Author definitions +#define NAME "Christian Wolff" +#define EMAIL "scarabaeus@convergence.de" +#define COMPANY "convergence integrated media GmbH" +#define AUTHOR NAME " <" EMAIL "> " COMPANY + +#define MAXDEV 1 // maximum number of cards, distance between minor devices + +#define MINORNUM (256/MAXDEV) // number of minor devices + +#define NAVISIZE 1024 // size of one navi block +#define NAVIBUFFERSIZE NAVISIZE*10 // size of ten navi blocks + +#define BLANK 0xFFFFFFFF + +#define FIFO_MASK 1023 + +#define CCIR601Lines(system) (((system==NTSC) || (system==NTSC60) || (system==PALM) || (system==PALM60) || (system==PAL60))?525:625) + +// default video mode +#define VIDEO_MODE PAL +//#define VIDEO_MODE NTSC + +struct DRAMBlock { + u32 start; // start address of the block; (21 bit word address, 64 bit aligned) + u32 length; // length of the block (in 16 bit words) + struct DRAMBlock *next; // chain link +}; + +struct CSS { + u8 status; // interrupt status from Register 0x0B0 + int ChallengeReady; // 1 if challenge data valid + u8 challenge[10]; // challenge data + int ResponseReady; // 1 if response data valid + u8 response[5]; // response data + int DiskKey; // 1 if disk key extraction complete + int TitleKey; // 1 if title key decryption complete + int Error; // 1 if authentication or disc key extraction + int TitleKeyDiff; // 1 if title key different from previous +}; + +struct GOPHeader { + int valid; // 1: struct contains valid data + int timecode; + int closedgop; + int brokenlink; +}; + +struct SequenceHeader { + int valid; // 1: struct contains valid data + int hsize; + int vsize; + int aspectratio; + int frameratecode; + int bitrate; + int vbvbuffersize; + int constrained; +}; + +struct SequenceExtension { + int valid; // 1: struct contains valid data + int profilelevel; + int progressive; + int chroma; + int hsizeext; + int vsizeext; + int bitrateext; + int vbvbuffersizeext; + int lowdelay; + int frextn; + int frextd; +}; + +struct AudioMPEG { + int present; // true: MPEG audio stream present + int MPEG2; // 0:MPEG1 Audio + int layer; // 1..3 (I..III) + int bitrate; // 0=free, 32-448 kbps + int samplefreq; // 32,44,48 (44 eq. 44.1) + int mode; // 0=stereo 1=joint-stereo 2=dualchannel 3=single channel (just right channel) + int modeext; // Layer I&II: intensity stereo subbands Layer III: bit 0=intensity stereo, bit 1=ms-stereo + int copyright; // true=copyrighted material + int original; // 0=copy true=original + int emphasis; // 0=no emph. 1=50/15usec 3=CCITT J.17 +}; + +struct AudioAC3 { + int present; // 1: AC3 audio stream present + int acmod; // parameters from the AC3 documentation + int bsmod; + int dialnorm; + int dialnorm2; + int surmixlev; + int mixlevel; + int cmixlev; + int mixlevel2; + int fscod; + int lfeon; + int bsid; + int dsurmod; + int frmsizecod; + int langcod; + int langcod2; + int timecod; + int roomtyp; + int timecod2; + int roomtyp2; +}; + +struct AudioPCM { + int present; // 1: PCM audio stream present + int audio_frm_num; + int num_of_audio_ch; + int Fs; + int quantization; + int emphasis; + int mute_bit; +}; + +struct AudioParam { + int valid; + struct AudioMPEG mpeg; + struct AudioAC3 ac3; + struct AudioPCM pcm; +}; + +struct OSDPicture { // all u32 pointers are 21 bit word addresses + int open; // are the buffers initialized? + int width; // frame width + int height; // frame height + int bpp; // bit per pixel + int evenfirst; // first line is in even field + int aspectratio; // pixel aspect ratio: 11/aspectratio + int oddheight; // height of the odd field + u32 oddmem; // DRAM address of allocated memory + u32 odddata; // data (=header) pointer + u32 oddpalette; // pointer to palette inside data + u32 oddbitmap; // pointer to bitmap inside data + u32 oddterm; // pointer to termination header + int evenheight; // height of the even field + u32 evenmem; // DRAM address of allocated memory + u32 evendata; // data (=header) pointer + u32 evenpalette; // pointer to palette inside data + u32 evenbitmap; // pointer to bitmap inside data + u32 eventerm; // pointer to termination header +}; + +struct StreamInfo { + int valid; // 1: struct contains valid data + int MPEG2; // 0: MPEG1/ISO11172 1: MPEG2/ISO13818 + int hsize; // overall hsize (hsize&hsizeext) + int vsize; // overall vsize (vsize&vsizeext) + int bitrate; // overall bitrate (bitrate&bitrateext) + int vbvbuffersize; // overall... + struct GOPHeader gop; + struct SequenceHeader sh; + struct SequenceExtension se; + struct AudioParam audio; +}; + +struct StreamSetup { // user selected parameters for the stream playback + stream_type streamtype; // what is the type of our input stream? + audio_type audioselect; // 0=auto/unknown 1=MPEG 2=LPCM 3=AC3 + int videoID; // stream ID of the video ES, -1 for any + int audioID; // stream ID of the audio ES, -1 for any + int audioIDext; // stream ID of the audio extension ES, -1 for none + int SPDIFmode; // 0:MPEG/AC3 data on digital S/PDIF out 1:IEC956 data on digital S/PDIF out +}; + +#define MAX_PTS 256 + +typedef struct PTSRecord { + int begin; + int end; + int size; + u32 LastAddr; + u32 AddrB[MAX_PTS]; + u32 AddrE[MAX_PTS]; + u32 PTS[MAX_PTS]; +} PTSStorage; + +#define DVB_DEVS_MAX 9 + +typedef struct dvb_devs_s { + int num; + int tab[DVB_DEVS_MAX]; + int max_users[DVB_DEVS_MAX]; + int max_writers[DVB_DEVS_MAX]; +} dvb_devs_t; + +struct cvdv_cards { +#ifdef DVB + struct dvb_device dvb_dev; + dvb_demux_t demux; +#endif + struct cvdv_cards *next; + void *margi; + struct bus_operations *bus; + u_char scl; + u_char sda; + int i2c_addr; + u32 VideoESSize; + u32 AudioESSize; + u32 VideoPESSize; + u32 DataDumpSize; + u32 AudioPESSize; + u32 NaviBankSize; + int currentType; + ringbuffy rbufA; + ringbuffy rbufB; + int use_ringA; + int use_ringB; + int nonblock; + u8 *addr; + unsigned int size; + unsigned int minor; + struct DRAMBlock *DRAMFirstBlock; + u32 DRAMSize; + struct OSDPicture OSD; + int DMAABusy; // Is the DMA A currently in use? + int DMABBusy; // Is the DMA B currently in use? + int IntInstalled; // is the card interrupt routine installed? + int ChannelBuffersAllocated; // Are the channel buffers for the decoder allocated? + u32 VideoES; // 21 bit word address of the allocated channel + u32 AudioES; // 21 bit word address of the allocated channel + u32 VideoPES; // 21 bit word address of the allocated channel + u32 DataDump; // 21 bit word address of the allocated channel + u32 AudioPES; // 21 bit word address of the allocated channel + u32 NaviBank; // 21 bit word address of the allocated channel + int FrameBuffersAllocated; // Are the frame buffers for the decoder allocated? + u32 FrameStoreLuma1; // 21 bit word address of the allocated frame + u32 FrameStoreChroma1; // 21 bit word address of the allocated frame + u32 FrameStoreLuma2; // 21 bit word address of the allocated frame + u32 FrameStoreChroma2; // 21 bit word address of the allocated frame + u32 FrameStoreLumaB; // 21 bit word address of the allocated frame + u32 FrameStoreChromaB; // 21 bit word address of the allocated frame + int DecoderOpen; // Is the Decoder initialized? + u16 AuxFifo[FIFO_MASK + 1]; // Auxiliary Fifo Data + int AuxFifoHead; // Auxiliary Fifo Position + int AuxFifoTail; // Auxiliary Fifo Position + u16 DataFifo[FIFO_MASK + 1]; // Data Fifo Data + int DataFifoHead; // Data Fifo Position + int DataFifoTail; // Data Fifo Position + int FifoALast; // last used thread of FIFO A + int FifoBLast; // last used thread of FIFO B + videosystem videomode; // current video output mode, PAL or NTSC + struct StreamInfo stream; // header information of the current stream + struct StreamSetup setup; // should be filled bevor sending data, but default is OK + int AuxFifoExt; // used by Aux FIFO parser + int AuxFifoLayer; // " " " " " + int AudioInitialized; // Is the Audio set up? + int AudioOldMode; // remainder of the previous mode while trickmodes, or -1 + int open; // is the 64017 initialized and the video out active? + int closing; // 1 if char device closed, but DMA still running + int startingV; // 1 if card is waiting for the Video ES buffer to fill up, to start the decoder + int startingA; // 1 if card is waiting for the Audio ES buffer to fill up, to start the decoder + int startingDVDV; // 1 if card is waiting for the Video ES buffer to fill up, to start the decoder + int startingDVDA; // 1 if card is waiting for the Audio ES buffer to fill up, to start the decoder + int channelrun; // 1 if channel has been started by the host + int fields; // counter of video fields, debugging only + struct CSS css; // CSS data + u32 NaviPackAddress; // Read address of the Navi Pack Buffer + wait_queue_head_t wqA; + wait_queue_head_t wqB; + u8 navibuffer[NAVIBUFFERSIZE]; + int navihead; + int navitail; + int intdecodestatus; + int showvideo; + int videodelay; + int videodelay_last; + int videoskip; + int videoskip_last; + int videosync; + int videoslow; + int videoslow_last; + int videoffwd; + int videoffwd_last; + PTSStorage VideoPTSStore; + PTSStorage AudioPTSStore; + u32 LastAddr; + u32 VPTS; + u32 oldVPTS; + long VSCR; + u32 APTS; + u32 oldAPTS; + int scrset; + long ASCR; + long SyncTime; + int paused; + u16 lastvattr; + u16 lastaattr; + u8 reg07B; // mirrors of write-only register + u8 reg08F; + u8 reg090; + u8 reg091; + u8 reg092; + u8 reg093; + u8 highlight[10]; // content of registers 1C0 thru 1C0, to be written after next BAV int. + int highlight_valid; // if 1 + int do_flush; // if 1, send flush packet after last transfer done + int hasZV; +#ifdef NOINT + struct timer_list timer; + spinlock_t timelock; +#endif + +#ifdef DVB + dvb_devs_t *dvb_devs; + int users[DVB_DEVS_MAX]; + int writers[DVB_DEVS_MAX]; + + dmxdev_t dmxdev; + boolean video_blank; + struct videoStatus videostate; + struct audioStatus audiostate; + int dvb_registered; + char demux_id[16]; + dmx_frontend_t mem_frontend; + ipack tsa; + ipack tsv; +#endif + + int svhs; + int composite; +}; + +extern u8 FlushPacket[32]; + +extern struct cvdv_cards *first_card; +extern struct cvdv_cards *minorlist[MAXDEV]; + +void DecoderStreamReset(struct cvdv_cards *card); + +void DecoderSetupReset(struct cvdv_cards *card); + +void DecoderCSSReset(struct cvdv_cards *card); + +void card_init(struct cvdv_cards *card, unsigned int minor); + +#endif /* CARDBASE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/CHANGES linux.20pre2-ac1/drivers/media/video/margi/CHANGES --- linux.20pre2/drivers/media/video/margi/CHANGES 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/CHANGES 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,30 @@ +version 0.6 +- added ZV initialisation +- added diff for ZV support in pcmcia-cs version <= 3.1.25 +- added v4l device +- added dvb api devices +- tested it with powerbook g4 and pcmcia-cs-3.1.24 +- WARNING, on some computers using FFWD and slow motion may cause hangups + +version 0.5 +- should work with 2.4.0-test12 +- added driver to public CVS at linuxtv.org + http://linuxtv.org/cgi-bin/cvsweb.cgi/ +- added 32kHz audio support +- fixed problem with PAL MPEG1 playback +- fixed problem with playback of MPEGs with lots of PTS +- fixed switching audio channels + +version 0.4.3 +- it is now working with 2.4.0-test10 and later kernels. Use pcmcia-cs-3.1.22 + and later.(Don't use kernel pcmcia,it's not tested with that. ) +- added playfile to the testsuite + +version 0.4.2 +- changed major device number to 200 until we get a new one +- changed some buffer settings for DVD playback +- added some programming examples in testsuit directory +- some other minor improvements + +version 0.4.1 +- corrected makefile error diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/COPYING linux.20pre2-ac1/drivers/media/video/margi/COPYING --- linux.20pre2/drivers/media/video/margi/COPYING 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/COPYING 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/crc.c linux.20pre2-ac1/drivers/media/video/margi/crc.c --- linux.20pre2/drivers/media/video/margi/crc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/crc.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,78 @@ +/* + crc.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/*--------------------------------------------------------- + +Cyclic Redundancy Check 16 and 32 Bit + +Christian Wolff, 19990122 + +---------------------------------------------------------*/ + +#define __NO_VERSION__ + +#include "crc.h" + +unsigned short crc_16_table[256]; +unsigned long crc_32_table[256]; + +// generate the tables of CRC-16 and CRC-32 remainders for all possible bytes +void gen_crc_table() +{ + register int i, j; + register unsigned short crc16; + register unsigned long crc32; + for (i = 0; i < 256; i++) { + crc16 = (unsigned short) i << 8; + crc32 = (unsigned long) i << 24; + for (j = 0; j < 8; j++) { + if (crc16 & 0x8000) + crc16 = (crc16 << 1) ^ POLYNOMIAL_16; + else + crc16 = (crc16 << 1); + if (crc32 & 0x80000000L) + crc32 = (crc32 << 1) ^ POLYNOMIAL_32; + else + crc32 = (crc32 << 1); + } + crc_16_table[i] = crc16; + crc_32_table[i] = crc32; + } +} + +// update the CRC on the data block one byte at a time +unsigned short update_crc_16_block(unsigned short crc, + char *data_block_ptr, + int data_block_size) +{ + register int i; + for (i = 0; i < data_block_size; i++) + crc = update_crc_16(crc, *data_block_ptr++); + return crc; +} + +unsigned long update_crc_32_block(unsigned long crc, char *data_block_ptr, + int data_block_size) +{ + register int i; + for (i = 0; i < data_block_size; i++) + crc = update_crc_32(crc, *data_block_ptr++); + return crc; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/crc.h linux.20pre2-ac1/drivers/media/video/margi/crc.h --- linux.20pre2/drivers/media/video/margi/crc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/crc.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,56 @@ +/* + crc.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/*--------------------------------------------------------- + +Cyclic Redundancy Check 16 and 32 Bit - Header File + +Christian Wolff, 19990122 + +---------------------------------------------------------*/ + +#ifndef _CRC_H_ +#define _CRC_H_ + +// 16 Bit CCITT standard polynomial x^16 + x^12 + x^5 + x^1 + x^0 +#define POLYNOMIAL_16 0x1021 +// 32 Bit standard polynomial x^32 + x^26 + x^23 + x^22 + x^16 + +// x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + x^0 +#define POLYNOMIAL_32 0x04C11DB7L + +#define CRC_INIT_16 0xFFFF +#define CRC_INIT_32 0xFFFFFFFFL + +#define update_crc_16(crc, data) ((crc << 8) ^ crc_16_table[((int)(crc >> 8 ) ^ (data)) & 0xFF]) +#define update_crc_32(crc, data) ((crc << 8) ^ crc_32_table[((int)(crc >> 24) ^ (data)) & 0xFF]) + +extern unsigned short crc_16_table[256]; +extern unsigned long crc_32_table[256]; + +extern void gen_crc_table(void); + +extern unsigned short update_crc_16_block(unsigned short crc, + char *data_block_ptr, + int data_block_size); +extern unsigned long update_crc_32_block(unsigned long crc, + char *data_block_ptr, + int data_block_size); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/cvdv.c linux.20pre2-ac1/drivers/media/video/margi/cvdv.c --- linux.20pre2/drivers/media/video/margi/cvdv.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/cvdv.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1985 @@ +/* + cvdv.c + + Copyright (C) Christian Wolff + Marcus Metzler for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + ///////////////////////////////////////////////////////////////////// + // // + // Driver for the Convergence Digital Video decoder card (pci) // + // with L64017, L64021, PCM1723, and Bt864/Bt865 chipset // + // (c) Christian Wolff 19990209 for convergence integrated media // + // // +///////////////////////////////////////////////////////////////////// + +// Convergence CV2300i +#define __NO_VERSION__ + +#include +#include "cvdv.h" +#include "ost/osd.h" +#include "i2c.h" + + ////////////////////// + // global variables // +////////////////////// + +// Our major device number +unsigned int major_device_number; + + +// my little random function for memory test +uint16_t rnd_seed; +uint16_t rnd(uint16_t range) +{ // returns random 0..(range-1) range<=872 + uint32_t b = 75 * (rnd_seed + 1) - 1; + rnd_seed = (uint16_t) (b & 0xFFFF); + return ((b * range) / 0xFFFF) - ((b / 0xFFFF) * range); +} +void rnd_omize(void) +{ + rnd_seed = (uint16_t) jiffies; +} + +static char *cimlogo[] = { +".............................................", +".............................................", +"......................###....................", +".....................#####...................", +".....................######..................", +"..............#......#####...................", +"...........#####....######...................", +".........########...######...................", +"........########....######...................", +".......#########...######....................", +"......########.....######...####.............", +".....#######.......#####...#####.............", +".....######.......######...######............", +"....#######.......######....######...........", +"....######........######....######...........", +"....#####........######......#####...........", +"...######........######......#####...........", +"...#####.........######......######..........", +"...#####.........#####.......######..........", +"...#####........######........#####..........", +"...#####........######.......######..........", +"...#####........#####.........#####..........", +"...#####.......######........######..........", +"...#####.......######........#####...........", +"...######.......####.........#####...........", +"....#####........##.........######...........", +"....######..................######...........", +"....######.................######............", +".....#######..............######.....#####...", +".....########............#######....#######..", +"......#########........########.....#######..", +".......#######################......########.", +"........#####################.......#######..", +"..........#################.........#######..", +"............#############............#####...", +"...............#.#####.................##....", +".............................................", +"............................................." +}; + + ///////////////////////////////////////////// + // // + // Controlling the L64021 MPEG-2 Decoder // + // // +///////////////////////////////////////////// + +int OSDTest(struct cvdv_cards *card) +{ + int i, j, col, x0, y0, x1, y1,aspx; + uint8_t b; + + + if (!card->OSD.open) + return -2; + + OSDQuery(card, &x0, &y0, &x1, &y1, &aspx); + OSDShow(card); + OSDSetColor(card, 0, 0, 0, 0, 0, 0, 0); + OSDSetColor(card, 1, 128, 255, 255, 0, 0, 0); + for ( i = 0; i < cimlogo_width; i++){ + for ( j = 0; j < cimlogo_height; j++){ + b = cimlogo[j][i]; + col = (b == '#') ? 1: 0; + OSDSetPixel(card, x0+i, y0+j, col); + } + } + + return 0; +} + + +void SetVideoSystem(struct cvdv_cards *card) +{ + uint8_t reg; + + // set the hsync and vsync generators in the L64017 according to the video standard + reg = read_indexed_register(card, IIO_VIDEO_CONTROL1); + reg &= ~0x03; + switch (card->videomode) { + case PAL: // 864*625*50Hz = 27MHz, 25fps + I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x41 | 0x0a); + I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04); + I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x96); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0x13); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x54); + reg |= VMS_PAL; + break; + case PALN: + I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0xa1 | 0x0a); + I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04); + I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x96); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0x13); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x54); + reg |= VMS_PAL; + break; + + case PALNc: + I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x81 | 0x0a); + I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04); + I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x8c); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x28); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xed); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43); + reg |= VMS_PAL; + break; + + case NTSC: // 858*525*59.94006Hz = 27MHz, 29.97fps + I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x01 | 0x0a); + I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04); + I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x1c); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x3e); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0xf8); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xe0); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43); + reg |= VMS_NTSC; + break; + + case PALM: + I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x01 | 0x0a); + I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04); + I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x4e); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x4a); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xe1); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43); + reg |= VMS_PAL; + break; + + case NTSC60: // 857*525*60.010002Hz = 27MHz, 30fps + I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x21 | 0x0a); + I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04); + I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x1c); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x3e); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0xf8); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xe0); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43); + reg |= VMS_NTSC; + break; + + case PALM60: + I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x61 | 0x0a); + I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04); + I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x4e); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x4a); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xe1); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43); + reg |= VMS_PAL; + break; + + case PAL60: + break; + } + write_indexed_register(card, IIO_VIDEO_CONTROL1, reg); + // set the pixel generators according to the video standard + L64021Setup(card); +} + +int SetVideoAttr(struct cvdv_cards *card, uint16_t vattr) +{ + uint8_t video_compression_mode; + uint8_t tv_system; + uint8_t aspect_ratio; + uint8_t display_mode; + uint8_t line_21_switch_1; + uint8_t line_21_switch_2; + uint8_t source_picture_resolution; + uint8_t source_picture_letterboxed; + uint8_t reserved; + uint8_t film_camera_mode; + uint16_t hsize, vsize; + if (vattr != card->lastvattr) { + video_compression_mode = (vattr >> 14) & 0x03; + tv_system = (vattr >> 12) & 0x03; + aspect_ratio = (vattr >> 10) & 0x03; + display_mode = (vattr >> 8) & 0x03; + line_21_switch_1 = (vattr >> 7) & 0x01; + line_21_switch_2 = (vattr >> 6) & 0x01; + source_picture_resolution = (vattr >> 3) & 0x07; + source_picture_letterboxed = (vattr >> 2) & 0x01; + reserved = (vattr >> 1) & 0x01; + film_camera_mode = (vattr >> 0) & 0x01; + card->videomode = + ((tv_system == 0) ? NTSC : ((tv_system == 1) ? + PAL : PAL)); + SetVideoSystem(card); + hsize = + ((source_picture_resolution == 0) ? 720 + : ((source_picture_resolution == 1) ? 702 : 352)); + vsize = ((source_picture_resolution == 3) + ? ((tv_system == 0) ? 240 : 288) + : ((tv_system == 0) ? 480 : 576)); + if (DecoderOpen + (card, hsize, vsize, ((aspect_ratio) ? 3 : 2), + ((video_compression_mode) ? 0 : 1), + source_picture_letterboxed, tv_system)) { + MDEBUG(0, + ": Video Decoder Open failed: On-card memory insufficient for frame stores\n"); + } + card->lastvattr = vattr; + } else { + MDEBUG(0, + ": Video attribute not set, equal to previous one.\n"); + } + return 0; +} + +int SetAudioAttr(struct cvdv_cards *card, uint16_t aattr) +{ + uint8_t audio_coding_mode; + uint8_t multichannel_extension; + uint8_t audio_type; + uint8_t audio_application_mode; + uint8_t quantization_drc; + uint8_t fs; + uint8_t reserved; + uint8_t num_audio_ch; + if (aattr) { + if (aattr != card->lastaattr) { + audio_coding_mode = (aattr >> 13) & 0x07; + multichannel_extension = (aattr >> 12) & 0x01; + audio_type = (aattr >> 10) & 0x03; + audio_application_mode = (aattr >> 8) & 0x03; + quantization_drc = (aattr >> 6) & 0x03; + fs = (aattr >> 4) & 0x03; + reserved = (aattr >> 3) & 0x01; + num_audio_ch = (aattr >> 0) & 0x07; + switch (audio_coding_mode) { + case 0: // AC-3 + card->setup.audioselect = audio_AC3; + break; + case 2: // MPEG Audio + card->setup.audioselect = audio_MPEG; + break; + case 3: // MPEG Audio with ext. + card->setup.audioselect = audio_MPEG_EXT; + break; + case 4: // Linear Pulse Code Modulation LPCM + card->setup.audioselect = audio_LPCM; + break; + case 6: // DTS + card->setup.audioselect = audio_DTS; + break; + case 7: // SDDS + card->setup.audioselect = audio_SDDS; + break; + } + DecoderPrepareAudio(card); + AudioInit(card, ((fs) ? 96 : 48), + ((audio_application_mode == 2) ? 1 : 0)); + } else { + MDEBUG(0, + ": Audio attribute not set, equal to previous one.\n"); + } + } else { + card->setup.audioselect = audio_none; + DecoderPrepareAudio(card); + } + card->lastaattr = aattr; + return 0; +} + +int Prepare(struct cvdv_cards *card) +{ + int err, h; + struct StreamSetup *setup = &card->setup; + + if (!card->ChannelBuffersAllocated) { + + DecoderStreamReset(card); + if (setup->streamtype == stream_none) { + setup->streamtype = stream_PS; + } + + if (setup->audioselect == audio_none) { + setup->audioselect = audio_MPEG; + } + + DecoderPrepareAudio(card); + AudioMute(card, 1); + DecoderPrepareVideo(card); + VideoSetBackground(card, 1, 0, 0, 0); // black + + switch (setup->streamtype) { + default: + case stream_none: // unknown stream! + MDEBUG(0, + ": Video Decoder Prepare failed: unknown stream type\n"); + return -ENODEV; // not an MPEG stream! + case stream_ES: // Elementary Stream + err = DecoderPrepareES(card); + break; + case stream_PES: // Packetized Elementary Stream + err = DecoderPreparePES(card); + break; + case stream_PS: // MPEG-1 System Stream / MPEG-2 Program Stream + err = DecoderPreparePS(card, -1, 0, 0, 0, 0, 0); + break; + case stream_DVD: // DVD Stream + err = DecoderPreparePS(card, 0, 0, 0, 0, 3, 1); + break; + } + if (err) { // insufficient memory + MDEBUG(0, + ": Video Decoder Prepare failed: no kernel memory, please reboot if possible\n"); + CloseCard(card); + return -ENODEV; + } + } + + // Set up the Video Decoder as we have the stream information + if ((!card->FrameBuffersAllocated) + && (card->ChannelBuffersAllocated) && (card->stream.sh.valid)) { + // Automatic PAL/NTSC-switch according to MPEG-Source + h = card->stream.vsize; + if (h < 480) + h *= 2; // catch quarter sized images + printk(KERN_INFO LOGNAME ": Video mode: %s\n", + ((h == 480) ? "NTSC" : "PAL")); + card->videomode = ((h == 480) ? NTSC : PAL); + SetVideoSystem(card); + // Open the Video Decoder with the parameters retreived from the stream + if ( + (err = + DecoderOpen(card, card->stream.hsize, + card->stream.vsize, + card->stream.sh.aspectratio, + !card->stream.MPEG2, 0, + (card->stream.hsize > 480)))) { // TODO: include vbvbuffersize + MDEBUG(0, + ": Video Decoder Open failed: %s\n", + ((err == 1) ? + "Picture size too big (>1440 pixel wide)" : + "On-card memory insufficient for frame stores")); + CloseCard(card); + return -ENODEV; // picture too big or insufficient memory + } + MDEBUG(1, ": Ready to go\n"); + card->startingV = 1; // tell the card to start playing as soon as ES-buffers are sufficiently full + card->startingA = 1; // tell the card to start playing as soon as ES-buffers are sufficiently full + } + + + return 0; +} + +int SetSCRstart(struct cvdv_cards *card, uint32_t SCR_base) +{ + uint32_t SCR_compare; + uint32_t SCR_compareA; + uint32_t SCR_compareV; + if (card->startingV) { + MDEBUG(0, ": SCR in DVD Pack: 0x%08X\n", + SCR_base); + card->startingV = 0; + card->startingA = 0; + DecoderMaskByte(card, 0x007, 0xD2, 0xD2); // Set 0x010, halt SCR counter + SCR_compare = SCR_base + 000; + if (SCR_base < 900) + SCR_base = 0; + else + SCR_base -= 900; + //DecoderWriteDWord(card,0x009,SCR_base); // Set SCR counter + DecoderWriteByte(card, 0x009, SCR_base & 0xFF); // Set SCR counter + DecoderWriteByte(card, 0x00A, (SCR_base >> 8) & 0xFF); + DecoderWriteByte(card, 0x00B, (SCR_base >> 16) & 0xFF); + DecoderWriteByte(card, 0x00C, (SCR_base >> 24) & 0xFF); + DecoderMaskByte(card, 0x011, 0x03, 0x02); // compare, not capture + MDEBUG(0, ": SCR compare value: 0x%08X\n", + SCR_compare); + //DecoderWriteDWord(card,0x00D,SCR_compare); // Set Compare register + DecoderWriteByte(card, 0x00D, SCR_compare & 0xFF); // Set Compare register + DecoderWriteByte(card, 0x00E, (SCR_compare >> 8) & 0xFF); + DecoderWriteByte(card, 0x00F, (SCR_compare >> 16) & 0xFF); + DecoderWriteByte(card, 0x010, (SCR_compare >> 24) & 0xFF); + //DecoderWriteDWord(card,0x014,SCR_compare); // Set audio compare reg. + DecoderWriteByte(card, 0x014, SCR_compare & 0xFF); // Set audio compare reg. + DecoderWriteByte(card, 0x015, (SCR_compare >> 8) & 0xFF); + DecoderWriteByte(card, 0x016, (SCR_compare >> 16) & 0xFF); + DecoderWriteByte(card, 0x017, (SCR_compare >> 24) & 0xFF); + DecoderSetByte(card, 0x013, 0x03); // Video and Audio start on cmp. + //DecoderSetVideoPanic(card,0,DecoderGetVideoESSize(card)/4); // video panic at 25 percent + VideoSetBackground(card, 1, 0, 0, 0); // black + SCR_base = DecoderReadByte(card, 0x009); + SCR_base = + SCR_base | ((uint32_t) DecoderReadByte(card, 0x00A) << 8); + SCR_base = + SCR_base | ((uint32_t) DecoderReadByte(card, 0x00B) << 16); + SCR_base = + SCR_base | ((uint32_t) DecoderReadByte(card, 0x00C) << 24); + SCR_compareA = DecoderReadByte(card, 0x014); + SCR_compareA = + SCR_compareA | ((uint32_t) DecoderReadByte(card, 0x015) << + 8); + SCR_compareA = + SCR_compareA | ((uint32_t) DecoderReadByte(card, 0x016) << + 16); + SCR_compareA = + SCR_compareA | ((uint32_t) DecoderReadByte(card, 0x017) << + 24); + SCR_compareV = DecoderReadByte(card, 0x00D); + SCR_compareV = + SCR_compareV | ((uint32_t) DecoderReadByte(card, 0x00E) << + 8); + SCR_compareV = + SCR_compareV | ((uint32_t) DecoderReadByte(card, 0x00F) << + 16); + SCR_compareV = + SCR_compareV | ((uint32_t) DecoderReadByte(card, 0x010) << + 24); + if (DecoderReadByte(card, 0x013) & 0x03) + MDEBUG(1,": SCR 0x%08X, videocmp=0x%08X, audiocmp=0x%08X %02X\n", + SCR_base, SCR_compareV, SCR_compareA, + DecoderReadByte(card, 0x013)); + DecoderMaskByte(card, 0x007, 0xD2, 0xC2); // Del 0x010, SCR counter run + } + return 0; +} + +int DecoderWriteBlock(struct cvdv_cards *card, uint8_t * data, int size, + int initial, int setSCR) +{ + //int a,v,as,vs,ap,vp; + int res; + uint32_t SCR_base; + int co = 0; + // uint32_t SCR_compare; + res = 0; + + Prepare(card); + + if (size > 0) { + + if (!card->use_ringA) + MargiSetBuffers(card, NBBUF*CHANNELBUFFERSIZE,0); + + if (card->startingDVDV || card->startingDVDA) + setSCR = 1; + + if (initial) { + DecoderStreamReset(card); + //TODO stop and start channel interface + setSCR = 1; + } + + if (setSCR) { + SCR_base = ParseSCR(data); + SetSCR(card, SCR_base); + } + card->DMAABusy = 0; + while (((res = MargiPushA(card, size, data)) < size) + && co < 1000) { + data+=res; + size-=res; + co++; + MDEBUG(2, + ": DecoderWriteBlock - buffers only filled with %d instead of %d bytes\n",res, size); + if (card->DMAABusy){ + interruptible_sleep_on(&card->wqA); + } + } + + if (card->startingDVDV) { + card->startingDVDV = 0; + card->startingV = 1; + DecoderStartDecode(card); + } + if (card->startingDVDA) { + card->startingDVDA = 0; + card->startingA = 1; + AudioSetPlayMode(card, MAUDIO_PLAY); + } + } + return 0; +} + + + + + + ////////////////////////////// + // // + // Char Device Procedures // + // // +////////////////////////////// +static long margi_write(struct cvdv_cards *card, const char *data, + unsigned long count, int nonblock) +{ + + int res; + long int out=0; + int free; + + free = ring_write_rest(&(card->rbufA)); + + if (card != NULL) { + card->nonblock = nonblock; + if (count > 0) { // Do we have data? + if ((res = Prepare(card))) + return res; + if (!card->use_ringA) + MargiSetBuffers(card, NBBUF*CHANNELBUFFERSIZE, + 0); + if (!nonblock && + !wait_event_interruptible( + card->wqA, + ring_write_rest(&(card->rbufA)) >count )){ + + out = MargiPushA(card, count, + data); + } else { + out = MargiPushA(card, count, data); + } + } + return out; + } else { + MDEBUG(0, + ": Video Decoder Prepare failed: device with this minor number not found\n"); + return -ENODEV; // device with this minor number not found + } +} + + +static long margi_write_audio(struct cvdv_cards *card, const char *data, + unsigned long count, int nonblock) +{ + struct StreamSetup *setup = &card->setup; + + int res; + long int out=0; + int free; + + free = ring_write_rest(&(card->rbufB)); + + if (card != NULL) { + card->nonblock = nonblock; + + if (count > 0) { // Do we have data? + if ((res = Prepare(card))) + return res; + if ((setup->streamtype == stream_ES) + || (setup->streamtype == stream_PES)){ + if (!card->use_ringB) + MargiSetBuffers(card, NBBUF* + CHANNELBUFFERSIZE,1); + if (!nonblock && + !wait_event_interruptible( + card->wqB, + ring_write_rest(&(card->rbufB)) + > count)){ + out = MargiPushB(card, count, + data); + } else { + out = MargiPushB(card, count, data); + } + } + } + return out; + } else { + MDEBUG(0, + ": Video Decoder Prepare failed: device with this minor number not found\n"); + return -ENODEV; // device with this minor number not found + } +} + +void pes_write(uint8_t *buf, int count, void *priv) +{ + struct cvdv_cards *card = (struct cvdv_cards *) priv; + + margi_write(card, buf, count, 0); +} + + +static ssize_t PSwrite(struct file *file, const char *data, size_t count, + loff_t * offset) +{ + struct cvdv_cards *card = + minorlist[MINOR(file->f_dentry->d_inode->i_rdev) % MAXDEV]; // minor number modulo 16 + return margi_write(card, data, count, file->f_flags&O_NONBLOCK); +} + +static unsigned int PSpoll(struct file *file, poll_table * table) +{ + struct cvdv_cards *card = + minorlist[MINOR(file->f_dentry->d_inode->i_rdev) % MAXDEV]; // minor number modulo 16 + if (card != NULL) { + poll_wait(file, &card->wqA , table); + if ( !card->rbufA.buffy || ring_write_rest(&(card->rbufA)) ) + return (POLLOUT | POLLWRNORM); + else { + return 0; + } + } else + return POLLERR; +} + +static unsigned int poll_audio(struct file *file, poll_table * table) +{ + struct cvdv_cards *card = + minorlist[MINOR(file->f_dentry->d_inode->i_rdev) % MAXDEV]; // minor number modulo 16 + if (card != NULL) { + poll_wait(file, &card->wqB, table); + if ( !card->rbufB.buffy || ring_write_rest(&(card->rbufB)) ) + return (POLLOUT | POLLWRNORM); + else { + return 0; + } + } else + return POLLERR; +} + +static int +OSD_DrawCommand(struct cvdv_cards *card,osd_cmd_t *dc) +{ + + switch (dc->cmd) { + case OSD_Close: + MDEBUG(1,": OSD Close\n"); + return OSDClose(card); + case OSD_Open: // Open(x0,y0,x1,y1,BitPerPixel(2/4/8),mix(0..15)) + return OSDOpen(card, dc->x0, + dc->y0, dc->x1, + dc->y1, + dc->color & 0x0F, + (dc->color >> 4) & + 0x0F); + case OSD_Show: + return OSDShow(card); + case OSD_Hide: + return OSDHide(card); + case OSD_Clear: + return OSDClear(card); + case OSD_Fill: // Fill(color) + return OSDFill(card, dc->color); + case OSD_SetColor: // SetColor(color,R(x0),G(y0),B(x1),opacity(y1)) + return (OSDSetColor + (card, dc->color, dc->x0, + dc->y0, dc->x1, 0, + (dc->y1 != 255), + (dc->y1 == 0)) >= 0); + case OSD_SetPalette:// SetPalette(firstcolor{color},lastcolor{x0},data) + return OSDSetPalette(card, + dc->color, + dc->x0, (uint8_t *) + dc->data); + case OSD_SetTrans: // SetTrans(transparency{color}) + return OSDSetTrans(card, + (dc->color >> 4) + & 0x0F); + case OSD_SetPixel: // SetPixel(x0,y0,color) + return OSDSetPixel(card, dc->x0, + dc->y0, + dc->color); + case OSD_GetPixel: // GetPixel(x0,y0); + return OSDGetPixel(card, dc->x0, + dc->y0); + case OSD_SetRow: // SetRow(x0,y0,x1,(uint8_t*)data) + return OSDSetRow(card, dc->x0, + dc->y0, dc->x1, + (uint8_t *) dc->data); + case OSD_SetBlock: // SetBlock(x0,y0,x1,y1,(uint8_t*)data) + return OSDSetBlock(card, dc->x0, + dc->y0, dc->x1, + dc->y1, + dc->color, + (uint8_t *) + dc->data); + case OSD_FillRow: // FillRow(x0,y0,x1,color) + return OSDFillRow(card, dc->x0, + dc->y0, dc->x1, + dc->color); + case OSD_FillBlock: // FillRow(x0,y0,x1,y1,color) + return OSDFillBlock(card, dc->x0, + dc->y0, dc->x1, + dc->y1, + dc->color); + case OSD_Line: // Line(x0,y0,x1,y1,color); + return OSDLine(card, dc->x0, + dc->y0, dc->x1, + dc->y1, dc->color); + case OSD_Query: // Query(x0,y0,x1,y1,aspect(color:11) + return OSDQuery(card, &dc->x0, + &dc->y0, &dc->x1, + &dc->y1, + &dc->color); + case OSD_Test: + return OSDTest(card); + default: + return -EINVAL; + } +} + + +static int PSioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct cvdv_cards *card = minorlist[MINOR(inode->i_rdev) % MAXDEV]; // minor number modulo 16 + osd_cmd_t *dc; + struct decodercmd *command; + uint16_t attr; + + if (card != NULL) { + if (_IOC_TYPE(cmd) == CVDV_IOCTL_MAGIC) + switch (_IOC_NR(cmd)) { + case IOCTL_DRAW: // Drawing commands + dc = (osd_cmd_t *) arg; + return OSD_DrawCommand(card,dc); + break; + case IOCTL_DECODER: + command = (struct decodercmd *) arg; + switch (command->cmd) { + + case Decoder_CSS: + /* + return DecoderCSS(card, + command->param1, + command->data1); + */ + break; + + case Decoder_Set_Videosystem: + MDEBUG(1,": -- Decoder_Set_Videosystem\n"); + card->videomode = + (videosystem) command->param1; + SetVideoSystem(card); + return 0; + break; + + case Decoder_Set_Streamtype: + MDEBUG(1,": -- Decoder_Set_Streamtype\n"); + card->setup.streamtype = + (stream_type) command->param1; + return 0; + break; + + case Decoder_Set_Audiotype: + MDEBUG(1,": -- Decoder_Set_Audiotype\n"); + card->setup.audioselect = + (audio_type) command->param1; + DecoderPrepareAudio(card); + return 0; + break; + + case Decoder_Set_VideoStreamID: + MDEBUG(1,": -- Decoder_Set_VideoStreamID\n"); + card->setup.videoID = + command->param1; + DecoderPrepareVideo(card); + return 0; + break; + + case Decoder_Set_AudioStreamID: + MDEBUG(1,": -- Decoder_Set_AudioStreamID 0x%02X 0x%02X\n", + command->param1,command->param2); + card->setup.audioID = + command->param1; + card->setup.audioIDext = + command->param2; + attr = card->lastaattr; + DecoderSelectAudioID(card); + card->lastaattr = attr; + return 0; + break; + + case Decoder_Still_Put: + return DecoderShowStill(card, + command-> + param1, + command-> + param2, + command-> + data1, + command-> + data2); + break; + + case Decoder_Still_Get: + return DecoderGetStill(card, + &command-> + param1, + &command-> + param2, + command-> + data1, + command-> + data2); + break; + + case Decoder_Pause: // pause{param1} 0=run 1=pause 2=toggle + if (command->param1 == 2) { + if (card->paused) + DecoderUnPause + (card); + else + DecoderPause(card); + } else { + if (!command->param1) + DecoderUnPause + (card); + else + DecoderPause(card); + } + return 0; + + /* Too buggy + case Decoder_FFWD: // pause{param1} =normal 1=ffwd 2=toggle + if (command->param1 == 2) { + if (card->videoffwd) + card->videoffwd = 0; + else + card->videoffwd = 3; + } else { + if (!command->param1) + card->videoffwd = 0; + else + card->videoffwd = 3; + } + return 0; + + case Decoder_Slow: // pause{param1} =normal 1=slow 2=toggle + if (command->param1 == 2) { + if (card->videoslow) + card->videoslow = 0; + else + card->videoslow = 4; + } else { + if (!command->param1) + card->videoslow = 0; + else + card->videoslow = 4; + } + return 0; + */ + case Decoder_Highlight: // active{param1}, color information(SL_COLI or AC_COLI){data1[4]}, button position(BTN_POSI){data2[6]} + return DecoderHighlight(card, + command-> + param1, + command-> + data1, + command-> + data2); + case Decoder_SPU: // stream{param1}, active{param2} + return DecoderSPUStream(card, + command-> + param1, + command-> + param2); + case Decoder_SPU_Palette: // length{param1}, palette{data1} + return DecoderSPUPalette(card, + command-> + param1, + command-> + data1); + case Decoder_GetNavi: // data1 will be filled with PCI or DSI pack, and 1024 will be returned + return DecoderGetNavi(card, + command-> + data1); + case Decoder_SetKaraoke: // Vocal1{param1}, Vocal2{param2}, Melody{param3} + return DecoderKaraoke(card, + command-> + param1, + command-> + param2, + command-> + param3); + case Decoder_Set_Videoattribute: + MDEBUG(1,": -- Decoder_Set_Videoattribute\n"); + if (!card->ChannelBuffersAllocated) { + DecoderStreamReset(card); + MargiFlush(card); + + card->setup.streamtype = + stream_DVD; + card->setup.videoID = 0; + DecoderPrepareVideo(card); + DecoderPreparePS(card, 0, + 0, 2, 2, + 3, 1); + } + + SetVideoAttr(card, + command->param1); + card->startingDVDV = 1; +// tell the card to start playing as soon as ES-buffers are sufficiently full + return 0; + case Decoder_Set_Audioattribute: + MDEBUG(1,": -- Decoder_Set_Audioattribute\n"); + SetAudioAttr(card, + command->param1); + card->startingDVDA = + ((card->setup.audioselect != + audio_none) + && (card->setup.audioselect != audio_disable)); // tell the card to start playing as soon as ES-buffers are sufficiently full + return 0; + case Decoder_WriteBlock: // DVD-Sector{data1}, sectorsize{param1{2048}}, initialsector{param2{bool}}, set_SCR{param3} + return DecoderWriteBlock(card, + command-> + data1, + command-> + param1, + command-> + param2, + command-> + param3); + default: + return -EINVAL; + } + default: + return -EINVAL; + } else + return -EINVAL; + } else { + MDEBUG(0, + ": Video Decoder Prepare failed: device with this minor number not found\n"); + return -ENODEV; // device with this minor number not found + } +} + + +static int PSmmap(struct file *file, struct vm_area_struct *vm) +{ + return -ENODEV; +} + + + +static int margi_open(struct cvdv_cards *card, int flags) +{ + int closed; + + printk("Open card = %p\n", card); + + if (card != NULL) { + MDEBUG(1, ": -- open \n"); + CloseCard(card); + OSDClose(card); + + printk("Card and OSD closed.\n"); +#ifdef NOINT + card->timer.function = Timerfunction; + card->timer.data=(unsigned long) card; + card->timer.expires=jiffies+1; + add_timer(&card->timer); +#endif + printk("Timer added.\n"); + + if (card->open) + MDEBUG(0,": PSopen - already open\n"); + closed = 1; + if (card->open) + closed = 0; + if (closed) { // first open() for this card? + printk("Freeing buffers.\n"); + MargiFreeBuffers(card); + printk("Fade to black.\n"); + VideoSetBackground(card, 1, 0, 0, 0); // black + } + printk("Go\n"); + card->open++; + return 0; + } else { + MDEBUG(0, + ": Video Decoder Prepare failed: device with this minor number not found\n"); + return -ENODEV; // device with this minor number not found + } + +} + + +static int PSopen(struct inode *inode, struct file *file) +{ + struct cvdv_cards *card = minorlist[MINOR(inode->i_rdev) % MAXDEV]; +#ifdef DVB + if(card) + card->audiostate.AVSyncState=true; +#endif + return margi_open(card, file->f_flags); +} + + +static int all_margi_close(struct cvdv_cards *card) +{ + + if (card != NULL) { + MDEBUG(1, ": -- PSrelease\n"); + if (card->open <= 0) + MDEBUG(1,": PSrelease - not open\n"); + card->open--; + + if (!card->open) { + MDEBUG(1,": PSrelease - last close\n"); + CloseCard(card); // close immediately + } + return 0; + } else { + MDEBUG(0,": Video Decoder Prepare failed:\n"); + return -ENODEV; // device with this minor number not found + } + +} + +static int PSrelease(struct inode *inode, struct file *file) +{ + struct cvdv_cards *card = minorlist[MINOR(inode->i_rdev) % MAXDEV]; // minor number modulo 16 + return all_margi_close(card); +} + + ////////////////////////// + // // + // Char Device Hookup // + // // +////////////////////////// + +// Hookups for a write-only device, that accepts MPEG-2 Program Stream +struct file_operations cvdv_fileops = { + owner: THIS_MODULE, + write: PSwrite, + poll: PSpoll, + ioctl: PSioctl, + mmap: PSmmap, + open: PSopen, + release: PSrelease, +}; + + +#ifdef DVB + +static inline int +num2type(struct cvdv_cards *card, int num) +{ + if (!card->dvb_devs) + return -2; + if (num>=card->dvb_devs->num) + return -2; + return card->dvb_devs->tab[num]; +} + +static int +dvbdev_open(struct dvb_device *dvbdev, int num, + struct inode *inode, struct file *file) +{ + struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv; + int type=num2type(card, num); + int ret=0; + + if (type<0) + return -EINVAL; + + if (card->users[num] >= card->dvb_devs->max_users[num]) + return -EBUSY; + + if ((file->f_flags&O_ACCMODE)!=O_RDONLY) + if (card->writers[num] >= card->dvb_devs->max_writers[num]) + return -EBUSY; + + switch (type) { + case DVB_DEVICE_VIDEO_0: + card->video_blank=true; + card->audiostate.AVSyncState=true; + card->videostate.streamSource=VIDEO_SOURCE_DEMUX; + margi_open(card, file->f_flags); + break; + + case DVB_DEVICE_AUDIO_0: + card->audiostate.AVSyncState=true; + card->audiostate.streamSource=AUDIO_SOURCE_DEMUX; + break; + + case DVB_DEVICE_DEMUX_0: + if ((file->f_flags&O_ACCMODE)!=O_RDWR) + return -EINVAL; + ret=DmxDevFilterAlloc(&card->dmxdev, file); + break; + + case DVB_DEVICE_DVR_0: + card->audiostate.AVSyncState=true; + card->setup.streamtype = stream_PES; + margi_open(card, file->f_flags); + ret=DmxDevDVROpen(&card->dmxdev, file); + break; + + case DVB_DEVICE_OSD_0: + break; + default: + return -EINVAL; + } + if (ret<0) + return ret; + if ((file->f_flags&O_ACCMODE)!=O_RDONLY) + card->writers[num]++; + card->users[num]++; + return ret; +} + +static int +dvbdev_close(struct dvb_device *dvbdev, int num, + struct inode *inode, struct file *file) +{ + struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv; + int type=num2type(card, num); + int ret=0; + + if (type<0) + return -EINVAL; + + switch (type) { + case DVB_DEVICE_VIDEO_0: + case DVB_DEVICE_AUDIO_0: + if (card->open) + all_margi_close(card); + break; + + case DVB_DEVICE_DEMUX_0: + ret=DmxDevFilterFree(&card->dmxdev, file); + break; + + case DVB_DEVICE_DVR_0: + ret=DmxDevDVRClose(&card->dmxdev, file); + if (card->open) + all_margi_close(card); + break; + case DVB_DEVICE_OSD_0: + break; + default: + return -EINVAL; + } + if (ret<0) + return ret; + if ((file->f_flags&O_ACCMODE)!=O_RDONLY) + card->writers[num]--; + card->users[num]--; + return ret; +} + + +static ssize_t +dvbdev_write(struct dvb_device *dvbdev, int num, + struct file *file, + const char *buf, size_t count, loff_t *ppos) +{ + struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv; + int type=num2type(card, num); + + switch (type) { + case DVB_DEVICE_VIDEO_0: + if (card->videostate.streamSource!=VIDEO_SOURCE_MEMORY) + return -EPERM; + return margi_write(card, buf, count, + file->f_flags&O_NONBLOCK); + + case DVB_DEVICE_AUDIO_0: + if (card->audiostate.streamSource!=AUDIO_SOURCE_MEMORY) + return -EPERM; + if ( card->setup.streamtype != stream_PES ) + return -EPERM; + + return margi_write_audio(card, buf, count, + file->f_flags&O_NONBLOCK); + + case DVB_DEVICE_DVR_0: + return DmxDevDVRWrite(&card->dmxdev, file, buf, count, ppos); + default: + return -EOPNOTSUPP; + } + return 0; +} + +static ssize_t +dvbdev_read(struct dvb_device *dvbdev, int num, + struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv; + int type=num2type(card, num); + + switch (type) { + case DVB_DEVICE_VIDEO_0: + break; + case DVB_DEVICE_AUDIO_0: + break; + case DVB_DEVICE_DEMUX_0: + return DmxDevRead(&card->dmxdev, file, buf, count, ppos); + case DVB_DEVICE_DVR_0: + return DmxDevDVRRead(&card->dmxdev, file, buf, count, ppos); + case DVB_DEVICE_CA_0: + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + + + + +static int +dvbdev_ioctl(struct dvb_device *dvbdev, int num, + struct file *file, unsigned int cmd, unsigned long arg) +{ + struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv; + void *parg=(void *)arg; + int type=num2type(card, num); + uint16_t attr; + + switch (type) { + case DVB_DEVICE_VIDEO_0: + if (((file->f_flags&O_ACCMODE)==O_RDONLY) && + (cmd!=VIDEO_GET_STATUS)) + return -EPERM; + + switch (cmd) { + + case VIDEO_STOP: + DecoderPause(card); + card->videostate.playState = VIDEO_STOPPED; + if (card->videostate.videoBlank) + VideoSetBackground(card, 1, 0, 0, 0); + + + return 0; + + case VIDEO_PLAY: + + if (card->videostate.streamSource== + VIDEO_SOURCE_MEMORY) { + if (card->videostate.playState==VIDEO_FREEZED){ + DecoderUnPause(card); + } else { + DecoderUnPause(card); + } + } + break; + + case VIDEO_FREEZE: + DecoderPause(card); + break; + + case VIDEO_CONTINUE: + if (card->videostate.playState==VIDEO_FREEZED) { + DecoderUnPause(card); + } + break; + + case VIDEO_SELECT_SOURCE: + card->videostate.streamSource=(videoStreamSource_t) arg; + break; + + case VIDEO_SET_BLANK: + card->videostate.videoBlank=(boolean) arg; + break; + + case VIDEO_GET_STATUS: + if(copy_to_user(parg, &card->videostate, + sizeof(struct videoStatus))) + return -EFAULT; + break; + + case VIDEO_GET_EVENT: + return -EOPNOTSUPP; + + case VIDEO_SET_DISPLAY_FORMAT: + { + videoDisplayFormat_t format=(videoDisplayFormat_t) arg; + uint16_t val=0; + + switch(format) { + case VIDEO_PAN_SCAN: + val=VID_PAN_SCAN_PREF; + break; + + case VIDEO_LETTER_BOX: + val=VID_VC_AND_PS_PREF; + break; + + case VIDEO_CENTER_CUT_OUT: + val=VID_CENTRE_CUT_PREF; + break; + + default: + return -EINVAL; + } + + card->videostate.videoFormat=format; + return 0; + } + + case VIDEO_STILLPICTURE: + { + struct videoDisplayStillPicture pic; + + if(copy_from_user(&pic, parg, + sizeof(struct videoDisplayStillPicture))) + return -EFAULT; + + break; + } + + case VIDEO_FAST_FORWARD: + if (card->videostate.streamSource != + VIDEO_SOURCE_MEMORY) + return -EPERM; + card->videoffwd = 3; + break; + + case VIDEO_SLOWMOTION: + if (card->videostate.streamSource!=VIDEO_SOURCE_MEMORY) + return -EPERM; + card->videoslow = arg; + + break; + + case VIDEO_GET_CAPABILITIES: + { + int cap=VIDEO_CAP_MPEG1| + VIDEO_CAP_MPEG2| + VIDEO_CAP_SYS| + VIDEO_CAP_PROG| + VIDEO_CAP_SPU| + VIDEO_CAP_NAVI| + VIDEO_CAP_CSS; + + + if (copy_to_user(parg, &cap, + sizeof(cap))) + return -EFAULT; + break; + } + + case VIDEO_SET_STREAMTYPE: + { + int f = -1; + switch(arg){ + case VIDEO_CAP_MPEG1: + case VIDEO_CAP_MPEG2: + f = stream_PES; + break; + + case VIDEO_CAP_SYS: + case VIDEO_CAP_PROG: + f = stream_PS; + break; + + case VIDEO_CAP_SPU: + case VIDEO_CAP_NAVI: + case VIDEO_CAP_CSS: + f = stream_DVD; + } + card->setup.streamtype = f; + + } + break; + + case VIDEO_SET_ID: + card->setup.videoID = arg; + DecoderPrepareVideo(card); + break; + + case VIDEO_SET_SYSTEM: + card->videomode = (videosystem) arg; + SetVideoSystem(card); + break; + + case VIDEO_SET_HIGHLIGHT: + { + uint8_t data1[4]; + uint8_t data2[6]; + videoHighlight_t vh; + + if(copy_from_user(&vh, parg, sizeof(videoHighlight_t))) + return -EFAULT; + + data1[0] = vh.contrast1; + data1[1] = vh.contrast2; + data1[2] = vh.color1; + data1[3] = vh.color2; + data2[0] = vh.ypos & 0xFF; + data2[1] = (uint8_t) ((vh.ypos >> 1) & 0xFF); + data2[2] = (uint8_t) ((vh.ypos >> 2) & 0xFF); + data2[3] = vh.xpos & 0xFF; + data2[4] = (uint8_t) ((vh.xpos >> 1) & 0xFF); + data2[5] = (uint8_t) ((vh.xpos >> 2) & 0xFF); + return DecoderHighlight(card, vh.active, data1, data2); + break; + } + + case VIDEO_SET_SPU: + { + videoSPU_t spu; + + if(copy_from_user(&spu, parg, sizeof(videoSPU_t))) + return -EFAULT; + + return DecoderSPUStream(card, spu.streamID, spu.active); + break; + } + + case VIDEO_SET_SPU_PALETTE: + { + videoSPUPalette_t spup; + + if(copy_from_user(&spup, parg, sizeof(videoSPUPalette_t))) + return -EFAULT; + + return DecoderSPUPalette(card, spup.length, spup.palette); + break; + } + + case VIDEO_GET_NAVI: + { + videoNaviPack_t navi; + + navi.length = DecoderGetNavi(card, (u8 *)&(navi.data)); + if(copy_to_user(parg, &navi, sizeof(videoNaviPack_t))) + return -EFAULT; + } + break; + + case VIDEO_SET_ATTRIBUTES: + { + if (!card->ChannelBuffersAllocated) { + DecoderStreamReset(card); + MargiFlush(card); + + card->setup.streamtype = stream_DVD; + card->setup.videoID = 0; + DecoderPrepareVideo(card); + DecoderPreparePS(card, 0, 0, 2, 2, 3, 1); + } + + SetVideoAttr(card, arg); + card->startingDVDV = 1; + } + break; + + default: + return -ENOIOCTLCMD; + } + return 0; + + case DVB_DEVICE_AUDIO_0: + if (((file->f_flags&O_ACCMODE)==O_RDONLY) && + (cmd!=AUDIO_GET_STATUS)) + return -EPERM; + + switch (cmd) { + + case AUDIO_STOP: + if (card->audiostate.streamSource!=AUDIO_SOURCE_MEMORY) + break; + AudioStopDecode(card); + card->audiostate.playState=AUDIO_STOPPED; + break; + + case AUDIO_PLAY: + if (card->audiostate.streamSource!=AUDIO_SOURCE_MEMORY) + break; + AudioSetPlayMode(card, MAUDIO_PLAY); + card->audiostate.playState=AUDIO_PLAYING; + break; + + case AUDIO_PAUSE: + card->audiostate.playState=AUDIO_PAUSED; + AudioSetPlayMode(card, MAUDIO_PAUSE); + break; + + case AUDIO_CONTINUE: + if (card->audiostate.playState==AUDIO_PAUSED) { + card->audiostate.playState=AUDIO_PLAYING; + AudioSetPlayMode(card, MAUDIO_PLAY); + } + break; + + case AUDIO_SELECT_SOURCE: + card->audiostate.streamSource= + (audioStreamSource_t) arg; + break; + + case AUDIO_SET_MUTE: + { + AudioMute(card, arg); + card->audiostate.muteState=(boolean) arg; + break; + } + + case AUDIO_SET_AV_SYNC: + card->videosync=(boolean) arg; + card->audiostate.AVSyncState=(boolean) arg; + break; + + case AUDIO_SET_BYPASS_MODE: + return -EINVAL; + + case AUDIO_CHANNEL_SELECT: + card->audiostate.channelSelect=(audioChannelSelect_t) arg; + + switch(card->audiostate.channelSelect) { + case AUDIO_STEREO: + break; + + case AUDIO_MONO_LEFT: + break; + + case AUDIO_MONO_RIGHT: + break; + + default: + return -EINVAL; + } + return 0; + + case AUDIO_GET_STATUS: + if(copy_to_user(parg, &card->audiostate, + sizeof(struct audioStatus))) + return -EFAULT; + break; + + case AUDIO_GET_CAPABILITIES: + { + int cap=AUDIO_CAP_LPCM| + AUDIO_CAP_MP1| + AUDIO_CAP_MP2| + AUDIO_CAP_AC3; + + if (copy_to_user(parg, &cap, + sizeof(cap))) + return -EFAULT; + } + break; + + + case AUDIO_SET_STREAMTYPE: + { + int f = -1; + + switch(arg){ + case AUDIO_CAP_DTS: + case AUDIO_CAP_MP3: + case AUDIO_CAP_AAC: + case AUDIO_CAP_SDDS: + case AUDIO_CAP_OGG: + f = audio_none; + break; + + case AUDIO_CAP_LPCM: + f = audio_LPCM; + break; + + case AUDIO_CAP_MP1: + case AUDIO_CAP_MP2: + f = audio_MPEG; + break; + + case AUDIO_CAP_AC3: + f = audio_AC3; + break; + } + + card->setup.audioselect = (audio_type) f; + DecoderPrepareAudio(card); + break; + } + + case AUDIO_SET_ID: + if (arg < 0 || arg >32) arg = 0; + card->setup.audioID = arg; + arg = 0; + case AUDIO_SET_EXT_ID: + if (arg < 0 || arg >32) arg = 0; + card->setup.audioIDext = arg; + + attr = card->lastaattr; + DecoderSelectAudioID(card); + card->lastaattr = attr; + break; + + case AUDIO_SET_MIXER: + return -EINVAL; + + case AUDIO_SET_ATTRIBUTES: + SetAudioAttr(card,arg); + card->startingDVDA = ((card->setup.audioselect != audio_none) + && (card->setup.audioselect != + audio_disable)); + break; + + + case AUDIO_SET_KARAOKE: + { + break; + } + + default: + return -ENOIOCTLCMD; + } + break; + + case DVB_DEVICE_DEMUX_0: + return DmxDevIoctl(&card->dmxdev, file, cmd, arg); + break; + + case DVB_DEVICE_OSD_0: + { + switch (cmd) { + case OSD_SEND_CMD: + { + osd_cmd_t doc; + + if(copy_from_user(&doc, parg, + sizeof(osd_cmd_t))) + return -EFAULT; + return OSD_DrawCommand(card, &doc); + } + default: + return -EINVAL; + } + break; + } + default: + return -EOPNOTSUPP; + } + return 0; +} + +static unsigned int +dvbdev_poll(struct dvb_device *dvbdev, int num, + struct file *file, poll_table * wait) +{ + struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv; + int type=num2type(card, num); + + switch (type) { + case DVB_DEVICE_DEMUX_0: + return DmxDevPoll(&card->dmxdev, file, wait); + + case DVB_DEVICE_VIDEO_0: + return PSpoll(file, wait); + + case DVB_DEVICE_AUDIO_0: + return poll_audio(file, wait); + + case DVB_DEVICE_CA_0: + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + + +static int +dvbdev_device_type(struct dvb_device *dvbdev, unsigned int num) +{ + struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv; + + return num2type(card, num); +} +#endif + +/****************************************************************************** + * driver registration + ******************************************************************************/ + + +#ifdef DVB + +#define INFU 32768 + + + +static dvb_devs_t mdvb_devs = { + 9, + { + DVB_DEVICE_VIDEO_0, DVB_DEVICE_AUDIO_0, + -1, -1, + DVB_DEVICE_DEMUX_0, DVB_DEVICE_DVR_0, + -1, -1, + DVB_DEVICE_OSD_0, + }, + { INFU, INFU, INFU, INFU, INFU, 1, 1, INFU, 1 }, + { 1, 1, 1, 1, INFU, 1, 1, 1, 1} +}; + + +static int +dvb_start_feed(dvb_demux_feed_t *dvbdmxfeed) +{ + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct cvdv_cards * card = (struct cvdv_cards *)dvbdmx->priv; + + if (!dvbdmx->dmx.frontend || !card) + return -EINVAL; + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + if ((dvbdmxfeed->ts_type & TS_DECODER) + && (dvbdmxfeed->pes_typedmx.frontend->source) { + case DMX_MEMORY_FE: + if (dvbdmxfeed->ts_type & TS_DECODER) + if (dvbdmxfeed->pes_type<2 && + dvbdmx->pids[0]!=0xffff && + dvbdmx->pids[1]!=0xffff) { + + setup_ts2pes( &card->tsa, + &card->tsv, + dvbdmx->pids, + dvbdmx->pids+1, + pes_write, + (void *)card); + + dvbdmx->playing=1; + } + break; + default: + return -EINVAL; + break; + } + } + } + + if (dvbdmxfeed->type == DMX_TYPE_SEC) { + int i; + + for (i=0; ifilternum; i++) { + if (dvbdmx->filter[i].state!=DMX_STATE_READY) + continue; + if (dvbdmx->filter[i].type!=DMX_TYPE_SEC) + continue; + if (dvbdmx->filter[i].filter.parent!= + &dvbdmxfeed->feed.sec) + continue; + + dvbdmxfeed->feed.sec.is_filtering=1; + dvbdmx->filter[i].state=DMX_STATE_GO; + } + } + + return 0; +} + + +static int +dvb_stop_feed(dvb_demux_feed_t *dvbdmxfeed) +{ + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct cvdv_cards * card = (struct cvdv_cards *)dvbdmx->priv; + if (!card) + return -EINVAL; + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + if ((dvbdmxfeed->ts_type & TS_DECODER) + && (dvbdmxfeed->pes_type<=1)) { + if (dvbdmx->playing) { + free_ipack(&card->tsa); + free_ipack(&card->tsv); + DecoderPause(card); + dvbdmx->playing=0; + } + } + + } + if (dvbdmxfeed->type == DMX_TYPE_SEC) { + int i; + + for (i=0; ifilternum; i++) + if (dvbdmx->filter[i].state==DMX_STATE_GO && + dvbdmx->filter[i].filter.parent== + &dvbdmxfeed->feed.sec) { + dvbdmx->filter[i].state=DMX_STATE_READY; + } + + } + return 0; +} + +static uint16_t get_pid(uint8_t *pid) +{ + uint16_t pp = 0; + + pp = (pid[0] & PID_MASK_HI)<<8; + pp |= pid[1]; + + return pp; +} + + +static int +dvb_write_to_decoder(dvb_demux_feed_t *dvbdmxfeed, uint8_t *buf, size_t count) +{ + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct cvdv_cards * card = (struct cvdv_cards *)dvbdmx->priv; + uint16_t pid = 0; + int off = 0; + + ipack *p; + + if (!card) + return -EINVAL; + + pid = get_pid(buf+1); + + if (pid == *(card->tsa.pid)) p = &(card->tsa); + else if (pid == *(card->tsv.pid)) p = &(card->tsv); + else return 0; + + if (dvbdmxfeed->pes_type>1) + return -1; + if (!(buf[3]&0x10)) // no payload? + return -1; + + if (count != TS_SIZE) return -1; + + if ( buf[3] & ADAPT_FIELD) { // adaptation field? + off = buf[4] + 1; + } + + + if (pid == *(card->tsa.pid)){ + MDEBUG(0,"AUDIO count: %d off: %d\n",count,off); + margi_write_audio(card, buf+off+4, TS_SIZE-4-off, 0); + } else { + MDEBUG(0,"VIDEO count: %d off: %d\n",count,off); + margi_write(card, buf+off+4, TS_SIZE-4-off, 0); + } + +// ts_to_pes( p, buf); // don't need count (=188) + return 0; +} + +int dvb_register(struct cvdv_cards *card) +{ + int i,ret; + struct dvb_device *dvbd=&card->dvb_dev; + + dvb_demux_t *dvbdemux = (dvb_demux_t *)&card->demux; + + if (card->dvb_registered) + return -1; + card->dvb_registered=1; + + card->audiostate.AVSyncState=0; + card->audiostate.muteState=0; + card->audiostate.playState=AUDIO_STOPPED; + card->audiostate.streamSource=AUDIO_SOURCE_MEMORY; + card->audiostate.channelSelect=AUDIO_STEREO; + card->audiostate.bypassMode=0; + + card->videostate.videoBlank=0; + card->videostate.playState=VIDEO_STOPPED; + card->videostate.streamSource=VIDEO_SOURCE_MEMORY; + card->videostate.videoFormat=VIDEO_FORMAT_4_3; + card->videostate.displayFormat=VIDEO_CENTER_CUT_OUT; + + // init and register demuxes + memcpy(card->demux_id, "demux0_0", 9); + card->demux_id[7] = 1+0x30; + dvbdemux->priv = (void *) card; + dvbdemux->filternum = 32; + dvbdemux->feednum = 32; + dvbdemux->start_feed = dvb_start_feed; + dvbdemux->stop_feed = dvb_stop_feed; + dvbdemux->write_to_decoder = dvb_write_to_decoder; + + dvbdemux->dmx.vendor="CIM"; + dvbdemux->dmx.model="sw"; + dvbdemux->dmx.id=card->demux_id; + dvbdemux->dmx.capabilities=(DMX_TS_FILTERING| + DMX_SECTION_FILTERING| + DMX_MEMORY_BASED_FILTERING); + + DvbDmxInit(&card->demux); + + card->dmxdev.filternum=32; + card->dmxdev.demux=&dvbdemux->dmx; + card->dmxdev.capabilities=0; + + DmxDevInit(&card->dmxdev); + + card->mem_frontend.id="mem_frontend"; + card->mem_frontend.vendor="memory"; + card->mem_frontend.model="sw"; + card->mem_frontend.source=DMX_MEMORY_FE; + ret=dvbdemux->dmx.add_frontend(&dvbdemux->dmx, + &card->mem_frontend); + if (ret<0) + return ret; + ret=dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, + &card->mem_frontend); + if (ret<0) + return ret; + + // init and register dvb device structure + dvbd->priv=(void *) card; + dvbd->open=dvbdev_open; + dvbd->close=dvbdev_close; + dvbd->write=dvbdev_write; + dvbd->read=dvbdev_read; + dvbd->ioctl=dvbdev_ioctl; + dvbd->poll=dvbdev_poll; + dvbd->device_type=dvbdev_device_type; + + for (i=0; iusers[i]=card->writers[i]=0; + + card->dvb_devs=0; + card->dvb_devs=&mdvb_devs; + + return dvb_register_device(dvbd); +} + +void dvb_unregister(struct cvdv_cards *card) +{ + dvb_demux_t *dvbdemux=&card->demux; + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &card->mem_frontend); + DmxDevRelease(&card->dmxdev); + DvbDmxRelease(&card->demux); + dvb_unregister_device(&card->dvb_dev); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/cvdvext.h linux.20pre2-ac1/drivers/media/video/margi/cvdvext.h --- linux.20pre2/drivers/media/video/margi/cvdvext.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/cvdvext.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,30 @@ +/* + cvdvtypes.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _CVDVEXT_H_ +#define _CVDVEXT_H_ + +#include +#include "cvdvtypes.h" + +#define OSD_Draw(file,cmd) ioctl(fileno(file),_IO(CVDV_IOCTL_MAGIC,IOCTL_DRAW),&cmd) +#define DecoderCommand(file,cmd) ioctl(fileno(file),_IO(CVDV_IOCTL_MAGIC,IOCTL_DECODER),&cmd) + +#endif // _CVDVEXT_H_ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/cvdv.h linux.20pre2-ac1/drivers/media/video/margi/cvdv.h --- linux.20pre2/drivers/media/video/margi/cvdv.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/cvdv.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,58 @@ +/* + cvdv.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _CVDV_H_ +#define _CVDV_H_ + + ////////////////////////////////////////////////////////// + // // + // Convergence Digital Video Decoder Card // + // Definitions for the PCI-Card and the Char-Driver // + // // +////////////////////////////////////////////////////////// + + +#include "cardbase.h" +#include "dram.h" +#include "osd.h" +#include "crc.h" +#include "l64021.h" +#include "audio.h" +#include "video.h" +#include "streams.h" +#include "decoder.h" +#include "spu.h" + +void SetVideoSystem(struct cvdv_cards *card); +u16 rnd(u16 range); +// debugging of the card: 0=normal, 1=color bars, 2=sync out +#define USE_DEBUG 0 + +#define cimlogo_width 45 +#define cimlogo_height 38 + +#define CHANNELBUFFERSIZE 32768*8 + +int Prepare(struct cvdv_cards *card); +int OSDTest(struct cvdv_cards *card); +void v4l_init(struct cvdv_cards *card); +int dvb_register(struct cvdv_cards *card); +void dvb_unregister(struct cvdv_cards *card); +#endif // _CVDV_H_ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/cvdvtypes.h linux.20pre2-ac1/drivers/media/video/margi/cvdvtypes.h --- linux.20pre2/drivers/media/video/margi/cvdvtypes.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/cvdvtypes.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,281 @@ +/* + cvdvtypes.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + ///////////////////////////////////////////////// + // // + // Convergence Digital Video Decoder Card // + // External Definitions for the Char-Driver // + // Copyright (c) 1999 Christian Wolff / // + // convergence integrated media GmbH Berlin // + // // +///////////////////////////////////////////////// + +// As of 1999-11-09 + +#ifndef _CVDVTYPE_H_ +#define _CVDVTYPE_H_ + +// our ioctl number: _IOC_TYPE() is 0xA2 (162) and the range of _IOC_NR() is 0x00 to 0x0F. +// submitted 99/10/15 to mec@shout.net +#define CVDV_IOCTL_MAGIC 0xA2 + +// command numbers _IOC_NR() for ioctl +typedef enum { + IOCTL_DRAW = 0x01, + IOCTL_DECODER = 0x02 +} IOCTL_Command; + + +// supported Videosystems +// everything but PAL and NTSC is untested and probably won't work. +typedef enum { + NTSC = 1, // NTSC 29.97 fps + NTSC60, // NTSC 30 fps + PAL, // PAL-B, D, G, H, I, 25 fps + PALM, // PAL-M 29.97 fps + PALM60, // PAL-M 30 fps + PALN, // PAL-N 25 fps + PALNc, // PAL-Nc 25 fps + PAL60 // PAL 30 fps (doesn't work, yet...) +} videosystem; + +typedef enum { + stream_none = 0, // unknown + stream_ES, + stream_PES, + stream_PS, + stream_DVD +} stream_type; + +typedef enum { + audio_disable = -1, + audio_none = 0, // unknown + audio_MPEG, + audio_MPEG_EXT, + audio_LPCM, + audio_AC3, + audio_DTS, + audio_SDDS +} audio_type; + +#if 0 +typedef enum { + // All functions return -2 on "not open" + OSD_Close = 1, // () + // Disables OSD and releases the buffers + // returns 0 on success + OSD_Open, // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) + // Opens OSD with this size and bit depth + // returns 0 on success, -1 on DRAM allocation error, -2 on "already open" + OSD_Show, // () + // enables OSD mode + // returns 0 on success + OSD_Hide, // () + // disables OSD mode + // returns 0 on success + OSD_Clear, // () + // Sets all pixel to color 0 + // returns 0 on success + OSD_Fill, // (color) + // Sets all pixel to color + // returns 0 on success + OSD_SetColor, // (color,R{x0},G{y0},B{x1},opacity{y1}) + // set palette entry to , and apply + // R,G,B: 0..255 + // R=Red, G=Green, B=Blue + // opacity=0: pixel opacity 0% (only video pixel shows) + // opacity=1..254: pixel opacity as specified in header + // opacity=255: pixel opacity 100% (only OSD pixel shows) + // returns 0 on success, -1 on error + OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data) + // Set a number of entries in the palette + // sets the entries "firstcolor" through "lastcolor" from the array "data" + // data has 4 byte for each color: + // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel + OSD_SetTrans, // (transparency{color}) + // Sets transparency of mixed pixel (0..15) + // returns 0 on success + OSD_SetPixel, // (x0,y0,color) + // sets pixel , to color number + // returns 0 on success, -1 on error + OSD_GetPixel, // (x0,y0) + // returns color number of pixel ,, or -1 + OSD_SetRow, // (x0,y0,x1,data) + // fills pixels x0,y through x1,y with the content of data[] + // returns 0 on success, -1 on clipping all pixel (no pixel drawn) + OSD_SetBlock, // (x0,y0,x1,y1,increment{color},data) + // fills pixels x0,y0 through x1,y1 with the content of data[] + // inc contains the width of one line in the data block, + // inc<=0 uses blockwidth as linewidth + // returns 0 on success, -1 on clipping all pixel + OSD_FillRow, // (x0,y0,x1,color) + // fills pixels x0,y through x1,y with the color + // returns 0 on success, -1 on clipping all pixel + OSD_FillBlock, // (x0,y0,x1,y1,color) + // fills pixels x0,y0 through x1,y1 with the color + // returns 0 on success, -1 on clipping all pixel + OSD_Line, // (x0,y0,x1,y1,color) + // draw a line from x0,y0 to x1,y1 with the color + // returns 0 on success + OSD_Query, // (x0,y0,x1,y1,xasp{color}}), yasp=11 + // fills parameters with the picture dimensions and the pixel aspect ratio + // returns 0 on success + OSD_Test // () + // draws a test picture. for debugging purposes only + // returns 0 on success +// TODO: remove "test" in final version +} OSD_Command; + +struct drawcmd { + OSD_Command cmd; + int x0; + int y0; + int x1; + int y1; + int color; + void *data; +}; +#endif + +typedef enum { + Decoder_Pause, // pause{param1} 0=run 1=pause 2=toggle + Decoder_Still_Put, // (width{param1}, height{param2}, luma{data1}, chroma{data2}) + // show still picture of specified size + // width; width of the image + // height; height of the image + // luma; Y values, one byte per pixel, width*height bytes + // chroma; 4:2:0 U and V values, interlaced, one byte each U, one byte each V, width*height/2 bytes + Decoder_Still_Get, // (width{param1}, height{param2}, luma{data1}, chroma{data2}) + // grab current showing image + // width and height will be set to current picture size + // if luma and croma are NULL, only width and height will be reported + // otherwise the pixel data is filled in there, same format as Still_put + Decoder_Set_Videosystem, // (videosystem{param1}) + // videosystem: see enum {} videosystem; + Decoder_Set_Streamtype, // (streamtype{param1}) + // streamtype: according to enum {} stream_type; + // This has to be set BEFORE you send data to the device + // For ES and PES streams, Audio has to go into the first device (e.g.minor 0) and video into the second (e.g.minor 16) + Decoder_Set_Audiotype, // (audiotype{param1}) + // audiotype: see enum {} audio_type, +16 for IEC956 on S/PDIF out + Decoder_Set_VideoStreamID, // (video stream ID {param1}) + // video stream ID: MPEG ID 0..15 of video stream to display (E0..EF), -1 for any/auto + Decoder_Set_AudioStreamID, // (audio stream ID {param1}, audio extension stream ID {param2}) + // audio stream ID: MPEG ID 0..31 of audio stream to display (C0..DF), -1 for any/auto + // audio extension stream ID: MPEG ID 0..31 of audio extension stream (C0..DF), -1 for none + Decoder_CSS, // Passes CSS information to and from the decoder + // action{param1}, + // data block{data1} MSB first + // execute 1 to 4 once for each disc, then 5 to 8 for each title + // returns 0 on success, <0 on error + // -1: timeout reading data from card + // -2: data pointer not initialized + // -3: invalid action number + // action=0 -> disable and bypass CSS + // Disk key: + // action=1 -> retreive drive challenge (10 byte) from card + // action=2 -> post drive response (5 byte) to card + // action=3 -> post card challenge (10 byte) and retreive card response (5 byte) + // action=4 -> post disk key (2048 byte) into the card + // Title key: + // action=5 -> retreive title challenge (10 byte) from card + // action=6 -> post title response (5 byte) to card + // action=7 -> post card challenge (10 byte) and retreive card response (5 byte) + // action=8 -> post encrypted title key (5 byte) into the card + Decoder_Highlight, // post SPU Highlight information, + // active{param1} + // 1=show highlight, 0=hide highlight + // color information(SL_COLI or AC_COLI){data1[4]} MSB first + // bits: descr. + // 31-28 Emphasis pixel-2 color + // 27-24 Emphasis pixel-1 color + // 23-20 Pattern pixel color + // 19-16 Background pixel color + // 15-12 Emphasis pixel-2 contrast + // 11- 8 Emphasis pixel-1 contrast + // 7- 4 Pattern pixel contrast + // 3- 0 Background pixel contrast + // button position(BTN_POSI){data2[6]} MSB first + // bits: descr. + // 47-46 button color number + // 45-36 start x + // 33-24 end x + // 23-22 auto action mode + // 21-12 start y + // 9- 0 end y + Decoder_SPU, // Activate SPU decoding and select SPU stream ID + // stream{param1} + // active{param2} + Decoder_SPU_Palette, // post SPU Palette information + // length{param1} + // palette{data1} + Decoder_GetNavi, // Retreives CSS-decrypted navigational information from the stream. + // data1 will be filled with PCI or DSI pack (private stream 2 stream_id), + // and the length of data1 (1024 or 0) will be returned + Decoder_SetKaraoke, // Vocal1{param1}, Vocal2{param2}, Melody{param3} + // if Vocal1 or Vocal2 are non-zero, they get mixed into left and right at 70% each + // if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets mixed into the left channel and + // Vocal2 into the right channel at 100% each. + // if Melody is non-zero, the melody channel gets mixed into left and right + Decoder_Set_Videoattribute, // Set the video parameters + // attribute{param1} (2 byte V_ATR) + // bits: descr. + // 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) + // 13-12 TV system (0=525/60, 1=625/50) + // 11-10 Aspect ratio (0=4:3, 3=16:9) + // 9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-scan, 2=only letterbox) + // 7 line 21-1 data present in GOP (1=yes, 0=no) + // 6 line 21-2 data present in GOP (1=yes, 0=no) + // 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/576, 3=352x240/288) + // 2 source letterboxed (1=yes, 0=no) + // 0 film/camera mode (0=camera, 1=film (625/50 only)) + Decoder_Set_Audioattribute, // Set the audio parameters + // attribute{param1} (2 most significan bytes of A_ATR (bit 63 through 48)) + // bits: descr. + // 15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, 7=SDDS) + // 12 multichannel extension + // 11-10 audio type (0=not spec, 1=language included) + // 9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) + // 7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit, 1=20bit, 2=24bit) + // 5- 4 Sample frequency fs (0=48kHz, 1=96kHz) + // 2- 0 number of audio channels (n+1 channels) + Decoder_WriteBlock, // Post one block of data, e.g. one DVD sector of 2048 byte, into the decoder queue + // sectordata{data1} + // length{param1} + // is_initial_block{param2} + // set_SCR{param3} + /* + Decoder_FFWD, // ffwd{param1} 0=normal 1=ffwd 2=toggle + Decoder_Slow // slow{param1} 0=normal 1=slow 2=toggle + */ +} Decoder_Command; + +struct decodercmd { + Decoder_Command cmd; + int param1; + int param2; + int param3; + int param4; + int param5; + void *data1; + void *data2; +}; + +#endif // _CVDVTYPE_H_ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/decoder.c linux.20pre2-ac1/drivers/media/video/margi/decoder.c --- linux.20pre2/drivers/media/video/margi/decoder.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/decoder.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1536 @@ +/* + decoder.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define __NO_VERSION__ + +#include "decoder.h" +#include "l64021.h" +#include "video.h" +#include "audio.h" +#include "streams.h" +#include "osd.h" +#include "dram.h" +#include "cvdv.h" + +int DecoderGetNavi(struct cvdv_cards *card, u8 *navidata) +{ + if (card->navihead == card->navitail) return 0; + MDEBUG(3, ": Retreiving NaviPack\n"); + memcpy(navidata, &card->navibuffer[card->navitail], NAVISIZE); + card->navitail += NAVISIZE; + if (card->navitail >= NAVIBUFFERSIZE) card->navitail = 0; + return NAVISIZE; +} + +// returns 1 on overrun, 0 on no error +int DecoderQueueNavi(struct cvdv_cards *card, u8 *navidata) +{ + memcpy(&card->navibuffer[card->navihead], navidata, NAVISIZE); + card->navihead += NAVISIZE; + if (card->navihead >= NAVIBUFFERSIZE) card->navihead = 0; + if (card->navihead == card->navitail) { + MDEBUG(3, ": NaviPack buffer overflow\n"); + card->navitail += NAVISIZE; + if (card->navitail >= NAVIBUFFERSIZE) card->navitail = 0; + return 1; + } + return 0; +} + +u32 ParseSCR(const u8 *data) +{ + u32 SCR_base=0; + u8 scrdata[9]; + copy_from_user (scrdata, data, 9); + + if ((!scrdata[0]) && (!scrdata[1]) && (scrdata[2]==1) + && (scrdata[3]==0xBA) && ((scrdata[4]&0xC0)==0x40)) { + SCR_base=((scrdata[4]>>3)&0x07); + SCR_base=(SCR_base<<2) | (scrdata[4]&0x03); + SCR_base=(SCR_base<<8) | scrdata[5]; + SCR_base=(SCR_base<<5) | ((scrdata[6]>>3)&0x1F); + SCR_base=(SCR_base<<2) | (scrdata[6]&0x03); + SCR_base=(SCR_base<<8) | scrdata[7]; + SCR_base=(SCR_base<<5) | ((scrdata[8]>>3)&0x1F); + } + return SCR_base; +} + +u32 SetSCR(struct cvdv_cards *card, u32 SCR_base) +{ + MDEBUG(3, ": SCR in DVD Pack: 0x%08X\n",SCR_base); + if (DecoderReadByte(card, 0x007) & 0x10) { // SCR already stopped + DecoderWriteByte(card,0x009,SCR_base&0xFF); // Set SCR counter + DecoderWriteByte(card,0x00A,(SCR_base>>8)&0xFF); + DecoderWriteByte(card,0x00B,(SCR_base>>16)&0xFF); + DecoderWriteByte(card,0x00C,(SCR_base>>24)&0xFF); + } else { + DecoderMaskByte(card,0x007,0xD2,0xD2); + // Set 0x10, halt SCR counter + DecoderWriteByte(card,0x009,SCR_base&0xFF); // Set SCR counter + DecoderWriteByte(card,0x00A,(SCR_base>>8)&0xFF); + DecoderWriteByte(card,0x00B,(SCR_base>>16)&0xFF); + DecoderWriteByte(card,0x00C,(SCR_base>>24)&0xFF); + DecoderMaskByte(card,0x007,0xD2,0xC2); + // Del 0x10, SCR counter run + } + return SCR_base; +} + +void DecoderPause(struct cvdv_cards *card) +{ + DecoderMaskByte(card, 0x007, 0xD2, 0xD2); + // Set 0x010, halt SCR counter + AudioSetPlayMode(card, MAUDIO_PAUSE); + DecoderStopDecode(card); +#ifdef DVB + card->videostate.playState=VIDEO_FREEZED; +#endif + card->videoffwd = 0; + card->videoslow = 0; +} + +void DecoderUnPause(struct cvdv_cards *card) +{ + DecoderStartDecode(card); + card->videoffwd = 0; + AudioSetPlayMode(card, MAUDIO_PLAY); + DecoderMaskByte(card, 0x007, 0xD2, 0xC2); + // Del 0x010, SCR counter run +#ifdef DVB + card->videostate.playState=VIDEO_PLAYING;; +#endif + card->videoslow = 0; +} + +void CloseCard(struct cvdv_cards *card) +{ +#ifdef NOINT + spin_lock(&card->timelock); + del_timer(&card->timer); + spin_unlock(&card->timelock); +#endif + MargiFlush(card); + MDEBUG(1, ": Closing card\n"); + card->DecoderOpen = 1; + DecoderClose(card); + DecoderUnPrepare(card); + DecoderStreamReset(card); + DecoderSetupReset(card); + VideoSetBackground(card, 1, 0, 0, 0); + + AudioClose(card); + OSDClose(card); + L64021Init(card); + MargiFreeBuffers(card); + + OSDOpen(card, 50, 50, 150, 150, 2, 1); + OSDTest(card); +} + + +void DecoderReadAudioInfo(struct cvdv_cards *card) +{ + u8 data; + static int bitrates[17] = {0, 32, 40, 48, 56, 64, 80, 96, 112, + 128, 160, 192, 224, 256, 320, 384, 0}; + struct AudioParam *audio = &card->stream.audio; + data = DecoderReadByte(card, 0x150); + audio->mpeg.present = data & 0x60; + // MPEG Layer Code 00 reserverd, we can assume valid MPEG params + if (audio->mpeg.present) { + audio->mpeg.MPEG2 = data & 0x80; + audio->mpeg.layer = 4 - ((data >> 5) & 0x03); + if (data & 0x0F) { + if ((data & 0x0F) == 1) audio->mpeg.bitrate = 32; + else switch (audio->mpeg.layer) { + case 1: + audio->mpeg.bitrate = 32 * (data & 0x0F); + break; // Layer I + case 2: + audio->mpeg.bitrate = bitrates[(data & 0x0F) + + 1]; + break; // Layer II + default: + audio->mpeg.bitrate = bitrates[data & 0x0F]; + // Layer III + } + } else audio->mpeg.bitrate = 0; + data = DecoderReadByte(card, 0x151); + switch ((data >> 6) & 0x03) { + case 0: + audio->mpeg.samplefreq = 44; + break; + case 1: + audio->mpeg.samplefreq = 48; + break; + case 2: + audio->mpeg.samplefreq = 32; + break; + default: + audio->mpeg.samplefreq = 0; // invalid + } + audio->mpeg.mode = (data >> 3) & 0x03; + audio->mpeg.modeext = (data >> 1) & 0x03; + audio->mpeg.copyright = data & 0x01; + data=DecoderReadByte(card, 0x152); + audio->mpeg.original = data & 0x80; + audio->mpeg.emphasis = (data >> 5) & 0x03; + } + data = DecoderReadByte(card, 0x153); + audio->ac3.present = (data != 0); + // value 0 for bits 0..5 forbidden, we can assume valid ac3 params + if (audio->ac3.present) { + audio->ac3.acmod = (data >> 5) & 0x07; + audio->ac3.dialnorm = data & 0x1F; + data = DecoderReadByte(card, 0x154); + audio->ac3.bsmod = (data >> 5) & 0x07; + audio->ac3.dialnorm2 = data > 0x1F; + data = DecoderReadByte(card, 0x155); + audio->ac3.surmixlev = (data >> 6) & 0x03; + audio->ac3.mixlevel = (data >> 1) & 0x1F; + data = DecoderReadByte(card, 0x156); + audio->ac3.cmixlev = (data >> 6) & 0x03; + audio->ac3.mixlevel2 = (data >> 1) & 0x1F; + data = DecoderReadByte(card, 0x157); + audio->ac3.fscod = (data >> 6) & 0x03; + audio->ac3.lfeon = (data >> 5) & 0x01; + audio->ac3.bsid = data & 0x1F; + data = DecoderReadByte(card, 0x158); + audio->ac3.dsurmod = (data >> 6) & 0x03; + audio->ac3.frmsizecod = data & 0x3F; + audio->ac3.langcod = DecoderReadByte(card, 0x159); + audio->ac3.langcod2 = DecoderReadByte(card, 0x15A); + audio->ac3.timecod = DecoderReadByte(card, 0x15B); + data = DecoderReadByte(card, 0x15C); + audio->ac3.timecod = (audio->ac3.timecod << 6) | + ((data >> 2) & 0x3F); + audio->ac3.roomtyp = data & 0x03; + audio->ac3.timecod2 = DecoderReadByte(card, 0x15D); + data = DecoderReadByte(card, 0x15E); + audio->ac3.timecod2 = (audio->ac3.timecod2 << 6) | + ((data >> 2) & 0x3F); + audio->ac3.roomtyp2 = data & 0x03; + } + audio->pcm.present =! (DecoderReadByte(card, 0x161) & 0x20); + // PCM FIFO not empty? Then, we can assume valid LPCM params + if (audio->pcm.present) { + data = DecoderReadByte(card, 0x15F); + audio->pcm.audio_frm_num = (data >> 3) & 0x1F; + audio->pcm.num_of_audio_ch = data & 0x07; + data = DecoderReadByte(card, 0x160); + audio->pcm.Fs = (data >> 6) & 0x03; + audio->pcm.quantization = (data >> 4) & 0x03; + audio->pcm.emphasis = (data >> 2) & 0x03; + audio->pcm.mute_bit = (data >> 1) & 0x01; + } + switch (card->setup.audioselect) { + case audio_disable: + audio->valid = 0; + break; + case audio_none: + case audio_DTS: + case audio_SDDS: + if ((audio->valid = (audio->ac3.present || + audio->pcm.present || + audio->mpeg.present))) { + if (audio->mpeg.present) { + card->setup.audioselect = audio_MPEG; + } else if (audio->pcm.present) { + card->setup.audioselect = audio_LPCM; + } else if (audio->ac3.present) { + card->setup.audioselect = audio_AC3; + } + } else { + audio->valid = 0; + card->setup.audioselect = audio_none; + } + break; + case audio_MPEG: // MPEG Audio + case audio_MPEG_EXT: // MPEG Audio with extension stream + audio->valid = audio->mpeg.present; + break; + case audio_LPCM: // Linear Pulse Code Modulation LPCM + audio->valid = audio->pcm.present; + break; + case audio_AC3: // AC-3 + audio->valid = audio->ac3.present; + break; + } + MDEBUG(1, ": -- DecoderReadAudioInfo - type/valid %d/%d:\n", card->setup.audioselect, audio->valid); + if (audio->mpeg.present || audio->ac3.present || audio->pcm.present) + MDEBUG(1, ": Audio - Decoded parameters:\n"); + if (audio->mpeg.present) MDEBUG(1, ": MPEG%s Layer %d, %d kHz, %d kbps, %s, %s%s, %s emphasis\n", + ((audio->mpeg.MPEG2) ? "2" : "1"), + audio->mpeg.layer, + audio->mpeg.samplefreq, + audio->mpeg.bitrate, + ((audio->mpeg.mode == 0) ? "stereo" : ((audio->mpeg.mode == 1) ? "joint stereo" : ((audio->mpeg.mode == 2) ? "dual channel" : "single channel"))), + ((audio->mpeg.copyright) ? "copyrighted " : ""), + ((audio->mpeg.original) ? "original" : "copy"), + ((audio->mpeg.emphasis == 0) ? "no" : ((audio->mpeg.emphasis == 1) ? "50/15 usec." : ((audio->mpeg.emphasis == 2) ? "invalid" : "J.17"))) + ); + if (audio->ac3.present) MDEBUG(1, ": AC3 acmod=%d bsmod=%d dialnorm=%d dialnorm2=%d surmixlev=%d mixlevel=%d cmixlev=%d mixlevel2=%d fscod=%d lfeon=%d bsid=%d dsurmod=%d frmsizecod=%d langcod=%d langcod2=%d timecod=%d roomtyp=%d timecod2=%d roomtyp2=%d\n", + audio->ac3.acmod, + audio->ac3.bsmod, + audio->ac3.dialnorm, + audio->ac3.dialnorm2, + audio->ac3.surmixlev, + audio->ac3.mixlevel, + audio->ac3.cmixlev, + audio->ac3.mixlevel2, + audio->ac3.fscod, + audio->ac3.lfeon, + audio->ac3.bsid, + audio->ac3.dsurmod, + audio->ac3.frmsizecod, + audio->ac3.langcod, + audio->ac3.langcod2, + audio->ac3.timecod, + audio->ac3.roomtyp, + audio->ac3.timecod2, + audio->ac3.roomtyp2); + if (audio->pcm.present) MDEBUG(1, ": LPCM audio_frm_num=%d num_of_audio_ch=%d Fs=%d quantization=%d emphasis=%d mute_bit=%d\n", + audio->pcm.audio_frm_num, + audio->pcm.num_of_audio_ch, + audio->pcm.Fs, + audio->pcm.quantization, + audio->pcm.emphasis, + audio->pcm.mute_bit); +} + +void DecoderReadAuxFifo(struct cvdv_cards *card) +{ + int i = 0; + u8 data; + int layer; + + struct StreamInfo *stream = &card->stream; + MDEBUG(3, ": AUX - %03X ", card->AuxFifo[card->AuxFifoTail]); + while (card->AuxFifoHead != card->AuxFifoTail) { + + layer = (card->AuxFifo[card->AuxFifoTail] >> 8) & 0x07; + data = card->AuxFifo[card->AuxFifoTail] & 0xFF; + card->AuxFifoTail = (card->AuxFifoTail + 1) & FIFO_MASK; + if (layer != card->AuxFifoLayer) { // start of a new layer? + i = 0; + card->AuxFifoLayer = layer; + } else i++; + switch (layer) { // layer code + case 0: // sequence header + if (! stream->sh.valid) switch (i) { + case 0: + stream->sh.hsize = data & 0x0F; + break; + case 1: + stream->sh.hsize = (stream->sh.hsize << 8) + | data; + stream->hsize = stream->sh.hsize; + break; + case 2: + stream->sh.vsize = data & 0x0F; + break; + case 3: + stream->sh.vsize = (stream->sh.vsize << 8) | + data; + stream->vsize = stream->sh.vsize; + break; + case 4: + stream->sh.aspectratio = data & 0x0F; + break; + case 5: + stream->sh.frameratecode = data & 0x0F; + break; + case 6: + stream->sh.bitrate = data & 0x03; + break; + case 7: + stream->sh.bitrate = (stream->sh.bitrate << 8) + | data; + break; + case 8: + stream->sh.bitrate = (stream->sh.bitrate << 8) + | data; + stream->bitrate = stream->sh.bitrate; + break; + case 9: + stream->sh.vbvbuffersize = data & 0x03; + break; + case 10: + stream->sh.vbvbuffersize = + (stream->sh.vbvbuffersize << 8) | + data; + stream->vbvbuffersize = + stream->sh.vbvbuffersize; + break; + case 11: + stream->sh.constrained = data & 0x01; + stream->sh.valid = 1; + MDEBUG(1, ": AUX - MPEG1 - %dx%d %s %s fps, %d bps, %d kByte vbv%s\n", stream->sh.hsize, stream->sh.vsize, + ((stream->sh.aspectratio == 1) ? "1:1" : + ((stream->sh.aspectratio == 2) ? "3:4" : + ((stream->sh.aspectratio == 3) ? "9:16" : + ((stream->sh.aspectratio == 4) ? "1:2.21" : + "?:?")))), + ((stream->sh.frameratecode == 1) ? "23.976" : + ((stream->sh.frameratecode == 2) ? "24" : + ((stream->sh.frameratecode == 3) ? "25" : + ((stream->sh.frameratecode == 4) ? "29.97" : + ((stream->sh.frameratecode == 5) ? "30" : + ((stream->sh.frameratecode == 6) ? "50" : + ((stream->sh.frameratecode == 7) ? "59.94" : + ((stream->sh.frameratecode == 8) ? "60" : + "?")))))))), + stream->sh.bitrate * 400, + stream->sh.vbvbuffersize * 16, + ((stream->sh.constrained) ? ", constrained" : "") + ); + break; + } + break; + case 1: // group of pictures + if (! stream->gop.valid) + switch (i) { + case 0: + stream->gop.timecode = data & 0x01; + break; + case 1: + stream->gop.timecode = + (stream->gop.timecode << 8) | + data; + break; + case 2: + stream->gop.timecode = + (stream->gop.timecode << 8) | + data; + break; + case 3: + stream->gop.timecode = + (stream->gop.timecode << 8) | + data; + break; + case 4: + stream->gop.closedgop = data & 0x01; + break; + case 5: + stream->gop.brokenlink = data & 0x01; + stream->gop.valid = 1; + break; + } + break; + case 2: // picture + if (0) + switch (i) { + case 0: + break; + } + break; + case 7: // extension layer + if (i == 0) card->AuxFifoExt = data; + else + switch (card->AuxFifoExt) { // extension code + case 1: // sequence extension + if ((stream->sh.valid) && + (! stream->se.valid)) + switch (i) { + case 1: + stream->se.profilelevel + = data; + break; + case 2: + stream->se.progressive + = data & 0x01; + break; + case 3: + stream->se.chroma = + (data >> 4) & + 0x03; + stream->se.hsizeext = + (data >> 2) & + 0x03; + stream->se.vsizeext = + data & 0x03; + stream->hsize |= + (stream->se.hsizeext << 12); + stream->vsize |= + (stream->se.vsizeext << 12); + break; + case 4: + stream->se.bitrateext = + data & 0x0F; + break; + case 5: + stream->se.bitrateext = + (stream->se.bitrateext << 8) | data; + stream->bitrate |= + (stream->se.bitrateext << 18); + break; + case 6: + stream->se.vbvbuffersizeext = data; + stream->vbvbuffersize |= (stream->se.vbvbuffersizeext << 10); + break; + case 7: + stream->se.lowdelay = + (data >> 7) & + 0x01; + stream->se.frextn = + (data >> 5) & + 0x03; + stream->se.frextd = + data & 0x1F; + stream->se.valid = 1; + stream->MPEG2 = 1; + MDEBUG(1, ": AUX - MPEG2 - %dx%d %s %s*%d/%d fps, %d bps, %d kByte vbv%s%s\n", stream->hsize, stream->vsize, + ((stream->sh.aspectratio == 1) ? "1:1" : + ((stream->sh.aspectratio == 2) ? "3:4" : + ((stream->sh.aspectratio == 3) ? "9:16" : + ((stream->sh.aspectratio == 4) ? "1:2.21" : + "?:?")))), + ((stream->sh.frameratecode == 1) ? "23.976" : + ((stream->sh.frameratecode == 2) ? "24" : + ((stream->sh.frameratecode == 3) ? "25" : + ((stream->sh.frameratecode == 4) ? "29.97" : + ((stream->sh.frameratecode == 5) ? "30" : + ((stream->sh.frameratecode == 6) ? "50" : + ((stream->sh.frameratecode == 7) ? "59.94" : + ((stream->sh.frameratecode == 8) ? "60" : + "?")))))))), + stream->se.frextn + 1, + stream->se.frextd + 1, + stream->bitrate * 400, + stream->vbvbuffersize * 16, + ((stream->sh.constrained) ? ", constrained" : ""), + ((stream->se.lowdelay) ? ", low delay" : "") + ); + break; + } + break; + case 2: // sequence display extension + if (0) + switch (i) { + case 0: + break; + } + break; + case 3: // quant matrix extension + if (0) + switch (i) { + case 0: + break; + } + break; + case 4: // copyright extension + if (0) + switch (i) { + case 0: + break; + } + break; + case 7: // picture display extension + if (0) switch (i) { + case 0: + break; + } + break; + case 8: // picture coding extension + if (0) + switch (i) { + case 0: + break; + } + break; + default: + break; + } + break; + default:break; + } + + } +} + +void DecoderReadDataFifo(struct cvdv_cards *card) +{ + MDEBUG(3, ": DATA - "); + while (card->DataFifoHead != card->DataFifoTail) { + MDEBUG(3,"%03X ", card->DataFifo[card->DataFifoTail]); + card->DataFifoTail = (card->DataFifoTail + 1) & FIFO_MASK; + } + MDEBUG(3,"\n"); +} + +int DecoderReadNavipack(struct cvdv_cards *card) +{ + u32 startaddr, endaddr, writeaddr; + u8 navipack[1024]; + u16 PacketLength; + u8 SubStreamID; + //struct Navi navi; + int i; + startaddr = (DecoderReadWord(card, 0x05C) & 0x3FFF) << 7; + // 21 bit word address + endaddr = (DecoderReadWord(card, 0x05E) & 0x3FFF) << 7; + // 21 bit word address + writeaddr = DecoderReadByte(card, 0x075) & 0xFF; + writeaddr |= (DecoderReadWord(card, 0x077) & 0x0FFF) << 8; + //writeaddr <<= 3; + MDEBUG(3, ": -- DecoderReadNavipack 0x%08X-0x%08X, ->0x%08X <-0x%08X\n", + startaddr, endaddr, writeaddr, card->NaviPackAddress); + + if (DecoderReadByte(card, 0x07B) & 0xC0) { // navi pack available? + DRAMReadByte(card, card->NaviPackAddress, 1024, navipack, 0); + card->reg07B |= 0x20; // decrement navi counter + DecoderWriteByte(card, 0x07B, card->reg07B); + card->reg07B &= ~0x20; + //DecoderSetByte(card, 0x07B, 0x20); // decrement navi counter + card->NaviPackAddress += 512; // increment in words + if (card->NaviPackAddress >= endaddr) + card->NaviPackAddress = startaddr; + MDEBUG(4, ": Navipack %02X %02X %02X %02X %02X %02X %02X %02X\n", + navipack[0], navipack[1], navipack[2], navipack[3], navipack[4], + navipack[5], navipack[6], navipack[7]); + if ((!navipack[0]) && (!navipack[1]) && (navipack[2] == 1) && + (navipack[3] == 0xBF)) { + PacketLength = (navipack[4] << 8) | navipack[5]; + SubStreamID = navipack[6]; + MDEBUG(4, ": Navipack Len=%d, ID=%d\n", PacketLength, SubStreamID); + i = 7; // start of payload data in navipack[] + switch (SubStreamID) { + case 0: // Presentation Control Information (PCI) + if (PacketLength < 980) return 1; // Packet too small + DecoderQueueNavi(card, navipack); + break; + case 1: // Data Search Information (DSI) + if (PacketLength < 1018) return 1; // Packet too small + DecoderQueueNavi(card, navipack); + break; + default: + break; + } + } else { + MDEBUG(4, "navipack format error:%02X %02X %02X %02X %02X %02X %02X %02X\n", + navipack[0], navipack[1], navipack[2], navipack[3], navipack[4], + navipack[5], navipack[6], navipack[7]); + } + } else { + MDEBUG(4, ": no navi pack avail.\n"); + } + return 0; +} + +int AudioStart(struct cvdv_cards *card) +{ + DecoderReadAudioInfo(card); // detect audio type + if (card->stream.audio.valid) { + MDEBUG(1, ": Audio Init in delayed decoder start\n"); + if (card->AudioInitialized) AudioClose(card); + switch (card->setup.audioselect) { + case audio_MPEG: // MPEG Audio + case audio_MPEG_EXT: // MPEG Audio with ext. + MDEBUG(1, ": Using MPEG Audio\n"); + AudioInit(card, card->stream.audio.mpeg.samplefreq, 0); + if (card->stream.audio.mpeg.mode == 3) AudioDualMono(card, 2); // left channel only + else AudioDualMono(card, 0); + break; + case audio_DTS: + case audio_LPCM: // Linear Pulse Code Modulation LPCM + MDEBUG(1, ": Using LPCM Audio\n"); + AudioInit(card, 48, 0); // or 96 + break; + case audio_AC3: // AC-3 + MDEBUG(1, ": Using AC-3 Audio\n"); + switch (card->stream.audio.ac3.fscod) { + case 0:AudioInit(card, 48, 0); break; + case 1:AudioInit(card, 44, 0); break; + case 2:AudioInit(card, 32, 0); break; + } + break; + case audio_none: + case audio_disable: + case audio_SDDS: + } + } else return 1; + return 0; +} + +u32 DecoderReadSCR(struct cvdv_cards *card, u16 address) +{ + u32 SCR; + SCR = DecoderReadByte(card, address); + SCR |= ((u32)DecoderReadByte(card, address+1) << 8); + SCR |= ((u32)DecoderReadByte(card, address+2) << 16); + SCR |= ((u32)DecoderReadByte(card, address+3) << 24); + return SCR; +} + +u32 DecoderReadRWAddr(struct cvdv_cards *card, u16 address) +{ + u32 addr; + addr = DecoderReadByte(card, address) & 0xFF; + addr |= (((u32)DecoderReadByte(card, address+1) & 0xFF) << 8); + addr |= (((u32)DecoderReadByte(card, address+2) & 0x0F) << 16); + return addr; +} + +int PTSGetFirstPTS(PTSStorage *store, u32 *PTS) +{ + if ( store->end == store->begin ) { + return 0; + } else { + *PTS = store->PTS[store->begin]; + return 1; + } +} + +void PTSStoreAdd(PTSStorage *store, u32 PTS, u32 AddrB, u32 AddrE) +{ + int new; + MDEBUG(3, ": PTSStoreAdd - store in [%d] %08X - %08X\n", store->end, AddrB, AddrE); + + // cheap fix: don't store if address rollover + if ((AddrB & 0x00080000) != (AddrE & 0x00080000)) return; + + new = store->end; + + store->end++; + if (store->end >= store->size) store->end = 0; + if (store->end == store->begin) { + store->begin++; + if (store->begin >= store->size) store->begin = 0; + } + + store->AddrB[new] = AddrB; + store->AddrE[new] = AddrE; + store->PTS[new] = PTS; +} + +int PTSGetPTS (PTSStorage *store, u32 Addr, u32 *PTS ) +{ + u32 AddrB; + u32 AddrE; + int i; + int found; + int search; + + MDEBUG(3, ": PTSGetPTS - search %08X\n", Addr); + + if (store->end == store->begin) { + store->LastAddr = Addr; + return 0; + } + + // Search for the PTS in the array + found = 0; + search = 1; + while (search && !found) { + // Get the first value + i = store->begin; + AddrB = store->AddrB[i]; + AddrE = store->AddrE[i]; + + MDEBUG(3, ": PTSGetPTS - search in [%d] %08X - %08X\n", i, AddrB, AddrE); + + //If in range, keep it + if ((Addr >= AddrB) && (Addr <= AddrE)) { + *PTS = store->PTS[i]; + found = 1; + } else { + if ((Addr & 0x00080000) == (AddrB & 0x00080000)) { + if (Addr < AddrB ) search = 0; + } else { + if ((store->LastAddr & 0x00080000) == (Addr & 0x00080000)) search = 0; + } + } + if (search) { + store->begin++; + if (store->begin >= store->size) store->begin = 0; + if (store->end == store->begin ) search = 0; + } + } + store->LastAddr = Addr; + return found; +} + + +u32 GetPTS(u8 *data, u32* MediaPointer, int mpeg, int hlength,int off) +{ + u32 PTS = 0xFFFFFFFFUL; + int p = 0; + + // Read PTS, if present + if ((mpeg == 2 && data[p + 7] & 0x80) || + (mpeg == 1 && off)) { + if (mpeg == 1) p = off-9; + PTS = (data[p + 9] >> 1) & 0x03UL; + PTS = (PTS << 8) | (data[p + 10] & 0xFFUL); + PTS = (PTS << 7) | ((data[p + 11] >> 1) & 0x7FUL); + PTS = (PTS << 8) | (data[p + 12] & 0xFFULL); + PTS = (PTS << 7) | ((data[p + 13] >> 1) & 0x7FUL); + } + // Now, skip rest of PES header and stuffing + if (mpeg == 2){ + p += (9 + (data[p + 8] & 0xFF)); + p = ((p + 7) / 8) * 8; + } else p = hlength+7; + if (!(data[p++] | data[p++] | data[p++] | data[p++])) { + *MediaPointer = (u32)data[p++] & 0xFF; + *MediaPointer = (*MediaPointer << 8) | ((u32)data[p++] & 0xFF); + *MediaPointer = (*MediaPointer << 8) | ((u32)data[p++] & 0xFF); + *MediaPointer = (*MediaPointer << 8) | ((u32)data[p++] & 0xFF); + } else { + *MediaPointer = 0xFFFFFFFFUL; + } + return PTS; +} + +int ReadPESChunk(struct cvdv_cards *card, u32 *addr, u8 *data, u32 start, u32 end) +{ + int i = 5, err = -1; + while (err && (i--)) err &= DRAMReadByte(card, *addr << 2, 8, &data[0], 0); + if (err) return 1; + (*addr)++; + if (*addr >= end) *addr = start; + return 0; +} + +void ReadPESHeaders(struct cvdv_cards *card) +{ + u8 startcode[] = {0x00, 0x00, 0x01}; + int LoopCount; + u32 LastVAddr; // Current Video Address + u32 LastAAddr; // Current Audio Address + u32 Addr; // Current Header Address + u32 PESAddr; // Pointer from Header Block + u32 PTS; // PTS from Header Block + u8 Data[32]; + u32 AudioPESStart; + u32 AudioPESEnd; + int i, j, p, fail; + u32 FailAddr; + int hlength=0; + int mpeg=0; + int check; + int mp=0; + int off=0; + + AudioPESStart = (DecoderReadWord(card, 0x058) & 0x3FFF) << 5; + AudioPESEnd = ((DecoderReadWord(card, 0x05A) & 0x3FFF) + 1) << 5; + + LastVAddr = DecoderReadRWAddr(card, 0x060); + LastAAddr = DecoderReadRWAddr(card, 0x063); + + if (card->LastAddr == 0) card->LastAddr = AudioPESStart; + + //Read the PES header buffer + Addr = DecoderReadRWAddr(card, 0x072) & 0x0007FFFF; + if (Addr >= AudioPESEnd) { + Addr = card->LastAddr = AudioPESStart; + } + + LoopCount = 0; + while ((card->LastAddr != Addr) && (LoopCount++ < 200)) { + FailAddr = card->LastAddr; + fail = 0; + p = 0; + + if (ReadPESChunk(card, &card->LastAddr, &Data[p], + AudioPESStart, AudioPESEnd)) continue; + p+=8; + j=1; + + if (memcmp(Data, startcode, 3)) continue; + if ((Data[3] == 0xE0) || (Data[3] == 0xBD) + || ((Data[3] & 0xE0) == 0xC0)) { + + fail |= ReadPESChunk(card, &card->LastAddr, + &Data[p], AudioPESStart, + AudioPESEnd); + + + p+=8; + j++; + if ( (Data[6] & 0xC0) == 0x80 ){ + hlength = 9+Data[8]; + mpeg = 2; + } else { + mpeg = 1; + mp = 6; + check = Data[mp]; + mp++; + while (check == 0xFF){ + if (!fail && mp == p) { + fail |= ReadPESChunk( + card, + &card->LastAddr, + &Data[p], + AudioPESStart, + AudioPESEnd); + p+=8; + j++; + } + check = Data[mp]; + mp++; + } + if (!fail && mp == p) { + fail |= ReadPESChunk( + card, + &card->LastAddr, + &Data[p], + AudioPESStart, + AudioPESEnd); + p+=8; + j++; + } + + if ( !fail && (check & 0xC0) == 0x40){ + check = Data[mp]; + mp++; + if (!fail && mp == p) { + fail |= ReadPESChunk( + card, + &card->LastAddr, + &Data[p], + AudioPESStart, + AudioPESEnd); + p+=8; + j++; + } + check = Data[mp]; + mp++; + } + if ( !fail && (check & 0x20)){ + if (check & 0x30) hlength = mp+10; + else hlength = mp+5; + off = mp-1; + } + } + + for (i = 1; (i < ((hlength+7) / 8)) && (!fail); + i++) { + fail |= ReadPESChunk(card, &card->LastAddr, + &Data[p], AudioPESStart, + AudioPESEnd); + p+=8; + j++; + } + + if (!fail) { + PTS = GetPTS(Data, &PESAddr, + mpeg, hlength,off); + if ((PTS != 0xFFFFFFFF) && + (PESAddr != 0xFFFFFFFF)) { + if (Data[3] == 0xE0) { // Video + PTSStoreAdd(&card->VideoPTSStore, PTS, PESAddr, LastVAddr); + } else { // Audio + PTSStoreAdd(&card->AudioPTSStore, PTS, PESAddr, LastAAddr); + } + } + } + } else { + //card->LastAddr = Addr; + } + // In case of error, rewind and try again + if (fail) card->LastAddr = FailAddr; + } +} + +void L64021Intr(struct cvdv_cards *card) +{ + u32 SCR_base, SCR_compareV, SCR_compareA; + u32 VideoAddr, AudioAddr, PTS; + int i, a, v, as, vs, ap, vp; + u8 intr[5]; + u8 layer; + long ISRTime, DeltaSyncTime, Offset; + + int used = 0; + u8 err; + + err = DecoderReadByte(card, 0x095); + if (err & 0x17) { + MDEBUG(0, ": Packet Error: 0x%02X\n", err); + } + + ISRTime = 0; // TODO system time + + for (i = 0; i < 5; i++) + if ((intr[i] = DecoderReadByte(card, i))) used = 1; + if (used) { + if (intr[0] & 0x80) { // new field + card->fields++; + + if (card->videoffwd){ + if (!card->videoffwd_last){ + AudioStopDecode(card); + card->videosync = 0; + card->videoskip = card->videoffwd; + card->videoskip = 0; + card->videoffwd_last = 1; + card->videoskip_last = 0; + } else { + if (card->videoskip_last == -1){ + card->videoskip = + card->videoffwd; + } + + if (!card->videoskip) + card->videoskip_last = -1; + else + card->videoffwd_last = + card->videoffwd; + } + } else if( card->videoffwd_last ){ + card->videoffwd_last = 0; +#ifdef DVB + if (card->audiostate.AVSyncState) +#endif + card->videosync = 1; + AudioStartDecode(card); + } + + + if (card->videoslow){ + if (!card->videoslow_last){ + AudioStopDecode(card); + card->videosync = 0; + card->videodelay = card->videoslow; + card->videoskip = 0; + card->videoslow_last = 1; + card->videodelay_last = 0; + } else { + if (card->videodelay_last == -1){ + card->videodelay = + card->videoslow; + } + + if (!card->videodelay) + card->videodelay_last = -1; + else + card->videodelay_last = + card->videodelay; + } + } else if( card->videoslow_last ){ + card->videoslow_last = 0; +#ifdef DVB + if (card->audiostate.AVSyncState) +#endif + card->videosync = 1; + AudioStartDecode(card); + } + + + if (card->videodelay > 0) { + if( (DecoderReadByte(card, 0x0ED) & 0x03) + == 0x00) { + card->videodelay--; + if(card->videodelay){ + DecoderWriteByte(card, 0x0ED, + 0x01); + } else { + DecoderWriteByte(card, 0x0ED, + 0x00); + } + } else { + card->videodelay--; + if(!card->videodelay){ + DecoderWriteByte(card, 0x0ED, + 0x00); + } + } + } else if (card->videoskip > 0) { + if ((DecoderReadByte(card, 0x0EC) & 0x03) + == 0x00) { + if (DecoderReadWord(card, 0x096) > 5){ + // pictures in video ES channel + card->videoskip--; + if(card->videoskip) { + DecoderWriteByte(card, + 0x0EC + ,0x03); + } else { + DecoderWriteByte(card, + 0x0EC + ,0x00); + } + } else { + card->videoskip = 0; + DecoderWriteByte (card, 0x0EC, + 0x00); + } + } + } + + + i = (DecoderReadByte(card, 0x113) & 0xFC) | + (DecoderReadByte(card, 0x114) & 0x01); + v = DecoderGetVideoESLevel(card); + if (card->startingV) { + vs = card->VideoESSize; + if (vs > 0) vp = (100 * v) / vs; + else vp = 0; + if (vp > 90) { + MDEBUG(0,": Delayed Video Decoder start\n"); + card->startingV = 0; + DecoderStartDecode(card); + //DecoderSetVideoPanic(card, 1, 3); + // video panic at 3 pictures + //DecoderSetVideoPanic(card, 0, DecoderGetVideoESSize(card) / 4); // video panic at 25 percent + } + } + a = DecoderGetAudioESLevel(card); + if (card->startingA) { + as = card->AudioESSize; + if (as > 0) ap = (100 * a) / as; + else ap = 0; + if (ap > 90) { + MDEBUG(0,": Delayed Audio Decoder start\n"); + AudioSetPlayMode(card, MAUDIO_PLAY); + if (!AudioStart(card)) { + card->startingA = 0; + } + } + } + if (card->fields >= 250) { // 5 seconds (PAL) + SCR_base = DecoderReadSCR(card, 0x009); + SCR_compareA = DecoderReadSCR(card, 0x014); + SCR_compareV = DecoderReadSCR(card, 0x00D); + if (DecoderReadByte(card, 0x013) & 0x03) + card->fields = 0; + } + } + + if (intr[0] & 0x04) { // First Slice Start Code + if (card->showvideo) { + // Unmute card video if first picture slice detected + VideoSetBackground(card, 0, 0, 0, 0); // Video on black + card->showvideo = 0; + } + } + + if (intr[0] & 0x02 ) { // Aux/User Data Fifo + used = 0; + while ( (used++ < 1000) && + (layer = DecoderReadByte(card, 0x040)) & 0x03){ + card->AuxFifo[card->AuxFifoHead] = + ((layer << 6) & 0x0700) | + DecoderReadByte(card, 0x043); + card->AuxFifoHead = (card->AuxFifoHead + 1) & + FIFO_MASK; + } + if (used < 1000) DecoderReadAuxFifo(card); + used = 0; + + while ( (used++ < 1000) && + (layer = DecoderReadByte(card, 0x041)) & 0x03){ + card->DataFifo[card->DataFifoHead] = + ((layer << 6) & 0x0300) | + DecoderReadByte(card, 0x043); + card->DataFifoHead = (card->DataFifoHead + 1) + & FIFO_MASK; + } + if (used < 1000 ) DecoderReadDataFifo(card); + } + + if ((intr[0] & 0x01) != card->intdecodestatus) { + // decode status + card->intdecodestatus = intr[0] & 0x01; + MDEBUG(0, ": Int - decode status now %s\n", + ((card->intdecodestatus) ? + "running" : "stopped")); + if (card->intdecodestatus) { // now running + //DecoderSetVideoPanic(card, 1, 3); + // video panic at 3 pictures + card->showvideo = 1; + } else { // now stopped + if (card->closing) { + card->closing = 0; + CloseCard(card); + } + } + + } + + if (intr[1] & 0x10) { // Begin Active Video + if (card->highlight_valid) { + for (i = 0; i < 10; i++) + DecoderWriteByte(card, 0x1C0 + i, + card->highlight[i]); + card->highlight_valid = 0; + } + } + if (intr[1] & 0x08) { // SPU Start Code Detected + MDEBUG(0, ": Int - SPU Start Code Detected\n"); + } + + if (intr[1] & 0x04) { // SCR compare audio + MDEBUG(0, ": Int - SCR compare audio\n"); + DecoderDelByte(card, 0x013, 0x01); + AudioStart(card); + } + + if (intr[2] & 0x20) { // DSI PES data ready + DecoderReadNavipack(card); + } + + if (intr[2] & 0x06) { // Audio / Video PES data ready + ReadPESHeaders(card); + } + + if (intr[3] & 0x40) { // CSS + card->css.status = DecoderReadByte(card, 0x0B0); + if (card->css.status&0x01) + card->css.ChallengeReady = 1; + // challenge ready + if (card->css.status&0x02) + card->css.ResponseReady = 1; + // response ready + if (card->css.status&0x04) + card->css.DiskKey = 1; + // Disk key ready + if (card->css.status&0x08) + card->css.Error = 1; + // Disk key error + if (card->css.status&0x10) + card->css.TitleKey = 1; + // Title key ready + if (card->css.status&0x20) + card->css.TitleKeyDiff = 1; + // Title key error + } + + + if (intr[3] & 0x30) { + // Audio/Video ES channel buffer underflow + MDEBUG(1,": Int - ES channel buffer underflow\n"); + if (card->closing) { + card->closing = 0; + CloseCard(card); + } + } + + if (intr[4] & 0x10 ) { // SPU decode error + MDEBUG(1,": Int - SPU decode error: (1CA)=0x%02X\n", + DecoderReadByte(card, 0x1CA)); + DecoderDelByte(card, 0x1A0, 0x01); // SPU decode stop + DecoderSetByte(card, 0x1A0, 0x01); // SPU decode start + } + + // Audio / Video Syncronisation + + if (card->videosync && !card->videoskip && !card->videodelay) { + SCR_base = DecoderReadSCR(card, 0x009); + SCR_compareV = DecoderReadSCR(card, 0x00D); + if (intr[1] & 0x02) { // picture start code detected + DecoderMaskByte(card, 0x011, 0x03, 0x01); + // Set SCR compare/capture mode to capture + DecoderSetByte(card, 0x11, 0x04); + // Set "capture on picture start" + if (intr[1] & 0x01) { + // audio sync code detected + DecoderSetByte(card, 0x11, 0x08); + // Set "capture on audio sync code" + } + VideoAddr = DecoderReadRWAddr(card,0x080); + if (PTSGetPTS(&card->VideoPTSStore, VideoAddr, + &PTS)) { + card->oldVPTS = card->VPTS; + card->VPTS = PTS; + card->VSCR = ((long)SCR_compareV + - (long)PTS) / 2; +// card->VideoTime = ISRTime; + } + } else if (intr[1] & 0x01) { + // audio sync code detected + DecoderMaskByte(card, 0x011, 0x03, 0x01); + // Set SCR compare/capture mode to capture + DecoderSetByte(card, 0x11, 0x08); + // Set "capture on audio sync code" + AudioAddr = DecoderReadRWAddr(card,0x083); + if (PTSGetPTS(&card->AudioPTSStore, AudioAddr, + &PTS)) { + card->oldAPTS = card->APTS; + card->APTS = PTS; + card->ASCR = ((long)SCR_compareV - + (long)PTS) / 2; + } else { + card->ASCR = 0x7FFFFFFF; + } + + if (card->VSCR != 0x7FFFFFFF) { + if (card->ASCR != 0x7FFFFFFF) { + DeltaSyncTime = ISRTime - + card->SyncTime; + card->SyncTime = ISRTime; + + // Calculate Audio and Video SCR difference + Offset = (card->ASCR - + card->VSCR - + (10 * 736)) / 736; + + // if the APTS and SCR are off update SCR to keep SubPic synced + if ((SCR_compareV > card->APTS) + || ((card->APTS - + SCR_compareV) > + 10000)) { + Offset = 0; + SetSCR(card, + card->APTS); + } + + // if more than 3 frames away + if ((Offset > 3) || + (Offset < -3)) { + if (Offset > 0 ) { + card->videodelay = 0; + if (Offset < 100) { + if (Offset < 10) { + card->videodelay = 1; + } else { + card->videodelay = Offset / 2; + if (card->videodelay > 20) { + card->videodelay = 20; + } + } + MDEBUG(0,": <<< Pausing %d\n", card->videodelay); + } else { + } + } else { + card->videoskip = 0; + if (Offset > -100) { + if (Offset < -10) { + card->videoskip = 10; + } else { + card->videoskip = 3; + } + MDEBUG(0, ": >>> FForward %d\n", card->videoskip); + } + } + } else { + } + card->VSCR = 0x7FFFFFFF; + } + } + } + } + } + DecoderWriteByte(card, 0x006, 0x01); // Clear Interrupt Pin +} + +// Enable the IRQ Masks +void L64021InstallIntr(struct cvdv_cards *card) { + u8 data; + + data=0; + data |= 0x80; // new field + data |= 0x40; // audio sync recovery + data |= 0x20; // SPU SCR compare + // data |= 0x10; // SDRAM Transfer Done + // data |= 0x08; // Sequence End Code Detect + data |= 0x04; // First Slice Start Code + data |= 0x02; // Aux/User Data Fifo + data |= 0x01; // decode status + DecoderWriteByte(card, 0x000, (~data) & 0xFF); + + data = 0; + // data |= 0x80; // SCR compare + // data |= 0x40; // SCR Overflow + // data |= 0x20; // Begin Vertical Blank + data |= 0x10; // Begin Active Video + data |= 0x08; // SPU Start Code Detected + data |= 0x04; // SCR compare audio + data |= 0x02; // picture start code detected + data |= 0x01; // audio sync code detected + DecoderWriteByte(card, 0x001, (~data) & 0xFF); + + data = 0; + // data |= 0x80; // DTS video event + // data |= 0x40; // DTS audio event + data |= 0x20; // DSI PES data ready + // data |= 0x10; // Seq end code in video channel + data |= 0x08; // SPU PES data ready + data |= 0x04; // Video PES data ready + data |= 0x02; // Audio PES data ready + // data |= 0x01; // Pack data ready + DecoderWriteByte(card, 0x002, (~data) & 0xFF); + + data = 0; + // data |= 0x80; // Reserved + data |= 0x40; // CSS + data |= 0x20; // Video ES channel buffer underflow + data |= 0x10; // Audio ES channel buffer underflow + // data |= 0x08; // Data Dump channel PES data ready + data |= 0x04; // SPU channel buffer overflow + //data |= 0x02; // Video ES channel buffer overflow + //data |= 0x01; // Audio ES channel buffer overflow + DecoderWriteByte(card, 0x003, (~data) & 0xFF); + + data = 0; +// data |= 0x80; // S/PDIF channel buffer underflow + // data |= 0x40; // packet error + // data |= 0x20; // reserved + data |= 0x10; // SPU decode error +// data |= 0x08; // Audio Sync error +// data |= 0x04; // Audio CRC or illegal bit error +// data |= 0x02; // context error +// data |= 0x01; // VLC or Run length error + DecoderWriteByte(card, 0x004, (~data) & 0xFF); + card->IntInstalled = 1; +} + +int L64021RemoveIntr(struct cvdv_cards *card) { + // Disable the IRQ Masks + DecoderWriteByte(card, 0x000, 0xFF); // No ints + DecoderWriteByte(card, 0x001, 0xFF); // No ints + DecoderWriteByte(card, 0x002, 0xFF); // No ints + DecoderWriteByte(card, 0x003, 0xFF); // No ints + DecoderWriteByte(card, 0x004, 0xFF); // No ints + card->IntInstalled = 0; + return 0; +} + +int L64021Reset(struct cvdv_cards *card) { + L64021RemoveIntr(card); // Stop interrupts + // Reset + MDEBUG(1, ": L64021 Software reset...\n"); + //DecoderSetByte(card, 0x007, 0x20); // reset on + DecoderMaskByte(card, 0x007, 0xE2, 0xE2); // reset on + while (!(DecoderReadByte(card, 0x007) & 0x02)) ; // wait until reset is done + //DecoderDelByte(card, 0x007, 0x20); // reset off + DecoderMaskByte(card, 0x007, 0xE2, 0xC2); // reset off + MDEBUG(1, ": L64021 Software reset done.\n"); + DecoderStopChannel(card); + DecoderStopDecode(card); + DecoderStreamReset(card); + DecoderSetupReset(card); + printk(KERN_INFO LOGNAME ": L64021 Rev. 0x%02X reset successfully.\n", +DecoderReadByte(card, 0x0F5)); + return 0; +} + +int L64021Setup(struct cvdv_cards *card) { + MDEBUG(1, ": -- L64021Setup\n"); + DecoderWriteByte(card, 0x0C1, 0x88); // + switch (card->videomode) { + case NTSC: // NTSC M, N. America, Taiwan, Japan + DecoderMaskByte(card, 0x122, 0x03, 0x01); // Television Standard: NTSC + /* Default values: + DecoderWriteByte(card, 0x116, 90); // Main Reads per Line + DecoderWriteByte(card, 0x11A, 4); // Vline Count Init + DecoderWriteByte(card, 0x11C, 0x13); // Pixel State Reset Value / BT.656 Mode / Sync Active Low + DecoderWriteByte(card, 0x129, 23); // Start- and End Row + DecoderWriteByte(card, 0x12A, 262 & 0xFF); + DecoderWriteByte(card, 0x12B, (262>>4)&0x70); + DecoderWriteByte(card, 0x12C, 244 & 0xFF); // Start- and End Column + DecoderWriteByte(card, 0x12D, 1683 & 0xFF); + DecoderWriteByte(card, 0x12E, ((1683>>4)&0x70)|((244>>8)&0x07)); + DecoderWriteByte(card, 0x132, 240 & 0xFF); // SAV Column + DecoderWriteByte(card, 0x133, 1684 & 0xFF); // EAV Column + DecoderWriteByte(card, 0x134, ((1684>>4)&0x70)|((240>>8)&0x07)); + DecoderWriteByte(card, 0x12F, (21&0x1F)|((262>>3)&0x20)|(1<<6)|((265>>1)&0x80)); // VCode Zero... + DecoderWriteByte(card, 0x130, 262&0xFF); // ... and VCode Even + DecoderWriteByte(card, 0x131, 265&0xFF); // ... and FCode + */ + break; + case PAL: // PAL-B, D, G, H, I, Europe, Asia + DecoderMaskByte(card, 0x122, 0x03, 0x02); // Television Standard: PAL + /* Default values: + DecoderWriteByte(card, 0x116, 90); // Main Reads per Line + DecoderWriteByte(card, 0x11A, 1); // Vline Count Init + DecoderWriteByte(card, 0x11C, 0x13); // Pixel State Reset Value / BT.656 Mode / Sync Active Low + DecoderWriteByte(card, 0x129, 23); // Start- and End Row + DecoderWriteByte(card, 0x12A, 310 & 0xFF); + DecoderWriteByte(card, 0x12B, (310>>4)&0x70); + DecoderWriteByte(card, 0x12C, 264 & 0xFF); // Start- and End Column + DecoderWriteByte(card, 0x12D, 1703 & 0xFF); + DecoderWriteByte(card, 0x12E, ((1703>>4)&0x70)|((264>>8)&0x07)); + DecoderWriteByte(card, 0x132, 260 & 0xFF); // SAV Column + DecoderWriteByte(card, 0x133, 1704 & 0xFF); // EAV Column + DecoderWriteByte(card, 0x134, ((1704>>4)&0x70)|((260>>8)&0x07)); + DecoderWriteByte(card, 0x12F, (21&0x1F)|((310>>3)&0x20)|(0<<6)|((312>>1)&0x80)); // VCode Zero... + DecoderWriteByte(card, 0x130, 310&0xFF); // ... and VCode Even + DecoderWriteByte(card, 0x131, 312&0xFF); // ... and FCode + */ + break; + case PAL60: // PAL 60Hz + case NTSC60: // NTSC 60Hz, USA HDTV + case PALM: // PAL-M normal, Brazil + case PALM60: // PAL-M HDTV, Brazil + case PALN: // PAL-N, Uruguay, Paraguay + case PALNc: // PAL-Nc, Argentinia + default: // TODO: set mode according to other standards + DecoderMaskByte(card, 0x122, 0x03, 0x00); // Television Standard: User programmed + DecoderWriteByte(card, 0x116, 90); // Main Reads per Line + DecoderWriteByte(card, 0x11A, 1); // Vline Count Init + DecoderWriteByte(card, 0x11C, 0x13); // Pixel State Reset Value / BT.656 Mode / Sync Active Low + DecoderWriteByte(card, 0x129, 23); // Start- and End Row + DecoderWriteByte(card, 0x12A, 310 & 0xFF); + DecoderWriteByte(card, 0x12B, (310>>4)&0x70); + DecoderWriteByte(card, 0x12C, 264 & 0xFF); // Start- and End Column + DecoderWriteByte(card, 0x12D, 1703 & 0xFF); + DecoderWriteByte(card, 0x12E, ((1703>>4)&0x70)|((264>>8)&0x07)); + DecoderWriteByte(card, 0x132, 260 & 0xFF); // SAV Column + DecoderWriteByte(card, 0x133, 1704 & 0xFF); // EAV Column + DecoderWriteByte(card, 0x134, ((1704>>4)&0x70)|((260>>8)&0x07)); + DecoderWriteByte(card, 0x12F, (21&0x1F)|((310>>3)&0x20)|(0<<6)|((312>>1)&0x80)); // VCode Zero... + DecoderWriteByte(card, 0x130, 310&0xFF); // ... and VCode Even + DecoderWriteByte(card, 0x131, 312&0xFF); // ... and FCode + break; + } + DecoderWriteByte(card, 0x045, 0x00); // disable compares and panic mode + DecoderWriteByte(card, 0x094, 0x00); // disable TOS Detect + DecoderMaskByte(card, 0x109, 0x30, 0x00); // Display Override off, don't change OSD, Background + DecoderWriteByte(card, 0x112, 0x00); // Disable Horizontal 2:1 Filter + DecoderWriteByte(card, 0x113, 0x14); // FreezeMode 1 / 3:2 Pulldown / Repeat First Field / Top Field First + DecoderWriteByte(card, 0x114, ( 5 <<3)|( 0 <<1)|( 0 <<2)|( 1 <<7)); // VideoMode/FilterEnable/FilterAB/FieldSyncEnable + DecoderWriteByte(card, 0x115, 0); // Horizontal Filter Scale + DecoderWriteByte(card, 0x117, 0x80); // Automatic Field Inversion Correction +// DecoderWriteByte(card, 0x117, 0x00); // no Automatic Field Inversion Correction + DecoderWriteByte(card, 0x118, 0); // Horizontal Pan and Scan Word Offset (signed) + DecoderWriteByte(card, 0x119, 0); // Vertical Pan and Scan Line Offset + DecoderWriteByte(card, 0x11B, 0x00); // Override Picture Width +// if (0) { // letterbox +// DecoderWriteByte(card, 0x114, (DecoderReadByte(card, 0x114) & ~0x78) | 0x40); // mode 8 +// DecoderWriteByte(card, 0x129, 0x35); +// DecoderWriteByte(card, 0x12A, 0xE7); +// DecoderWriteByte(card, 0x114, DecoderReadByte(card, 0x114) & ~0x77); // ??? +// } else { +// if (0) { // MPEG-1 +// DecoderWriteByte(card, 0x114, (DecoderReadByte(card, 0x114) & ~0x78) | 0x10); // mode 2 +// } else { // MPEG-2 +// DecoderWriteByte(card, 0x114, (DecoderReadByte(card, 0x114) & ~0x78) | 0x28); // mode 5 +// } +// } + L64021InstallIntr(card); // Set the interrupt masks, again + + return 0; +} + +int L64021Init(struct cvdv_cards *card) { +MDEBUG(1, ": -- L64021Init\n"); + L64021Reset(card); + L64021Setup(card); + VideoSetBackground(card, 1, 0, 0, 0); // black + DecoderWriteByte(card, 0x135, 0x01); // Enable Video Out, Disable SPU Mix + DecoderWriteByte(card,0x11C,0x13); // Pixel State Reset Value / BT.656 Mode / Sync Active Low + L64021InstallIntr(card); + return 0; +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/decoder.h linux.20pre2-ac1/drivers/media/video/margi/decoder.h --- linux.20pre2/drivers/media/video/margi/decoder.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/decoder.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,70 @@ +/* + decoder.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CVDV_DECODER_H +#define CVDV_DECODER_H + +#include "cardbase.h" + + +int DecoderGetNavi(struct cvdv_cards *card, u8 * navidata); + +// returns 1 on overrun, 0 on no error +int DecoderQueueNavi(struct cvdv_cards *card, u8 * navidata); + +u32 ParseSCR(const u8 * scrdata); + +u32 SetSCR(struct cvdv_cards *card, u32 SCR_base); + +void DecoderPause(struct cvdv_cards *card); + +void DecoderUnPause(struct cvdv_cards *card); + +void CloseCard(struct cvdv_cards *card); + + +void DecoderReadAudioInfo(struct cvdv_cards *card); + +void DecoderReadAuxFifo(struct cvdv_cards *card); + +void DecoderReadDataFifo(struct cvdv_cards *card); + +int DecoderReadNavipack(struct cvdv_cards *card); + +int AudioStart(struct cvdv_cards *card); + +// Puts decoder in pause after so many fields +void StepsToPause(struct cvdv_cards *card, int steps); + +void L64021Intr(struct cvdv_cards *card); +//static void L64021Intr(struct cvdv_cards *card); + +// Enable the IRQ Masks +void L64021InstallIntr(struct cvdv_cards *card); + +int L64021RemoveIntr(struct cvdv_cards *card); + +int L64021Reset(struct cvdv_cards *card); + +int L64021Setup(struct cvdv_cards *card); + +int L64021Init(struct cvdv_cards *card); + +#endif /* CVDV_DECODER_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dmxdev.c linux.20pre2-ac1/drivers/media/video/margi/dmxdev.c --- linux.20pre2/drivers/media/video/margi/dmxdev.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dmxdev.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1065 @@ +/* + * dmxdev.c - DVB demultiplexer device + * + * Copyright (C) 2000 Ralph Metzler + * & Marcus Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include + +#include "cardbase.h" +#include "dmxdev.h" + +#ifdef MODULE +MODULE_DESCRIPTION(""); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +MODULE_PARM(debug,"i"); +#endif +static int debug = 0; + +#define dprintk if (debug) printk + +inline dmxdev_filter_t * +DmxDevFile2Filter(dmxdev_t *dmxdev, struct file *file) +{ + return (dmxdev_filter_t *) file->private_data; +} + +inline dmxdev_dvr_t * +DmxDevFile2DVR(dmxdev_t *dmxdev, struct file *file) +{ + return (dmxdev_dvr_t *) file->private_data; +} + +static inline void +DmxDevBufferInit(dmxdev_buffer_t *buffer) +{ + buffer->data=0; + buffer->size=8192; + buffer->pread=0; + buffer->pwrite=0; + buffer->error=0; + init_waitqueue_head(&buffer->queue); +} + +static inline int +DmxDevBufferWrite(dmxdev_buffer_t *buf, uint8_t *src, int len) +{ + int split; + int free; + int todo; + + if (!len) + return 0; + if (!buf->data) + return 0; + + free=buf->pread-buf->pwrite; + split=0; + if (free<=0) { + free+=buf->size; + split=buf->size-buf->pwrite; + } + if (len>=free) { + dprintk("dmxdev: buffer overflow\n"); + return -1; + } + if (split>=len) + split=0; + todo=len; + if (split) { + memcpy(buf->data + buf->pwrite, src, split); + todo-=split; + buf->pwrite=0; + } + memcpy(buf->data + buf->pwrite, src+split, todo); + buf->pwrite=(buf->pwrite+todo)%buf->size; + return len; +} + +static ssize_t +DmxDevBufferRead(dmxdev_buffer_t *src, int non_blocking, + char *buf, size_t count, loff_t *ppos) +{ + unsigned long todo=count; + int split, avail, error; + + if (!src->data) + return 0; + if ((error=src->error)) { + src->error=0; + return error; + } + + if (non_blocking && (src->pwrite==src->pread)) + return -EWOULDBLOCK; + + while (todo>0) { + if (non_blocking && (src->pwrite==src->pread)) + return (count-todo) ? (count-todo) : -EWOULDBLOCK; + + if (wait_event_interruptible(src->queue, + (src->pread!=src->pwrite) || + (src->error))<0) + return count-todo; + + if ((error=src->error)) { + src->error=0; + return error; + } + + split=src->size; + avail=src->pwrite - src->pread; + if (avail<0) { + avail+=src->size; + split=src->size - src->pread; + } + if (avail>todo) + avail=todo; + if (splitdata+src->pread, split)) + return -EFAULT; + buf+=split; + src->pread=0; + todo-=split; + avail-=split; + } + if (avail) { + if (copy_to_user(buf, src->data+src->pread, avail)) + return -EFAULT; + src->pread = (src->pread + avail) % src->size; + todo-=avail; + buf+=avail; + } + } + return count; +} + +static dmx_frontend_t * +get_fe(dmx_demux_t *demux, int type) +{ + struct list_head *head, *pos; + + head=demux->get_frontends(demux); + if (!head) + return 0; + list_for_each(pos, head) + if (DMX_FE_ENTRY(pos)->source==type) + return DMX_FE_ENTRY(pos); + + return 0; +} + +static inline void +DmxDevDVRStateSet(dmxdev_dvr_t *dmxdevdvr, int state) +{ + spin_lock_irq(&dmxdevdvr->dev->lock); + dmxdevdvr->state=state; + spin_unlock_irq(&dmxdevdvr->dev->lock); +} + +int +DmxDevDVROpen(dmxdev_t *dmxdev, struct file *file) +{ + dmx_frontend_t *front; + + down(&dmxdev->mutex); + if ((file->f_flags&O_ACCMODE)==O_RDWR) { + if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) { + up(&dmxdev->mutex); + return -EOPNOTSUPP; + } + } + + if ((file->f_flags&O_ACCMODE)==O_RDONLY) { + DmxDevBufferInit(&dmxdev->dvr_buffer); + dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE; + dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE); + if (!dmxdev->dvr_buffer.data) { + up(&dmxdev->mutex); + return -ENOMEM; + } + } + + if ((file->f_flags&O_ACCMODE)==O_WRONLY) { + dmxdev->dvr_orig_fe=dmxdev->demux->frontend; + + if (!dmxdev->demux->write) { + up(&dmxdev->mutex); + return -EOPNOTSUPP; + } + + front=get_fe(dmxdev->demux, DMX_MEMORY_FE); + + if (!front) { + up(&dmxdev->mutex); + return -EINVAL; + } + dmxdev->demux->disconnect_frontend(dmxdev->demux); + dmxdev->demux->connect_frontend(dmxdev->demux, front); + } + up(&dmxdev->mutex); + return 0; +} + +int +DmxDevDVRClose(dmxdev_t *dmxdev, struct file *file) +{ + down(&dmxdev->mutex); + if ((file->f_flags&O_ACCMODE)==O_WRONLY) { + dmxdev->demux->disconnect_frontend(dmxdev->demux); + dmxdev->demux->connect_frontend(dmxdev->demux, + dmxdev->dvr_orig_fe); + } + if ((file->f_flags&O_ACCMODE)==O_RDONLY) { + if (dmxdev->dvr_buffer.data) { + void *mem=dmxdev->dvr_buffer.data; + mb(); + spin_lock_irq(&dmxdev->lock); + dmxdev->dvr_buffer.data=0; + spin_unlock_irq(&dmxdev->lock); + vfree(mem); + } + } + up(&dmxdev->mutex); + return 0; +} + +ssize_t +DmxDevDVRWrite(dmxdev_t *dmxdev, struct file *file, + const char *buf, size_t count, loff_t *ppos) +{ + int ret; + + if (!dmxdev->demux->write) + return -EOPNOTSUPP; + if ((file->f_flags&O_ACCMODE)!=O_WRONLY) + return -EINVAL; + down(&dmxdev->mutex); + ret=dmxdev->demux->write(dmxdev->demux, buf, count); + up(&dmxdev->mutex); + return ret; +} + +ssize_t +DmxDevDVRRead(dmxdev_t *dmxdev, struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int ret; + + down(&dmxdev->mutex); + ret= DmxDevBufferRead(&dmxdev->dvr_buffer, + file->f_flags&O_NONBLOCK, + buf, count, ppos); + up(&dmxdev->mutex); + return ret; +} + +static inline void +DmxDevFilterStateSet(dmxdev_filter_t *dmxdevfilter, int state) +{ + spin_lock_irq(&dmxdevfilter->dev->lock); + dmxdevfilter->state=state; + spin_unlock_irq(&dmxdevfilter->dev->lock); +} + +static int +DmxDevSetBufferSize(dmxdev_filter_t *dmxdevfilter, unsigned long size) +{ + dmxdev_buffer_t *buf=&dmxdevfilter->buffer; + + if (buf->size==size) + return 0; + if (dmxdevfilter->state>=DMXDEV_STATE_GO) + return -EBUSY; + spin_lock_irq(&dmxdevfilter->dev->lock); + if (buf->data) + vfree(buf->data); + buf->data=0; + buf->size=size; + buf->pwrite=buf->pread=0; + spin_unlock_irq(&dmxdevfilter->dev->lock); + + if (buf->size) { + void *mem=vmalloc(dmxdevfilter->buffer.size); + + if (!mem) + return -ENOMEM; + spin_lock_irq(&dmxdevfilter->dev->lock); + buf->data=mem; + spin_unlock_irq(&dmxdevfilter->dev->lock); + } + return 0; +} + +static void +DmxDevFilterTimeout(unsigned long data) +{ + dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *)data; + + dmxdevfilter->buffer.error=-ETIMEDOUT; + spin_lock_irq(&dmxdevfilter->dev->lock); + dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT; + spin_unlock_irq(&dmxdevfilter->dev->lock); + wake_up(&dmxdevfilter->buffer.queue); +} + +static void +DmxDevFilterTimer(dmxdev_filter_t *dmxdevfilter) +{ + struct dmxSctFilterParams *para=&dmxdevfilter->params.sec; + + del_timer(&dmxdevfilter->timer); + if (para->timeout) { + dmxdevfilter->timer.function=DmxDevFilterTimeout; + dmxdevfilter->timer.data=(unsigned long) dmxdevfilter; + dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000; + add_timer(&dmxdevfilter->timer); + } +} + +static int +DmxDevSectionCallback(u8 *buffer1, size_t buffer1_len, + u8 *buffer2, size_t buffer2_len, + dmx_section_filter_t *filter, + dmx_success_t success) +{ + dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *) filter->priv; + int ret; + + if (dmxdevfilter->buffer.error) + return 0; + spin_lock(&dmxdevfilter->dev->lock); + if (dmxdevfilter->state!=DMXDEV_STATE_GO) { + spin_unlock(&dmxdevfilter->dev->lock); + return 0; + } + del_timer(&dmxdevfilter->timer); + dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", + buffer1[0], buffer1[1], + buffer1[2], buffer1[3], + buffer1[4], buffer1[5]); + ret=DmxDevBufferWrite(&dmxdevfilter->buffer, buffer1, buffer1_len); + if (ret==buffer1_len) { + ret=DmxDevBufferWrite(&dmxdevfilter->buffer, buffer2, buffer2_len); + } + if (ret<0) { + dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread; + dmxdevfilter->buffer.error=-EBUFFEROVERFLOW; + } + if (dmxdevfilter->params.sec.flags&DMX_ONESHOT) + dmxdevfilter->state=DMXDEV_STATE_DONE; + spin_unlock(&dmxdevfilter->dev->lock); + wake_up(&dmxdevfilter->buffer.queue); + return 0; +} + +static int +DmxDevTSCallback(u8 *buffer1, size_t buffer1_len, + u8 *buffer2, size_t buffer2_len, + dmx_ts_feed_t *feed, + dmx_success_t success) +{ + dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *) feed->priv; + dmxdev_buffer_t *buffer; + int ret; + + if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) + return 0; + + if (dmxdevfilter->params.pes.output==DMX_OUT_TAP) + buffer=&dmxdevfilter->buffer; + else + buffer=&dmxdevfilter->dev->dvr_buffer; + if (buffer->error) { + wake_up(&buffer->queue); + return 0; + } + ret=DmxDevBufferWrite(buffer, buffer1, buffer1_len); + if (ret==buffer1_len) + ret=DmxDevBufferWrite(buffer, buffer2, buffer2_len); + if (ret<0) { + buffer->pwrite=buffer->pread; + buffer->error=-EBUFFEROVERFLOW; + } + wake_up(&buffer->queue); + return 0; +} + + +/* stop feed but only mark the specified filter as stopped (state set) */ + +static int +DmxDevFeedStop(dmxdev_filter_t *dmxdevfilter) +{ + DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_SET); + + switch (dmxdevfilter->type) { + case DMXDEV_TYPE_SEC: + del_timer(&dmxdevfilter->timer); + dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); + break; + case DMXDEV_TYPE_PES: + dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts); + break; + default: + return -EINVAL; + } + return 0; +} + + +/* start feed associated with the specified filter */ + +static int +DmxDevFeedStart(dmxdev_filter_t *dmxdevfilter) +{ + DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_GO); + + switch (dmxdevfilter->type) { + case DMXDEV_TYPE_SEC: + dmxdevfilter->feed.sec->start_filtering(dmxdevfilter->feed.sec); + break; + case DMXDEV_TYPE_PES: + dmxdevfilter->feed.ts->start_filtering(dmxdevfilter->feed.ts); + break; + default: + return -EINVAL; + } + return 0; +} + + +/* restart section feed if it has filters left associated with it, + otherwise release the feed */ + +static int +DmxDevFeedRestart(dmxdev_filter_t *dmxdevfilter) +{ + int i; + dmxdev_t *dmxdev=dmxdevfilter->dev; + dvb_pid_t pid=dmxdevfilter->params.sec.pid; + + for (i=0; ifilternum; i++) + if (dmxdev->filter[i].state>=DMXDEV_STATE_GO && + dmxdev->filter[i].type==DMXDEV_TYPE_SEC && + dmxdev->filter[i].pid==pid) { + DmxDevFeedStart(&dmxdev->filter[i]); + return 0; + } + + dmxdevfilter->dev->demux-> + release_section_feed(dmxdev->demux, + dmxdevfilter->feed.sec); + + return 0; +} + +static int +DmxDevFilterStop(dmxdev_filter_t *dmxdevfilter) +{ + if (dmxdevfilter->statetype) { + case DMXDEV_TYPE_SEC: + if (!dmxdevfilter->feed.sec) + break; + DmxDevFeedStop(dmxdevfilter); + if (dmxdevfilter->filter.sec) + dmxdevfilter->feed.sec-> + release_filter(dmxdevfilter->feed.sec, + dmxdevfilter->filter.sec); + DmxDevFeedRestart(dmxdevfilter); + dmxdevfilter->feed.sec=0; + break; + case DMXDEV_TYPE_PES: + if (!dmxdevfilter->feed.ts) + break; + DmxDevFeedStop(dmxdevfilter); + dmxdevfilter->dev->demux-> + release_ts_feed(dmxdevfilter->dev->demux, + dmxdevfilter->feed.ts); + dmxdevfilter->feed.ts=0; + break; + default: + if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED) + return 0; + return -EINVAL; + } + dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0; + return 0; +} + +static inline int +DmxDevFilterReset(dmxdev_filter_t *dmxdevfilter) +{ + if (dmxdevfilter->statetype=DMXDEV_TYPE_NONE; + dmxdevfilter->pid=0xffff; + DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_ALLOCATED); + return 0; +} + +static int +DmxDevFilterStart(dmxdev_filter_t *dmxdevfilter) +{ + dmxdev_t *dmxdev=dmxdevfilter->dev; + void *mem; + int ret, i; + + if (dmxdevfilter->statestate>=DMXDEV_STATE_GO) + DmxDevFilterStop(dmxdevfilter); + + mem=dmxdevfilter->buffer.data; + if (!mem) { + mem=vmalloc(dmxdevfilter->buffer.size); + spin_lock_irq(&dmxdevfilter->dev->lock); + dmxdevfilter->buffer.data=mem; + spin_unlock_irq(&dmxdevfilter->dev->lock); + if (!dmxdevfilter->buffer.data) + return -ENOMEM; + } + + switch (dmxdevfilter->type) { + case DMXDEV_TYPE_SEC: + { + struct dmxSctFilterParams *para=&dmxdevfilter->params.sec; + dmx_section_filter_t **secfilter=&dmxdevfilter->filter.sec; + dmx_section_feed_t **secfeed=&dmxdevfilter->feed.sec; + + *secfilter=0; + *secfeed=0; + + /* find active filter/feed with same PID */ + for (i=0; ifilternum; i++) + if (dmxdev->filter[i].state>=DMXDEV_STATE_GO && + dmxdev->filter[i].pid==para->pid) { + if (dmxdev->filter[i].type!=DMXDEV_TYPE_SEC) + return -EBUSY; + *secfeed=dmxdev->filter[i].feed.sec; + break; + } + + /* if no feed found, try to allocate new one */ + if (!*secfeed) { + ret=dmxdev->demux-> + allocate_section_feed(dmxdev->demux, + secfeed, + DmxDevSectionCallback); + if (ret<0) { + printk ("could not alloc feed\n"); + return ret; + } + + ret=(*secfeed)->set(*secfeed, para->pid, 32768, 0, + (para->flags & DMX_CHECK_CRC) ? 1 : 0); + + if (ret<0) { + printk ("could not set feed\n"); + DmxDevFeedRestart(dmxdevfilter); + return ret; + } + } + else + DmxDevFeedStop(dmxdevfilter); + + ret=(*secfeed)->allocate_filter(*secfeed, secfilter); + if (ret<0) { + DmxDevFeedRestart(dmxdevfilter); + dmxdevfilter->feed.sec-> + start_filtering(*secfeed); + dprintk ("could not get filter\n"); + return ret; + } + + (*secfilter)->priv=(void *) dmxdevfilter; + memcpy(&((*secfilter)->filter_value[3]), + &(para->filter.filter[1]), DMX_FILTER_SIZE-1); + memcpy(&(*secfilter)->filter_mask[3], + ¶->filter.mask[1], DMX_FILTER_SIZE-1); + (*secfilter)->filter_value[0]=para->filter.filter[0]; + (*secfilter)->filter_mask[0]=para->filter.mask[0]; + (*secfilter)->filter_mask[1]=0; + (*secfilter)->filter_mask[2]=0; + + dmxdevfilter->todo=0; + dmxdevfilter->feed.sec-> + start_filtering(dmxdevfilter->feed.sec); + DmxDevFilterTimer(dmxdevfilter); + break; + } + + case DMXDEV_TYPE_PES: + { + struct timespec timeout = {0 }; + struct dmxPesFilterParams *para=&dmxdevfilter->params.pes; + dmxOutput_t otype; + int ret; + int ts_type; + dmx_ts_pes_t ts_pes; + dmx_ts_feed_t **tsfeed=&dmxdevfilter->feed.ts; + + dmxdevfilter->feed.ts=0; + otype=para->output; + + ts_pes=(dmx_ts_pes_t) para->pesType; + + if (ts_pesdemux->allocate_ts_feed(dmxdev->demux, + tsfeed, + DmxDevTSCallback); + if (ret<0) + return ret; + + (*tsfeed)->priv=(void *) dmxdevfilter; + ret=(*tsfeed)->set(*tsfeed, para->pid, 188, 32768, 0, timeout); + if (ret<0) { + dmxdev->demux-> + release_ts_feed(dmxdev->demux, *tsfeed); + return ret; + } + if ((*tsfeed)->set_type) + ret=(*tsfeed)->set_type(*tsfeed, ts_type, ts_pes); + if (ret<0) { + dmxdev->demux-> + release_ts_feed(dmxdev->demux, *tsfeed); + return ret; + } + dmxdevfilter->feed.ts-> + start_filtering(dmxdevfilter->feed.ts); + break; + } + default: + return -EINVAL; + } + DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_GO); + return 0; +} + +int +DmxDevFilterNum(dmxdev_t *dmxdev) +{ + int i, num; + + if (!dmxdev->filter) + return 0; + down(&dmxdev->mutex); + for (i=0, num=0; ifilternum; i++) + if (dmxdev->filter[i].state==DMXDEV_STATE_FREE) + num++; + up(&dmxdev->mutex); + return num; +} + +int +DmxDevFilterAlloc(dmxdev_t *dmxdev, struct file *file) +{ + int i; + dmxdev_filter_t *dmxdevfilter; + + if (!dmxdev->filter) + return -EINVAL; + down(&dmxdev->mutex); + for (i=0; ifilternum; i++) + if (dmxdev->filter[i].state==DMXDEV_STATE_FREE) + break; + if (i==dmxdev->filternum) { + up(&dmxdev->mutex); + return -EMFILE; + } + dmxdevfilter=&dmxdev->filter[i]; + file->private_data=dmxdevfilter; + + DmxDevBufferInit(&dmxdevfilter->buffer); + dmxdevfilter->type=DMXDEV_TYPE_NONE; + DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_ALLOCATED); + dmxdevfilter->feed.ts=0; + init_timer(&dmxdevfilter->timer); + + up(&dmxdev->mutex); + //printk("free filters = %d\n", DmxDevFilterNum(dmxdev)); + return 0; +} + +int +DmxDevFilterFree(dmxdev_t *dmxdev, struct file *file) +{ + dmxdev_filter_t *dmxdevfilter; + + down(&dmxdev->mutex); + + if (!(dmxdevfilter=DmxDevFile2Filter(dmxdev, file))) { + up(&dmxdev->mutex); + return -EINVAL; + } + + DmxDevFilterStop(dmxdevfilter); + DmxDevFilterReset(dmxdevfilter); + + if (dmxdevfilter->buffer.data) { + void *mem=dmxdevfilter->buffer.data; + + spin_lock_irq(&dmxdev->lock); + dmxdevfilter->buffer.data=0; + spin_unlock_irq(&dmxdev->lock); + vfree(mem); + } + DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_FREE); + wake_up(&dmxdevfilter->buffer.queue); + up(&dmxdev->mutex); + //printk("free filters = %d\n", DmxDevFilterNum(dmxdev)); + return 0; +} + + +static int +DmxDevFilterSet(dmxdev_t *dmxdev, + dmxdev_filter_t *dmxdevfilter, + struct dmxSctFilterParams *params) +{ + dprintk ("function : %s\n", __FUNCTION__); + + DmxDevFilterStop(dmxdevfilter); + + dmxdevfilter->type=DMXDEV_TYPE_SEC; + dmxdevfilter->pid=params->pid; + memcpy(&dmxdevfilter->params.sec, + params, sizeof(struct dmxSctFilterParams)); + + DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_SET); + + if (params->flags&DMX_IMMEDIATE_START) + return DmxDevFilterStart(dmxdevfilter); + + return 0; +} + +static int +DmxDevPesFilterSet(dmxdev_t *dmxdev, + dmxdev_filter_t *dmxdevfilter, + struct dmxPesFilterParams *params) +{ + DmxDevFilterStop(dmxdevfilter); + + if (params->pesType>DMX_PES_OTHER || params->pesType<0) + return -EINVAL; + + dmxdevfilter->type=DMXDEV_TYPE_PES; + dmxdevfilter->pid=params->pid; + memcpy(&dmxdevfilter->params, params, sizeof(struct dmxPesFilterParams)); + + DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_SET); + + if (params->flags&DMX_IMMEDIATE_START) + return DmxDevFilterStart(dmxdevfilter); + + return 0; +} + +int +DmxDevInit(dmxdev_t *dmxdev) +{ + int i; + + if (dmxdev->demux->open(dmxdev->demux)<0) + return -EUSERS; + + dmxdev->filter=vmalloc(dmxdev->filternum*sizeof(dmxdev_filter_t)); + if (!dmxdev->filter) + return -ENOMEM; + + dmxdev->dvr=vmalloc(dmxdev->filternum*sizeof(dmxdev_dvr_t)); + if (!dmxdev->dvr) { + vfree(dmxdev->filter); + dmxdev->filter=0; + return -ENOMEM; + } + sema_init(&dmxdev->mutex, 1); + spin_lock_init(&dmxdev->lock); + for (i=0; ifilternum; i++) { + dmxdev->filter[i].dev=dmxdev; + dmxdev->filter[i].buffer.data=0; + DmxDevFilterStateSet(&dmxdev->filter[i], DMXDEV_STATE_FREE); + dmxdev->dvr[i].dev=dmxdev; + dmxdev->dvr[i].buffer.data=0; + DmxDevFilterStateSet(&dmxdev->filter[i], DMXDEV_STATE_FREE); + DmxDevDVRStateSet(&dmxdev->dvr[i], DMXDEV_STATE_FREE); + } + DmxDevBufferInit(&dmxdev->dvr_buffer); + MOD_INC_USE_COUNT; + return 0; +} + +void +DmxDevRelease(dmxdev_t *dmxdev) +{ + if (dmxdev->filter) { + vfree(dmxdev->filter); + dmxdev->filter=0; + } + if (dmxdev->dvr) { + vfree(dmxdev->dvr); + dmxdev->dvr=0; + } + dmxdev->demux->close(dmxdev->demux); + MOD_DEC_USE_COUNT; +} + +static ssize_t +DmxDevReadSec(dmxdev_filter_t *dfil, struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + int result, hcount; + int done=0; + + if (dfil->todo<=0) { + hcount=3+dfil->todo; + if (hcount>count) + hcount=count; + result=DmxDevBufferRead(&dfil->buffer, file->f_flags&O_NONBLOCK, + buf, hcount, ppos); + if (result<0) { + dfil->todo=0; + return result; + } + if (copy_from_user(dfil->secheader-dfil->todo, buf, result)) + return -EFAULT; + buf+=result; + done=result; + count-=result; + dfil->todo-=result; + if (dfil->todo>-3) + return done; + dfil->todo=((dfil->secheader[1]<<8)|dfil->secheader[2])&0xfff; + if (!count) + return done; + } + if (count>dfil->todo) + count=dfil->todo; + result=DmxDevBufferRead(&dfil->buffer, file->f_flags&O_NONBLOCK, + buf, count, ppos); + if (result<0) + return result; + dfil->todo-=result; + return (result+done); +} + + +ssize_t +DmxDevRead(dmxdev_t *dmxdev, struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + dmxdev_filter_t *dmxdevfilter=DmxDevFile2Filter(dmxdev, file); + int ret=0; + + down(&dmxdev->mutex); + if (dmxdevfilter->type==DMXDEV_TYPE_SEC) + ret=DmxDevReadSec(dmxdevfilter, file, buf, count, ppos); + else + ret=DmxDevBufferRead(&dmxdevfilter->buffer, + file->f_flags&O_NONBLOCK, + buf, count, ppos); + up(&dmxdev->mutex); + return ret; +} + + +int DmxDevIoctl(dmxdev_t *dmxdev, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void *parg=(void *)arg; + int ret=0; + + dmxdev_filter_t *dmxdevfilter=DmxDevFile2Filter(dmxdev, file); + + if (!dmxdevfilter) + return -EINVAL; + + down(&dmxdev->mutex); + switch (cmd) { + case DMX_START: + if (dmxdevfilter->statedemux->get_pes_pids) { + ret=-EINVAL; + break; + } + dmxdev->demux->get_pes_pids(dmxdev->demux, pids); + if (copy_to_user(parg, pids, 5*sizeof(dvb_pid_t))) + ret=-EFAULT; + break; + } + + default: + ret=-EINVAL; + } + up(&dmxdev->mutex); + return ret; +} + +unsigned int +DmxDevPoll(dmxdev_t *dmxdev, struct file *file, poll_table * wait) +{ + dmxdev_filter_t *dmxdevfilter=DmxDevFile2Filter(dmxdev, file); + + if (!dmxdevfilter) + return -EINVAL; + + if (dmxdevfilter->state==DMXDEV_STATE_FREE) + return 0; + + if (dmxdevfilter->buffer.pread!=dmxdevfilter->buffer.pwrite || + dmxdevfilter->buffer.error) + return (POLLIN | POLLRDNORM | POLLPRI); + + if (dmxdevfilter->state!=DMXDEV_STATE_GO) + return 0; + + poll_wait(file, &dmxdevfilter->buffer.queue, wait); + + if (dmxdevfilter->state==DMXDEV_STATE_FREE) + return 0; + + if (dmxdevfilter->buffer.pread!=dmxdevfilter->buffer.pwrite || + dmxdevfilter->buffer.error) + return (POLLIN | POLLRDNORM | POLLPRI); + + return 0; +} + +int DmxDevDVRIoctl(dmxdev_t *dmxdev, struct file *file, + unsigned int cmd, unsigned long arg) +{ + //void *parg=(void *)arg; + int ret=0; + + down(&dmxdev->mutex); + switch (cmd) { + case DMX_SET_BUFFER_SIZE: + // FIXME: implement + ret=0; + break; + + default: + ret=-EINVAL; + } + up(&dmxdev->mutex); + return ret; +} + +unsigned int +DmxDevDVRPoll(dmxdev_t *dmxdev, struct file *file, poll_table * wait) +{ + if ((file->f_flags&O_ACCMODE)==O_RDONLY) { + if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite) + return (POLLIN | POLLRDNORM | POLLPRI); + + poll_wait(file, &dmxdev->dvr_buffer.queue, wait); + + if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite) + return (POLLIN | POLLRDNORM | POLLPRI); + + return 0; + } else + return (POLLOUT | POLLWRNORM | POLLPRI); +} + + +#ifdef MODULE +#ifdef EXPORT_SYMTAB +EXPORT_SYMBOL(DmxDevInit); +EXPORT_SYMBOL(DmxDevRelease); + +EXPORT_SYMBOL(DmxDevDVROpen); +EXPORT_SYMBOL(DmxDevDVRClose); +EXPORT_SYMBOL(DmxDevDVRRead); +EXPORT_SYMBOL(DmxDevDVRWrite); +EXPORT_SYMBOL(DmxDevDVRIoctl); +EXPORT_SYMBOL(DmxDevDVRPoll); + +EXPORT_SYMBOL(DmxDevFilterAlloc); +EXPORT_SYMBOL(DmxDevFilterFree); +EXPORT_SYMBOL(DmxDevRead); +EXPORT_SYMBOL(DmxDevIoctl); +EXPORT_SYMBOL(DmxDevPoll); +#endif +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dmxdev.h linux.20pre2-ac1/drivers/media/video/margi/dmxdev.h --- linux.20pre2/drivers/media/video/margi/dmxdev.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dmxdev.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,154 @@ +/* + * dmxdev.h + * + * Copyright (C) 2000 Ralph Metzler + * & Marcus Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _DMXDEV_H_ +#define _DMXDEV_H_ + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#ifdef __DVB_PACK__ +#include "ost/demux.h" +#include "ost/dmx.h" +#else +#include +#include +#endif +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < 0x020300 +#define WAIT_QUEUE struct wait_queue* +#define init_waitqueue_head(wq) *(wq) = NULL; +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) +#else +#define WAIT_QUEUE wait_queue_head_t +#endif + +typedef enum { + DMXDEV_TYPE_NONE, + DMXDEV_TYPE_SEC, + DMXDEV_TYPE_PES, +} dmxdev_type_t; + +typedef enum { + DMXDEV_STATE_FREE, + DMXDEV_STATE_ALLOCATED, + DMXDEV_STATE_SET, + DMXDEV_STATE_GO, + DMXDEV_STATE_DONE, + DMXDEV_STATE_TIMEDOUT +} dmxdev_state_t; + +typedef struct dmxdev_buffer_s { + uint8_t *data; + uint32_t size; + int32_t pread; + int32_t pwrite; + WAIT_QUEUE queue; + int error; +} dmxdev_buffer_t; + + +typedef struct dmxdev_filter_s { + union { + dmx_pes_filter_t *pes; + dmx_section_filter_t *sec; + } filter; + + union { + dmx_ts_feed_t *ts; + dmx_section_feed_t *sec; + } feed; + + union { + struct dmxSctFilterParams sec; + struct dmxPesFilterParams pes; + } params; + + int type; + dmxdev_state_t state; + struct dmxdev_s *dev; + dmxdev_buffer_t buffer; + + // only for sections + struct timer_list timer; + int todo; + uint8_t secheader[3]; + + u16 pid; +} dmxdev_filter_t; + + +typedef struct dmxdev_dvr_s { + int state; + struct dmxdev_s *dev; + dmxdev_buffer_t buffer; +} dmxdev_dvr_t; + + +typedef struct dmxdev_s { + dmxdev_filter_t *filter; + dmxdev_dvr_t *dvr; + dmx_demux_t *demux; + + int filternum; + int capabilities; +#define DMXDEV_CAP_DUPLEX 1 + dmx_frontend_t *dvr_orig_fe; + + dmxdev_buffer_t dvr_buffer; +#define DVR_BUFFER_SIZE (512*1024) + + struct semaphore mutex; + spinlock_t lock; +} dmxdev_t; + + +int DmxDevInit(dmxdev_t *dmxdev); +void DmxDevRelease(dmxdev_t *dmxdev); + +int DmxDevFilterAlloc(dmxdev_t *dmxdev, struct file *file); +int DmxDevFilterFree(dmxdev_t *dmxdev, struct file *file); +int DmxDevIoctl(dmxdev_t *dmxdev, struct file *file, + unsigned int cmd, unsigned long arg); +unsigned int DmxDevPoll(dmxdev_t *dmxdev, struct file *file, poll_table * wait); +ssize_t DmxDevRead(dmxdev_t *dmxdev, struct file *file, + char *buf, size_t count, loff_t *ppos); + +int DmxDevDVROpen(dmxdev_t *dmxdev, struct file *file); +int DmxDevDVRClose(dmxdev_t *dmxdev, struct file *file); +ssize_t DmxDevDVRWrite(dmxdev_t *dmxdev, struct file *file, + const char *buf, size_t count, loff_t *ppos); +ssize_t DmxDevDVRRead(dmxdev_t *dmxdev, struct file *file, + char *buf, size_t count, loff_t *ppos); +int DmxDevDVRIoctl(dmxdev_t *dmxdev, struct file *file, + unsigned int cmd, unsigned long arg); +unsigned int DmxDevDVRPoll(dmxdev_t *dmxdev, struct file *file, poll_table * wait); + +#endif /* _DMXDEV_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dram.c linux.20pre2-ac1/drivers/media/video/margi/dram.c --- linux.20pre2/drivers/media/video/margi/dram.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dram.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,515 @@ +/* + dram.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + ///////////////////////////////// + // // + // L64021 DRAM Memory Access // + // // +///////////////////////////////// + +#define __NO_VERSION__ + +#include "dram.h" +#include "l64021.h" + +#define EMERGENCYCOUNTER 5 + + // where: 21 bit DRAM Word-Address, 4 word aligned + // size: bytes (8 byte aligned, remainder will be filled with fill value) + // data: fill value +// returns 0 on success, -1 on collision with DMA transfer +int DRAMFillByte(struct cvdv_cards *card, u32 where, int size, u8 data) +{ + int i, j, k, n; + u8 volatile flag; + + size = (size >> 3) + ((size & 7) ? 1 : 0); // 8 bytes at a time, padding with garbage + where >>= 2; // 8 byte aligned data + DecoderSetByte(card, 0x0C1, 0x08); +//TODO: 0x80? + + DecoderWriteByte(card, 0x0C6, (u8) ((where >> 16) & 0x00000007L)); + DecoderWriteByte(card, 0x0C5, (u8) ((where >> 8) & 0x000000FFL)); + DecoderWriteByte(card, 0x0C4, (u8) (where & 0x000000FFL)); + i = 0; + for (j = 0; j < size; j++) { + for (k = 0; k < 8; k++) { + n = EMERGENCYCOUNTER; + do { // wait if FIFO full + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x08) && n--); + if (n<0) + return -1; + DecoderWriteByte(card, 0x0C3, data); + } + } + flag = DecoderReadByte(card, 0x0C0); + n = EMERGENCYCOUNTER; + do { // wait for FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while (!(flag & 0x04) && n--); + return ((n>=0) ? 0 : -1); +} + + // where: 21 bit DRAM Word-Address, 8 byte aligned + // size: bytes (8 byte aligned, remainder will be filled with garbage) + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) +// returns 0 on success, -1 on collision with DMA transfer +int DRAMWriteByte(struct cvdv_cards *card, u32 where, int size, u8 * data, + int swapburst) +{ + int i, j, k, n; + u8 volatile flag; + + size = (size >> 3) + ((size & 7) ? 1 : 0); // 8 bytes at a time, padding with garbage + where >>= 2; // 8 byte aligned data + MDEBUG(4, ": Moving %d 64-bit-words to DRAM 0x%08X\n",size,where); + //if (swap) DecoderDelByte(card,0x0C1,0x08); // byte swapping of 8 byte bursts + //else DecoderSetByte(card,0x0C1,0x08); // no byte swapping + DecoderSetByte(card, 0x0C1, 0x08); // no byte swapping + + DecoderWriteByte(card, 0x0C6, (u8) ((where >> 16) & 0x00000007L)); + DecoderWriteByte(card, 0x0C5, (u8) ((where >> 8) & 0x000000FFL)); + DecoderWriteByte(card, 0x0C4, (u8) (where & 0x000000FFL)); + i = 0; + if (swapburst) { + for (j = 0; j < size; j++) { + for (k = 7; k >= 0; k--) { + n = EMERGENCYCOUNTER; + do { // wait if FIFO full + flag = + DecoderReadByte(card, 0x0C0); + } while ((flag & 0x08) && n--); + if (n<0) + return -1; + DecoderWriteByte(card, 0x0C3, data[i + k]); + } + i += 8; + } + } else { + for (j = 0; j < size; j++) { + for (k = 0; k < 8; k++) { + n = EMERGENCYCOUNTER; + do { // wait if FIFO full + flag = + DecoderReadByte(card, 0x0C0); + } while ((flag & 0x08) && n--); + if (n<0) + return -1; + DecoderWriteByte(card, 0x0C3, data[i++]); + } + } + } + flag = DecoderReadByte(card, 0x0C0); + n = EMERGENCYCOUNTER; + do { // wait for FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while (!(flag & 0x04) && n--); + return ((n>=0) ? 0 : -1); +} + + // where: 21 bit DRAM Word-Address, 4 word aligned + // size: words (4 word aligned, remainder will be filled with garbage) + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) +// returns 0 on success, -1 on collision with DMA transfer +int DRAMWriteWord(struct cvdv_cards *card, u32 where, int size, u16 * data, + int swap) +{ + int i, j, k, n; + u8 volatile flag; + + size = (size >> 2) + ((size & 3) ? 1 : 0); // 4 words at a time, padding with garbage + where >>= 2; // 8 byte aligned data + MDEBUG(4, ": Moving %d 64-bit-words to DRAM 0x%08X\n",size,where); +//TODO: swap manually + if (swap) + DecoderDelByte(card, 0x0C1, 0x08); // byte swapping of 8 byte bursts + else + DecoderSetByte(card, 0x0C1, 0x08); // no byte swapping + + DecoderWriteByte(card, 0x0C6, (u8) ((where >> 16) & 0x00000007L)); + DecoderWriteByte(card, 0x0C5, (u8) ((where >> 8) & 0x000000FFL)); + DecoderWriteByte(card, 0x0C4, (u8) (where & 0x000000FFL)); + i = 0; + for (j = 0; j < size; j++) { + for (k = 0; k < 4; k++) { + n = EMERGENCYCOUNTER; + do { // wait if FIFO full + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x08) && n--); + if (n<0) + return -1; + DecoderWriteByte(card, 0x0C3, data[i] >> 8); + n = EMERGENCYCOUNTER; + do { // wait if FIFO full + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x08) && n--); + if (n<0) + return -1; + DecoderWriteByte(card, 0x0C3, data[i++]); + } + } + flag = DecoderReadByte(card, 0x0C0); + n = EMERGENCYCOUNTER; + do { // wait for FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while (!(flag & 0x04) && n--); + return ((n>=0) ? 0 : -1); +} + + // where: 21 bit DRAM Word-Address, 8 byte aligned + // size: bytes + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) +// returns 0 on success, -1 on collision with DMA transfer +int DRAMReadByte(struct cvdv_cards *card, u32 where, int size, u8 * data, + int swap) +{ + int i, j, rsize, n; + u8 volatile flag; + + rsize = size & 7; // padding bytes + size = size >> 3; // 8 bytes at a time + where >>= 2; // 8 byte aligned data + MDEBUG(4, ": Moving %d 64-bit-words to DRAM 0x%08X\n",size,where); +//TODO: swap manually + if (swap) + DecoderDelByte(card, 0x0C1, 0x08); // byte swapping of 8 byte bursts + else + DecoderSetByte(card, 0x0C1, 0x08); // no byte swapping + + DecoderWriteByte(card, 0x0C9, (u8) ((where >> 16) & 0x00000007L)); + DecoderWriteByte(card, 0x0C8, (u8) ((where >> 8) & 0x000000FFL)); + DecoderWriteByte(card, 0x0C7, (u8) (where & 0x000000FFL)); + i = 0; + for (j = 0; j < size; j++) { + n = EMERGENCYCOUNTER; + do { // wait if FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x01) && n--); + if (n<0) // WARNING nicht if(!n) + return -1; + data[i++] = DecoderReadByte(card, 0x0C2); + data[i++] = DecoderReadByte(card, 0x0C2); + data[i++] = DecoderReadByte(card, 0x0C2); + data[i++] = DecoderReadByte(card, 0x0C2); + data[i++] = DecoderReadByte(card, 0x0C2); + data[i++] = DecoderReadByte(card, 0x0C2); + data[i++] = DecoderReadByte(card, 0x0C2); + data[i++] = DecoderReadByte(card, 0x0C2); + } + n = EMERGENCYCOUNTER; + do { // wait if FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x01) && n--); + if (n<0) + return -1; + for (j = 0; j < rsize; j++) + data[i++] = DecoderReadByte(card, 0x0C2); + flag = DecoderReadByte(card, 0x0C0); + n = EMERGENCYCOUNTER; + do { // wait for FIFO full + flag = DecoderReadByte(card, 0x0C0); + } while (!(flag & 0x02) && n--); + return ((n>=0) ? 0 : -1); +} + + + // where: 21 bit DRAM Word-Address, 4 word aligned + // size: words + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) +// returns 0 on success, -1 on collision with DMA transfer +int DRAMReadWord(struct cvdv_cards *card, u32 where, int size, u16 * data, + int swap) +{ + int i, j, rsize, n; + u8 volatile flag; + u8 b; + + rsize = size & 3; // padding words + size >>= 2; // 4 words at a time + where >>= 2; // 8 byte aligned data + MDEBUG(4, ": Reading %d 64-bit-words and %d 16-bit-words from DRAM 0x%08X\n", + size,rsize,where); +//TODO: swap manually + if (swap) + DecoderDelByte(card, 0x0C1, 0x08); // byte swapping of 8 byte bursts + else + DecoderSetByte(card, 0x0C1, 0x08); // no byte swapping + + DecoderWriteByte(card, 0x0C9, (u8) ((where >> 16) & 0x00000007L)); + DecoderWriteByte(card, 0x0C8, (u8) ((where >> 8) & 0x000000FFL)); + DecoderWriteByte(card, 0x0C7, (u8) (where & 0x000000FFL)); + i = 0; + for (j = 0; j < size; j++) { + n = EMERGENCYCOUNTER; + do { // wait if FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x01) && n--); + if (n<0) + return -1; + b = DecoderReadByte(card, 0x0C2); + data[i++] = ((b << 8) | DecoderReadByte(card, 0x0C2)); + b = DecoderReadByte(card, 0x0C2); + data[i++] = ((b << 8) | DecoderReadByte(card, 0x0C2)); + b = DecoderReadByte(card, 0x0C2); + data[i++] = ((b << 8) | DecoderReadByte(card, 0x0C2)); + b = DecoderReadByte(card, 0x0C2); + data[i++] = ((b << 8) | DecoderReadByte(card, 0x0C2)); + } + n = EMERGENCYCOUNTER; + do { // wait if FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x01) && n--); + if (n<0) + return -1; + for (j = 0; j < rsize; j++) { + b = DecoderReadByte(card, 0x0C2); + data[i++] = ((b << 8) | DecoderReadByte(card, 0x0C2)); + } + flag = DecoderReadByte(card, 0x0C0); + n = EMERGENCYCOUNTER; + do { // wait for FIFO full + flag = DecoderReadByte(card, 0x0C0); + } while (!(flag & 0x02) && n--); + return ((n>=0) ? 0 : -1); +} + + // where: 21 bit DRAM Word-Address, 4 word aligned + // size: words + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) + // returns -1 on success (equal content), + // word position on error (compare failure), +// -2 on collision with DMA transfer +int DRAMVerifyWord(struct cvdv_cards *card, u32 where, int size, + u16 * data, int swap) +{ + int i, j, rsize, n; + u8 volatile flag, b; + + rsize = size & 3; // padding words + size >>= 2; // 4 words at a time + where >>= 2; // 8 byte aligned data, now 19 bit 64-bit-word-address +//TODO: swap manually + if (swap) + DecoderDelByte(card, 0x0C1, 0x08); // byte swapping of 8 byte bursts + else + DecoderSetByte(card, 0x0C1, 0x08); // no byte swapping + + DecoderWriteByte(card, 0x0C9, (u8) ((where >> 16) & 0x00000007L)); + DecoderWriteByte(card, 0x0C8, (u8) ((where >> 8) & 0x000000FFL)); + DecoderWriteByte(card, 0x0C7, (u8) (where & 0x000000FFL)); + i = 0; + for (j = 0; j < size; j++) { + n = EMERGENCYCOUNTER; + do { // wait if FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x01) && n--); + b = DecoderReadByte(card, 0x0C2); + if (data[i++] != ((b << 8) | DecoderReadByte(card, 0x0C2))) + return i; + b = DecoderReadByte(card, 0x0C2); + if (data[i++] != ((b << 8) | DecoderReadByte(card, 0x0C2))) + return i; + b = DecoderReadByte(card, 0x0C2); + if (data[i++] != ((b << 8) | DecoderReadByte(card, 0x0C2))) + return i; + b = DecoderReadByte(card, 0x0C2); + if (data[i++] != ((b << 8) | DecoderReadByte(card, 0x0C2))) + return i; + } + n = EMERGENCYCOUNTER; + do { // wait if FIFO empty + flag = DecoderReadByte(card, 0x0C0); + } while ((flag & 0x01) && n--); + for (j = 0; j < rsize; j++) { + b = DecoderReadByte(card, 0x0C2); + if (data[i++] != ((b << 8) | DecoderReadByte(card, 0x0C2))) + return i; + } + flag = DecoderReadByte(card, 0x0C0); + n = EMERGENCYCOUNTER; + do { // wait for FIFO full + flag = DecoderReadByte(card, 0x0C0); + } while (!(flag & 0x02) && n--); + return -1; +} + + // WARNING: better not use this one. It can collide with normal DRAM access and other DMA transfers + // If you want to use it, implement card->DMAMoveBusy in all other DMA functions, initialisation, and header file + // source, destination: 21 bit DRAM Word-Address, 4 word aligned + // size: byte (8 byte aligned, hang over bytes will NOT be moved) + // returns 0 on success on success, + // -1 on collision with DMA transfer, +// -2 on interrupt handler not installed +int DRAMMove(struct cvdv_cards *card, u32 source, u32 destination, + int size) +{ + if (!card->IntInstalled) + return -2; + if (card->DMAABusy || card->DMABBusy) + return -1; + + size >>= 3; // 64-bit-words + source >>= 2; // 8 byte aligned data, + destination >>= 2; // now 19 bit 64-bit-word-address + + DecoderDelByte(card, 0x0C1, 0x06); // DMA idle + + DecoderWriteByte(card, 0x0DA, (u8) ((source >> 16) & 0x00000007L)); + DecoderWriteByte(card, 0x0D9, (u8) ((source >> 8) & 0x000000FFL)); + DecoderWriteByte(card, 0x0D8, (u8) (source & 0x000000FFL)); + DecoderWriteByte(card, 0x0D7, + (u8) ((destination >> 16) & 0x00000007L)); + DecoderWriteByte(card, 0x0D6, + (u8) ((destination >> 8) & 0x000000FFL)); + DecoderWriteByte(card, 0x0D5, (u8) (destination & 0x000000FFL)); + + //card->DMAMoveBusy=1; // would have to catch that in all the other DMA routines + DecoderSetByte(card, 0x0C1, 0x06); // DMA block move + + return 0; +} + + // size in words + // align: number of words on wich start of block will be aligned +// return value is 21 bit word address, or 0xFFFFFFFF on error +u32 DRAMAlloc(struct cvdv_cards * card, u32 size, int align) +{ + struct DRAMBlock *ptr, *ptr2; + u32 addr = 0; + u32 alignmask = align - 1; + int valid = 0; + + printk("DRAMAlloc %d bytes (from %d).\n", size, card->DRAMSize); + + if (size == 0) + { + printk("DRAMAlloc - 0 size.\n"); + return BLANK; + } + + if (size & 3) + size = (size & ~3) + 4; // increase size if not 64 bit aligned + + printk("DRAMAlloc %d bytes.\n", size); + if (card->DRAMFirstBlock == NULL) { // virgin territory? + valid = ((addr + size) <= card->DRAMSize); // does it fit at all? + } else { + addr = 0; + valid = ((addr + size) <= card->DRAMSize); // does it fit at all? + for (ptr2 = card->DRAMFirstBlock; + (ptr2 != NULL) && (valid); ptr2 = ptr2->next) { // check against all existing blocks + if ((ptr2->start >= addr) + && (ptr2->start < (addr + size))) + valid = 0; // existing block start inside new block? + else if (((ptr2->start + ptr2->length) > addr) + && ((ptr2->start + ptr2->length) <= + (addr + size))) + valid = 0; // existing block end inside new block? + else if ((ptr2->start < addr) + && ((ptr2->start + ptr2->length) > + (addr + size))) valid = 0; // new block inside existing block? + } + for (ptr = card->DRAMFirstBlock; (ptr != NULL) && (!valid); + ptr = ptr->next) { // check all existing blocks + addr = ptr->start + ptr->length; // assume, after this block is free space + if (addr & alignmask) + addr = (addr & ~alignmask) + align; // round up to alignation border + valid = ((addr + size) <= card->DRAMSize); // does it fit at all? + for (ptr2 = card->DRAMFirstBlock; + (ptr2 != NULL) && (valid); ptr2 = ptr2->next) { // check against all existing blocks + if ((ptr2->start >= addr) + && (ptr2->start < (addr + size))) + valid = 0; // existing block start inside new block? + else + if ( + ((ptr2->start + ptr2->length) > + addr) + && ((ptr2->start + ptr2->length) <= + (addr + size))) + valid = 0; // existing block end inside new block? + else if ((ptr2->start < addr) + && ((ptr2->start + ptr2->length) > + (addr + size))) + valid = 0; // new block inside existing block? + } + } + } + if (valid) { // The new block fits + ptr = (struct DRAMBlock *) kmalloc(sizeof(struct DRAMBlock), GFP_KERNEL); + if (ptr == NULL) { + printk(KERN_INFO LOGNAME ": ERROR: out of kernel memory for block info. Please reboot if possible.\n"); + return BLANK; // out of kernel mem + } + if (card->DRAMFirstBlock == NULL) { + card->DRAMFirstBlock = ptr; + } else { + ptr2 = card->DRAMFirstBlock; + while (ptr2->next != NULL) + ptr2 = ptr2->next; + ptr2->next = ptr; + } + ptr->next = NULL; + ptr->start = addr; + ptr->length = size; + MDEBUG(1,": DRAM Allocate 0x%08X-0x%08X\n", addr, + addr + size - 1); + + printk("DRAMAlloc ok\n"); + return addr; + } + printk(KERN_ERR "DRAMAlloc: No card memory.\n"); + return BLANK; +} + + // addr is the return value of that resp. DRAMAlloc call +// returns 0 on success (always) +int DRAMFree(struct cvdv_cards *card, u32 addr) +{ + struct DRAMBlock *ptr, *ptr2; + ptr2 = NULL; + for (ptr = card->DRAMFirstBlock; ptr != NULL; ptr = ptr->next) { // check all existent blocks + if (addr == ptr->start) { // this is our block to be removed + if (ptr2 == NULL) + card->DRAMFirstBlock = ptr->next; + else + ptr2->next = ptr->next; + kfree(ptr); + MDEBUG(1, ": DRAM Free 0x%08X\n", addr); + } else + ptr2 = ptr; + } + return 0; +} + + // free all blocks +// returns 0 on success (always) +int DRAMRelease(struct cvdv_cards *card) +{ + struct DRAMBlock *ptr, *ptr2; + MDEBUG(1, ": -- DRAMRelease\n"); + for (ptr = card->DRAMFirstBlock; ptr != NULL; ptr = ptr2) { // check all existent blocks + ptr2 = ptr->next; + MDEBUG(4, ": kfree(0x%08X)\n",(int)ptr); + kfree(ptr); + } + card->DRAMFirstBlock = NULL; + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dram.h linux.20pre2-ac1/drivers/media/video/margi/dram.h --- linux.20pre2/drivers/media/video/margi/dram.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dram.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,99 @@ +/* + dram.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef DRAM_H +#define DRAM_H + + ///////////////////////////////// + // // + // L64021 DRAM Memory Access // + // // +///////////////////////////////// + +#include "cardbase.h" + + // where: 21 bit DRAM Word-Address, 4 word aligned + // size: bytes (8 byte aligned, remainder will be filled with fill value) + // data: fill value +// returns 0 on success, -1 on collision with DMA transfer +int DRAMFillByte(struct cvdv_cards *card, u32 where, int size, u8 data); + + // where: 21 bit DRAM Word-Address, 8 byte aligned + // size: bytes (8 byte aligned, remainder will be filled with garbage) + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) +// returns 0 on success, -1 on collision with DMA transfer +int DRAMWriteByte(struct cvdv_cards *card, u32 where, int size, u8 * data, + int swapburst); + + // where: 21 bit DRAM Word-Address, 4 word aligned + // size: words (4 word aligned, remainder will be filled with garbage) + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) +// returns 0 on success, -1 on collision with DMA transfer +int DRAMWriteWord(struct cvdv_cards *card, u32 where, int size, u16 * data, + int swap); + + // where: 21 bit DRAM Word-Address, 8 byte aligned + // size: bytes + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) +// returns 0 on success, -1 on collision with DMA transfer +int DRAMReadByte(struct cvdv_cards *card, u32 where, int size, u8 * data, + int swap); + + + // where: 21 bit DRAM Word-Address, 4 word aligned + // size: words + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) +// returns 0 on success, -1 on collision with DMA transfer +int DRAMReadWord(struct cvdv_cards *card, u32 where, int size, u16 * data, + int swap); + + // where: 21 bit DRAM Word-Address, 4 word aligned + // size: words + // swap: 0=normal mode, 1=write each 8 bytes on reverse order (7,6,5,4,3,2,1,0,15,14,13,etc.) + // returns -1 on success (equal content), + // word position on error (compare failure), +// -2 on collision with DMA transfer +int DRAMVerifyWord(struct cvdv_cards *card, u32 where, int size, + u16 * data, int swap); + + // WARNING: better not use this one. It can collide with normal DRAM access and other DMA transfers + // If you want to use it, implement card->DMAMoveBusy in all other DMA functions, initialisation, and header file + // source, destination: 21 bit DRAM Word-Address, 4 word aligned + // size: byte (8 byte aligned, hang over bytes will NOT be moved) + // returns 0 on success on success, + // -1 on collision with DMA transfer, +// -2 on interrupt handler not installed +int DRAMMove(struct cvdv_cards *card, u32 source, u32 destination, + int size); + + // size in words + // align: number of words on wich start of block will be aligned +// return value is 21 bit word address, or 0xFFFFFFFF on error +u32 DRAMAlloc(struct cvdv_cards *card, u32 size, int align); + + // addr is the return value of that resp. DRAMAlloc call +// returns 0 on success (always) +int DRAMFree(struct cvdv_cards *card, u32 addr); + + // free all blocks +// returns 0 on success (always) +int DRAMRelease(struct cvdv_cards *card); + +#endif /* DRAM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dvb_demux.c linux.20pre2-ac1/drivers/media/video/margi/dvb_demux.c --- linux.20pre2/drivers/media/video/margi/dvb_demux.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dvb_demux.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1169 @@ +/* + * dvb_demux.c - DVB kernel demux API + * + * Copyright (C) 2000-2001 Ralph Metzler + * & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include + +#include "dvb_demux.h" + +#ifdef MODULE +MODULE_DESCRIPTION(""); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +#endif + +#define NOBUFS + +LIST_HEAD(dmx_muxs); + +int dmx_register_demux(dmx_demux_t *demux) +{ + struct list_head *pos, *head=&dmx_muxs; + + if (!(demux->id && demux->vendor && demux->model)) + return -EINVAL; + list_for_each(pos, head) + { + if (!strcmp(DMX_DIR_ENTRY(pos)->id, demux->id)) + return -EEXIST; + } + demux->users=0; + list_add(&(demux->reg_list), head); + MOD_INC_USE_COUNT; + return 0; +} + +int dmx_unregister_demux(dmx_demux_t* demux) +{ + struct list_head *pos, *head=&dmx_muxs; + + list_for_each(pos, head) + { + if (DMX_DIR_ENTRY(pos)==demux) + { + if (demux->users>0) + return -EINVAL; + list_del(pos); + MOD_DEC_USE_COUNT; + return 0; + } + } + return -ENODEV; +} + + +struct list_head *dmx_get_demuxes(void) +{ + if (list_empty(&dmx_muxs)) + return NULL; + + return &dmx_muxs; +} + +/****************************************************************************** + * static inlined helper functions + ******************************************************************************/ + +static inline u16 +section_length(const u8 *buf) +{ + return 3+((buf[1]&0x0f)<<8)+buf[2]; +} + +static inline u16 +ts_pid(const u8 *buf) +{ + return ((buf[1]&0x1f)<<8)+buf[2]; +} + +static inline int +payload(const u8 *tsp) +{ + if (!(tsp[3]&0x10)) // no payload? + return 0; + if (tsp[3]&0x20) { // adaptation field? + if (tsp[4]>183) // corrupted data? + return 0; + else + return 184-1-tsp[4]; + } + return 184; +} + + +static u32 +dvb_crc_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; + +u32 dvb_crc32(u8 *data, int len) +{ + int i; + u32 crc = 0xffffffff; + + for (i=0; i> 24) ^ *data++) & 0xff]; + return crc; +} + +void dvb_set_crc32(u8 *data, int length) +{ + u32 crc; + + crc=dvb_crc32(data,length); + data[length] = (crc>>24)&0xff; + data[length+1] = (crc>>16)&0xff; + data[length+2] = (crc>>8)&0xff; + data[length+3] = (crc)&0xff; +} + + +/****************************************************************************** + * Software filter functions + ******************************************************************************/ + +static inline int +DvbDmxSWFilterPayload(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) +{ + int p, count; + //int ccok; + //u8 cc; + + if (!(count=payload(buf))) + return -1; + p=188-count; + /* + cc=buf[3]&0x0f; + ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0; + dvbdmxfeed->cc=cc; + if (!ccok) + printk("missed packet!\n"); + */ + if (buf[1]&0x40) // PUSI ? + dvbdmxfeed->peslen=0xfffa; + dvbdmxfeed->peslen+=count; + + return dvbdmxfeed->cb.ts((u8 *)&buf[p], count, 0, 0, + &dvbdmxfeed->feed.ts, DMX_OK); +} + + +static int +DvbDmxSWFilterSectionFilter(dvb_demux_feed_t *dvbdmxfeed, + dvb_demux_filter_t *dvbdmxfilter) +{ + dmx_section_filter_t *filter=&dvbdmxfilter->filter; +#if 1 + int i; + + for (i=0; ifilter_mask[i]& + (filter->filter_value[i]^dvbdmxfeed->secbuf[i])) + return 0; +#else + u32 res; + u32 *val=(u32 *)(filter->filter_value); + u32 *mask=(u32 *)(filter->filter_mask); + u32 *data=(u32 *)(dvbdmxfeed->secbuf); + + res=mask[0]&(val[0]^data[0]); + if (res) return 0; + + res=mask[1]&(val[1]^data[1]); + if (res) return 0; + + res=mask[2]&(val[2]^data[2]); + if (res) return 0; + + res=mask[3]&(val[3]^data[3]); + if (res) return 0; + + res=*(u16 *)(4+mask) & (*(u16 *)(4+val) ^ *(u16 *)(4+data)); + if (res) return 0; +#endif + + return dvbdmxfeed->cb.sec(dvbdmxfeed->secbuf, dvbdmxfeed->seclen, + 0, 0, filter, DMX_OK); +} + +static inline int +DvbDmxSWFilterSectionFeed(dvb_demux_feed_t *dvbdmxfeed) +{ + u8 *buf=dvbdmxfeed->secbuf; + dvb_demux_filter_t *f; + + if (dvbdmxfeed->secbufp!=dvbdmxfeed->seclen) + return -1; + if (!dvbdmxfeed->feed.sec.is_filtering) + return 0; + if (!(f=dvbdmxfeed->filter)) + return 0; + do + if (DvbDmxSWFilterSectionFilter(dvbdmxfeed, f)<0) + return -1; + while ((f=f->next) && dvbdmxfeed->feed.sec.is_filtering); + + dvbdmxfeed->secbufp=dvbdmxfeed->seclen=0; + memset(buf, 0, DVB_DEMUX_MASK_MAX); + return 0; +} + +static inline int +DvbDmxSWFilterSectionPacket(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) +{ + int p, count; + int ccok, rest; + u8 cc; + + if (!(count=payload(buf))) + return -1; + p=188-count; + + cc=buf[3]&0x0f; + ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0; + dvbdmxfeed->cc=cc; + + if (buf[1]&0x40) { // PUSI set + // offset to start of first section is in buf[p] + if (p+buf[p]>187) // trash if it points beyond packet + return -1; + if (buf[p] && ccok) { // rest of previous section? + // did we have enough data in last packet to calc length? + if (dvbdmxfeed->secbufp && dvbdmxfeed->secbufp<3) { + memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, + buf+p+1, + 3-dvbdmxfeed->secbufp); + dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf); + if (dvbdmxfeed->seclen>4096) + return -1; + } + rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp; + if (rest==buf[p] && dvbdmxfeed->seclen) { + memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, + buf+p+1, buf[p]); + dvbdmxfeed->secbufp+=buf[p]; + DvbDmxSWFilterSectionFeed(dvbdmxfeed); + } + } + p+=buf[p]+1; // skip rest of last section + count=188-p; + while (count>0) { + if ((count>2) && // enough data to determine sec length? + ((dvbdmxfeed->seclen=section_length(buf+p))<=count)) { + if (dvbdmxfeed->seclen>4096) + return -1; + memcpy(dvbdmxfeed->secbuf, buf+p, + dvbdmxfeed->seclen); + dvbdmxfeed->secbufp=dvbdmxfeed->seclen; + p+=dvbdmxfeed->seclen; + count=188-p; + DvbDmxSWFilterSectionFeed(dvbdmxfeed); + + // filling bytes until packet end? + if (count && buf[p]==0xff) + count=0; + } else { // section continues to following TS packet + memcpy(dvbdmxfeed->secbuf, buf+p, count); + dvbdmxfeed->secbufp+=count; + count=0; + } + } + } else { // section continued below + if (!ccok) + return -1; + if (!dvbdmxfeed->secbufp) // any data in last ts packet? + return -1; + // did we have enough data in last packet to calc section length? + if (dvbdmxfeed->secbufp<3) { + memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, + 3-dvbdmxfeed->secbufp); + dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf); + if (dvbdmxfeed->seclen>4096) + return -1; + } + rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp; + if (rest<0) + return -1; + if (rest<=count) { // section completed in this TS packet + memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, rest); + dvbdmxfeed->secbufp+=rest; + DvbDmxSWFilterSectionFeed(dvbdmxfeed); + } else { // section continues in following ts block + memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, count); + dvbdmxfeed->secbufp+=count; + } + + } + return 0; +} + +static inline void +DvbDmxSWFilterPacketType(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) +{ + switch(dvbdmxfeed->type) { + case DMX_TYPE_TS: + if (!dvbdmxfeed->feed.ts.is_filtering) + break; + if (dvbdmxfeed->ts_type & TS_PACKET) { + if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) + DvbDmxSWFilterPayload(dvbdmxfeed, buf); + else + dvbdmxfeed->cb.ts((u8 *)buf, 188, 0, 0, + &dvbdmxfeed->feed.ts, DMX_OK); + } + if (dvbdmxfeed->ts_type & TS_DECODER) + if (dvbdmxfeed->demux->write_to_decoder) + dvbdmxfeed->demux-> + write_to_decoder(dvbdmxfeed, (u8 *)buf, 188); + break; + + case DMX_TYPE_SEC: + if (!dvbdmxfeed->feed.sec.is_filtering) + break; + if (DvbDmxSWFilterSectionPacket(dvbdmxfeed, buf)<0) + dvbdmxfeed->seclen=dvbdmxfeed->secbufp=0; + break; + + default: + break; + } +} + +void inline +DvbDmxSWFilterPacket(dvb_demux_t *dvbdmx, const u8 *buf) +{ + dvb_demux_feed_t *dvbdmxfeed; + + if (!(dvbdmxfeed=dvbdmx->pid2feed[ts_pid(buf)])) + return; + DvbDmxSWFilterPacketType(dvbdmxfeed, buf); +} + +void +DvbDmxSWFilterPackets(dvb_demux_t *dvbdmx, const u8 *buf, int count) +{ + dvb_demux_feed_t *dvbdmxfeed; + + if ((dvbdmxfeed=dvbdmx->pid2feed[0x2000])) + dvbdmxfeed->cb.ts((u8 *)buf, count*188, 0, 0, + &dvbdmxfeed->feed.ts, DMX_OK); + while (count) { + DvbDmxSWFilterPacket(dvbdmx, buf); + count--; + buf+=188; + } +} + +static inline void +DvbDmxSWFilter(dvb_demux_t *dvbdmx, const u8 *buf, size_t count) +{ + int p=0,i, j; + + if ((i=dvbdmx->tsbufp)) { + if (count<(j=188-i)) { + memcpy(&dvbdmx->tsbuf[i], buf, count); + dvbdmx->tsbufp+=count; + return; + } + memcpy(&dvbdmx->tsbuf[i], buf, j); + DvbDmxSWFilterPacket(dvbdmx, dvbdmx->tsbuf); + dvbdmx->tsbufp=0; + p+=j; + } + + while (p=188) { + DvbDmxSWFilterPacket(dvbdmx, buf+p); + p+=188; + } else { + i=count-p; + memcpy(dvbdmx->tsbuf, buf+p, i); + dvbdmx->tsbufp=i; + return; + } + } else + p++; + } +} + + +/****************************************************************************** + ****************************************************************************** + * DVB DEMUX API LEVEL FUNCTIONS + ****************************************************************************** + ******************************************************************************/ + +static dvb_demux_filter_t * +DvbDmxFilterAlloc(dvb_demux_t *dvbdmx) +{ + int i; + + for (i=0; ifilternum; i++) + if (dvbdmx->filter[i].state==DMX_STATE_FREE) + break; + if (i==dvbdmx->filternum) + return 0; + dvbdmx->filter[i].state=DMX_STATE_ALLOCATED; + return &dvbdmx->filter[i]; +} + +static dvb_demux_feed_t * +DvbDmxFeedAlloc(dvb_demux_t *dvbdmx) +{ + int i; + + for (i=0; ifeednum; i++) + if (dvbdmx->feed[i].state==DMX_STATE_FREE) + break; + if (i==dvbdmx->feednum) + return 0; + dvbdmx->feed[i].state=DMX_STATE_ALLOCATED; + return &dvbdmx->feed[i]; +} + + +/****************************************************************************** + * dmx_ts_feed API calls + ******************************************************************************/ + +static int +dmx_ts_feed_set_type(dmx_ts_feed_t *feed, int type, dmx_ts_pes_t pes_type) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + + down(&dvbdmx->mutex); + dvbdmxfeed->ts_type=type; + dvbdmxfeed->pes_type=pes_type; + + if (dvbdmxfeed->ts_type & TS_DECODER) { + if (pes_type >= DMX_TS_PES_OTHER) { + up(&dvbdmx->mutex); + return -EINVAL; + } + if (dvbdmx->pesfilter[pes_type] && + (dvbdmx->pesfilter[pes_type]!=dvbdmxfeed)) { + up(&dvbdmx->mutex); + return -EINVAL; + } + dvbdmx->pesfilter[pes_type]=dvbdmxfeed; + dvbdmx->pids[pes_type]=dvbdmxfeed->pid; + } + up(&dvbdmx->mutex); + return 0; +} + +static int +dmx_pid_set(u16 pid, dvb_demux_feed_t *dvbdmxfeed) +{ + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + dvb_demux_feed_t **pid2feed=dvbdmx->pid2feed; + + if (pid>DMX_MAX_PID) + return -EINVAL; + if (dvbdmxfeed->pid!=0xffff) { + if (dvbdmxfeed->pid<=DMX_MAX_PID) + pid2feed[dvbdmxfeed->pid]=0; + dvbdmxfeed->pid=0xffff; + } + if (pid2feed[pid]) { + return -EBUSY; + } + pid2feed[pid]=dvbdmxfeed; + dvbdmxfeed->pid=pid; + return 0; +} + + +static int +dmx_ts_feed_set(struct dmx_ts_feed_s* feed, + u16 pid, + size_t callback_length, + size_t circular_buffer_size, + int descramble, + struct timespec timeout + ) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + int ret; + + down(&dvbdmx->mutex); + ret=dmx_pid_set(pid, dvbdmxfeed); + if (ret<0) { + up(&dvbdmx->mutex); + return ret; + } + dvbdmxfeed->buffer_size=circular_buffer_size; + dvbdmxfeed->descramble=descramble; + dvbdmxfeed->timeout=timeout; + dvbdmxfeed->cb_length=callback_length; + dvbdmxfeed->ts_type=TS_PACKET; + + if (dvbdmxfeed->descramble) { + up(&dvbdmx->mutex); + return -ENOSYS; + } + + if (dvbdmxfeed->buffer_size) { +#ifdef NOBUFS + dvbdmxfeed->buffer=0; +#else + dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); + if (!dvbdmxfeed->buffer) { + up(&dvbdmx->mutex); + return -ENOMEM; + } +#endif + } + dvbdmxfeed->state=DMX_STATE_READY; + up(&dvbdmx->mutex); + return 0; +} + +static int +dmx_ts_feed_start_filtering(struct dmx_ts_feed_s* feed) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + int ret; + + down(&dvbdmx->mutex); + if (dvbdmxfeed->state!=DMX_STATE_READY || + dvbdmxfeed->type!=DMX_TYPE_TS) { + up(&dvbdmx->mutex); + return -EINVAL; + } + if (!dvbdmx->start_feed) { + up(&dvbdmx->mutex); + return -1; + } + ret=dvbdmx->start_feed(dvbdmxfeed); + if (ret<0) { + up(&dvbdmx->mutex); + return ret; + } + feed->is_filtering=1; + dvbdmxfeed->state=DMX_STATE_GO; + up(&dvbdmx->mutex); + return 0; +} + +static int +dmx_ts_feed_stop_filtering(struct dmx_ts_feed_s* feed) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + int ret; + + down(&dvbdmx->mutex); + if (dvbdmxfeed->statemutex); + return -EINVAL; + } + if (!dvbdmx->stop_feed) { + up(&dvbdmx->mutex); + return -1; + } + ret=dvbdmx->stop_feed(dvbdmxfeed); + feed->is_filtering=0; + dvbdmxfeed->state=DMX_STATE_ALLOCATED; + + up(&dvbdmx->mutex); + return ret; +} + +static int dvbdmx_allocate_ts_feed(dmx_demux_t *demux, + dmx_ts_feed_t **feed, + dmx_ts_cb callback) +{ + dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; + dvb_demux_feed_t *dvbdmxfeed; + + down(&dvbdmx->mutex); + if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx))) { + up(&dvbdmx->mutex); + return -EBUSY; + } + dvbdmxfeed->type=DMX_TYPE_TS; + dvbdmxfeed->cb.ts=callback; + dvbdmxfeed->demux=dvbdmx; + dvbdmxfeed->pid=0xffff; + dvbdmxfeed->peslen=0xfffa; + dvbdmxfeed->buffer=0; + + (*feed)=&dvbdmxfeed->feed.ts; + (*feed)->is_filtering=0; + (*feed)->parent=demux; + (*feed)->priv=0; + (*feed)->set=dmx_ts_feed_set; + (*feed)->set_type=dmx_ts_feed_set_type; + (*feed)->start_filtering=dmx_ts_feed_start_filtering; + (*feed)->stop_filtering=dmx_ts_feed_stop_filtering; + + + if (!(dvbdmxfeed->filter=DvbDmxFilterAlloc(dvbdmx))) { + dvbdmxfeed->state=DMX_STATE_FREE; + up(&dvbdmx->mutex); + return -EBUSY; + } + + dvbdmxfeed->filter->type=DMX_TYPE_TS; + dvbdmxfeed->filter->feed=dvbdmxfeed; + dvbdmxfeed->filter->state=DMX_STATE_READY; + + up(&dvbdmx->mutex); + return 0; +} + +static int dvbdmx_release_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t *feed) +{ + dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + + down(&dvbdmx->mutex); + if (dvbdmxfeed->state==DMX_STATE_FREE) { + up(&dvbdmx->mutex); + return -EINVAL; + } +#ifndef NOBUFS + if (dvbdmxfeed->buffer) { + vfree(dvbdmxfeed->buffer); + dvbdmxfeed->buffer=0; + } +#endif + dvbdmxfeed->state=DMX_STATE_FREE; + dvbdmxfeed->filter->state=DMX_STATE_FREE; + if (dvbdmxfeed->pid!=0xffff) { + if (dvbdmxfeed->pid<=DMX_MAX_PID) + dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0; + dvbdmxfeed->pid=0xffff; + } + + up(&dvbdmx->mutex); + return 0; +} + + +/****************************************************************************** + * dmx_pes_feed API calls + ******************************************************************************/ +/* +static int +dmx_pes_feed_set(struct dmx_pes_feed_s* feed, + u16 pid, + size_t circular_buffer_size, + int descramble, + struct timespec timeout) +{ + return 0; +} + +static int +dmx_pes_feed_start_filtering(struct dmx_pes_feed_s* feed) +{ + return 0; +} + +static int +dmx_pes_feed_stop_filtering(struct dmx_pes_feed_s* feed) +{ + return 0; +} +*/ + +static int dvbdmx_allocate_pes_feed(dmx_demux_t *demux, + dmx_pes_feed_t **feed, + dmx_pes_cb callback) +{ + return 0; +} + +static int dvbdmx_release_pes_feed(dmx_demux_t *demux, + dmx_pes_feed_t *feed) +{ + return 0; +} + + +/****************************************************************************** + * dmx_section_feed API calls + ******************************************************************************/ + +static int +dmx_section_feed_allocate_filter(struct dmx_section_feed_s* feed, + dmx_section_filter_t** filter) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdemux=dvbdmxfeed->demux; + dvb_demux_filter_t *dvbdmxfilter; + + down(&dvbdemux->mutex); + dvbdmxfilter=DvbDmxFilterAlloc(dvbdemux); + if (!dvbdmxfilter) { + up(&dvbdemux->mutex); + return -ENOSPC; + } + *filter=&dvbdmxfilter->filter; + (*filter)->parent=feed; + (*filter)->priv=0; + dvbdmxfilter->feed=dvbdmxfeed; + dvbdmxfilter->pid=dvbdmxfeed->pid; + dvbdmxfilter->type=DMX_TYPE_SEC; + dvbdmxfilter->state=DMX_STATE_READY; + + dvbdmxfilter->next=dvbdmxfeed->filter; + dvbdmxfeed->filter=dvbdmxfilter; + up(&dvbdemux->mutex); + return 0; +} + +static int +dmx_section_feed_set(struct dmx_section_feed_s* feed, + u16 pid, size_t circular_buffer_size, + int descramble, int check_crc) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + + if (pid>0x1fff) + return -EINVAL; + down(&dvbdmx->mutex); + if (dvbdmxfeed->pid!=0xffff) { + dvbdmx->pid2feed[dvbdmxfeed->pid]=0; + dvbdmxfeed->pid=0xffff; + } + if (dvbdmx->pid2feed[pid]) { + up(&dvbdmx->mutex); + return -EBUSY; + } + dvbdmx->pid2feed[pid]=dvbdmxfeed; + dvbdmxfeed->pid=pid; + + dvbdmxfeed->buffer_size=circular_buffer_size; + dvbdmxfeed->descramble=descramble; + if (dvbdmxfeed->descramble) { + up(&dvbdmx->mutex); + return -ENOSYS; + } + + dvbdmxfeed->check_crc=check_crc; +#ifdef NOBUFS + dvbdmxfeed->buffer=0; +#else + dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); + if (!dvbdmxfeed->buffer) { + up(&dvbdmx->mutex); + return -ENOMEM; + } +#endif + dvbdmxfeed->state=DMX_STATE_READY; + up(&dvbdmx->mutex); + return 0; +} + +static int +dmx_section_feed_start_filtering(dmx_section_feed_t *feed) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + int ret; + + down(&dvbdmx->mutex); + if (feed->is_filtering) { + up(&dvbdmx->mutex); + return -EBUSY; + } + if (!dvbdmxfeed->filter) { + up(&dvbdmx->mutex); + return -EINVAL; + } + dvbdmxfeed->secbufp=0; + dvbdmxfeed->seclen=0; + + if (!dvbdmx->start_feed) { + up(&dvbdmx->mutex); + return -1; + } + ret=dvbdmx->start_feed(dvbdmxfeed); + if (ret<0) { + up(&dvbdmx->mutex); + return ret; + } + feed->is_filtering=1; + dvbdmxfeed->state=DMX_STATE_GO; + up(&dvbdmx->mutex); + return 0; +} + +static int +dmx_section_feed_stop_filtering(struct dmx_section_feed_s* feed) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + int ret; + + down(&dvbdmx->mutex); + if (!dvbdmx->stop_feed) { + up(&dvbdmx->mutex); + return -1; + } + ret=dvbdmx->stop_feed(dvbdmxfeed); + + dvbdmxfeed->state=DMX_STATE_READY; + feed->is_filtering=0; + up(&dvbdmx->mutex); + return ret; +} + +static int +dmx_section_feed_release_filter(dmx_section_feed_t *feed, + dmx_section_filter_t* filter) +{ + dvb_demux_filter_t *dvbdmxfilter=(dvb_demux_filter_t *) filter, *f; + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + + down(&dvbdmx->mutex); + if (dvbdmxfilter->feed!=dvbdmxfeed) { + up(&dvbdmx->mutex); + return -EINVAL; + } + if (feed->is_filtering) + feed->stop_filtering(feed); + + f=dvbdmxfeed->filter; + if (f==dvbdmxfilter) + dvbdmxfeed->filter=dvbdmxfilter->next; + else { + while(f->next!=dvbdmxfilter) + f=f->next; + f->next=f->next->next; + } + dvbdmxfilter->state=DMX_STATE_FREE; + up(&dvbdmx->mutex); + return 0; +} + +static int dvbdmx_allocate_section_feed(dmx_demux_t *demux, + dmx_section_feed_t **feed, + dmx_section_cb callback) +{ + dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; + dvb_demux_feed_t *dvbdmxfeed; + + down(&dvbdmx->mutex); + if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx))) { + up(&dvbdmx->mutex); + return -EBUSY; + } + dvbdmxfeed->type=DMX_TYPE_SEC; + dvbdmxfeed->cb.sec=callback; + dvbdmxfeed->demux=dvbdmx; + dvbdmxfeed->pid=0xffff; + dvbdmxfeed->secbufp=0; + dvbdmxfeed->filter=0; + dvbdmxfeed->buffer=0; + + (*feed)=&dvbdmxfeed->feed.sec; + (*feed)->is_filtering=0; + (*feed)->parent=demux; + (*feed)->priv=0; + (*feed)->set=dmx_section_feed_set; + (*feed)->allocate_filter=dmx_section_feed_allocate_filter; + (*feed)->release_filter=dmx_section_feed_release_filter; + (*feed)->start_filtering=dmx_section_feed_start_filtering; + (*feed)->stop_filtering=dmx_section_feed_stop_filtering; + + up(&dvbdmx->mutex); + return 0; +} + +static int dvbdmx_release_section_feed(dmx_demux_t *demux, + dmx_section_feed_t *feed) +{ + dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; + + down(&dvbdmx->mutex); + if (dvbdmxfeed->state==DMX_STATE_FREE) { + up(&dvbdmx->mutex); + return -EINVAL; + } +#ifndef NOBUFS + if (dvbdmxfeed->buffer) { + vfree(dvbdmxfeed->buffer); + dvbdmxfeed->buffer=0; + } +#endif + dvbdmxfeed->state=DMX_STATE_FREE; + dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0; + if (dvbdmxfeed->pid!=0xffff) + dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0; + up(&dvbdmx->mutex); + return 0; +} + + +/****************************************************************************** + * dvb_demux kernel data API calls + ******************************************************************************/ + +static int dvbdmx_open(dmx_demux_t *demux) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + + if (dvbdemux->users>=MAX_DVB_DEMUX_USERS) + return -EUSERS; + dvbdemux->users++; + return 0; +} + +static int dvbdmx_close(struct dmx_demux_s *demux) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + + if (dvbdemux->users==0) + return -ENODEV; + dvbdemux->users--; + //FIXME: release any unneeded resources if users==0 + return 0; +} + +static int dvbdmx_write(dmx_demux_t *demux, const char *buf, size_t count) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + + if ((!demux->frontend) || + (demux->frontend->source!=DMX_MEMORY_FE)) + return -EINVAL; + + down(&dvbdemux->mutex); + DvbDmxSWFilter(dvbdemux, buf, count); + up(&dvbdemux->mutex); + return count; +} + + +static int dvbdmx_add_frontend(dmx_demux_t *demux, + dmx_frontend_t *frontend) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct list_head *pos, *head=&dvbdemux->frontend_list; + + //printk ("function : %s\n", __FUNCTION__); + + if (!(frontend->id && frontend->vendor && frontend->model)) + return -EINVAL; + list_for_each(pos, head) + { + if (!strcmp(DMX_FE_ENTRY(pos)->id, frontend->id)) + return -EEXIST; + } + + list_add(&(frontend->connectivity_list), head); + return 0; +} + +static int +dvbdmx_remove_frontend(dmx_demux_t *demux, + dmx_frontend_t *frontend) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct list_head *pos, *head=&dvbdemux->frontend_list; + + list_for_each(pos, head) + { + if (DMX_FE_ENTRY(pos)==frontend) + { + list_del(pos); + return 0; + } + } + return -ENODEV; +} + +static struct list_head * +dvbdmx_get_frontends(dmx_demux_t *demux) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + + if (list_empty(&dvbdemux->frontend_list)) + return NULL; + return &dvbdemux->frontend_list; +} + +static int dvbdmx_connect_frontend(dmx_demux_t *demux, + dmx_frontend_t *frontend) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + + if (demux->frontend) + return -EINVAL; + + down(&dvbdemux->mutex); + demux->frontend=frontend; + up(&dvbdemux->mutex); + return 0; +} + +static int dvbdmx_disconnect_frontend(dmx_demux_t *demux) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + + down(&dvbdemux->mutex); + demux->frontend=NULL; + up(&dvbdemux->mutex); + return 0; +} + +static int dvbdmx_get_pes_pids(dmx_demux_t *demux, u16 *pids) +{ + dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + + memcpy(pids, dvbdemux->pids, 5*sizeof(u16)); + return 0; +} + +int +DvbDmxInit(dvb_demux_t *dvbdemux) +{ + int i; + dmx_demux_t *dmx=&dvbdemux->dmx; + + dvbdemux->users=0; + dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(dvb_demux_filter_t)); + if (!dvbdemux->filter) + return -ENOMEM; + + dvbdemux->feed=vmalloc(dvbdemux->feednum*sizeof(dvb_demux_feed_t)); + if (!dvbdemux->feed) { + vfree(dvbdemux->filter); + return -ENOMEM; + } + for (i=0; ifilternum; i++) { + dvbdemux->filter[i].state=DMX_STATE_FREE; + dvbdemux->filter[i].index=i; + } + for (i=0; ifeednum; i++) + dvbdemux->feed[i].state=DMX_STATE_FREE; + dvbdemux->frontend_list.next= + dvbdemux->frontend_list.prev= + &dvbdemux->frontend_list; + for (i=0; ipesfilter[i]=NULL; + dvbdemux->pids[i]=0xffff; + } + dvbdemux->playing=dvbdemux->recording=0; + memset(dvbdemux->pid2feed, 0, (DMX_MAX_PID+1)*sizeof(dvb_demux_feed_t *)); + dvbdemux->tsbufp=0; + + dmx->frontend=0; + dmx->reg_list.next=dmx->reg_list.prev=&dmx->reg_list; + dmx->priv=(void *) dvbdemux; + //dmx->users=0; // reset in dmx_register_demux() + dmx->open=dvbdmx_open; + dmx->close=dvbdmx_close; + dmx->write=dvbdmx_write; + dmx->allocate_ts_feed=dvbdmx_allocate_ts_feed; + dmx->release_ts_feed=dvbdmx_release_ts_feed; + dmx->allocate_pes_feed=dvbdmx_allocate_pes_feed; + dmx->release_pes_feed=dvbdmx_release_pes_feed; + dmx->allocate_section_feed=dvbdmx_allocate_section_feed; + dmx->release_section_feed=dvbdmx_release_section_feed; + + dmx->descramble_mac_address=NULL; + dmx->descramble_section_payload=NULL; + + dmx->add_frontend=dvbdmx_add_frontend; + dmx->remove_frontend=dvbdmx_remove_frontend; + dmx->get_frontends=dvbdmx_get_frontends; + dmx->connect_frontend=dvbdmx_connect_frontend; + dmx->disconnect_frontend=dvbdmx_disconnect_frontend; + dmx->get_pes_pids=dvbdmx_get_pes_pids; + sema_init(&dvbdemux->mutex, 1); + + if (dmx_register_demux(dmx)<0) + return -1; + + return 0; +} + +int +DvbDmxRelease(dvb_demux_t *dvbdemux) +{ + dmx_demux_t *dmx=&dvbdemux->dmx; + + dmx_unregister_demux(dmx); + if (dvbdemux->filter) + vfree(dvbdemux->filter); + if (dvbdemux->feed) + vfree(dvbdemux->feed); + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dvb_demux.h linux.20pre2-ac1/drivers/media/video/margi/dvb_demux.h --- linux.20pre2/drivers/media/video/margi/dvb_demux.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dvb_demux.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,141 @@ +/* + * dvb_demux.h - DVB kernel demux API + * + * Copyright (C) 2000-2001 Marcus Metzler + * & Ralph Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _DVB_DEMUX_H_ +#define _DVB_DEMUX_H_ + +#if LINUX_VERSION_CODE < 0x020300 +#define WAIT_QUEUE struct wait_queue* +#define init_waitqueue_head(wq) *(wq) = NULL; +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) +#else +#define WAIT_QUEUE wait_queue_head_t +#endif + +#include "ost/demux.h" + +#define DMX_TYPE_TS 0 +#define DMX_TYPE_SEC 1 +#define DMX_TYPE_PES 2 + +#define DMX_STATE_FREE 0 +#define DMX_STATE_ALLOCATED 1 +#define DMX_STATE_SET 2 +#define DMX_STATE_READY 3 +#define DMX_STATE_GO 4 + +#define DVB_DEMUX_MASK_MAX 18 + +typedef struct dvb_demux_filter_s { + dmx_section_filter_t filter; + struct dvb_demux_filter_s *next; + struct dvb_demux_feed_s *feed; + int index; + int state; + int type; + int pesto; + + u32 flags; + u16 handle; + u16 hw_handle; + struct timer_list timer; + int ts_state; + + u16 pid; //to be removed +} dvb_demux_filter_t; + +typedef struct dvb_demux_feed_s { + union { + dmx_ts_feed_t ts; + dmx_section_feed_t sec; + dmx_pes_feed_t pes; + } feed; + + union { + dmx_ts_cb ts; + dmx_section_cb sec; + dmx_pes_cb pes; + } cb; + + struct dvb_demux_s *demux; + int type; + int state; + u16 pid; + u8 *buffer; + int buffer_size; + int descramble; + int check_crc; + + struct timespec timeout; + dvb_demux_filter_t *filter; + int cb_length; + + int ts_type; + dmx_ts_pes_t pes_type; + + u8 secbuf[4096]; + int secbufp; + int seclen; + int cc; + + u16 peslen; +} dvb_demux_feed_t; + +typedef struct dvb_demux_s { + dmx_demux_t dmx; + void *priv; + int filternum; + int feednum; + int (*start_feed)(dvb_demux_feed_t *); + int (*stop_feed)(dvb_demux_feed_t *); + int (*write_to_decoder)(dvb_demux_feed_t *, u8 *, size_t); + + + int users; +#define MAX_DVB_DEMUX_USERS 10 + dvb_demux_filter_t *filter; + dvb_demux_feed_t *feed; + + struct list_head frontend_list; + + dvb_demux_feed_t *pesfilter[DMX_TS_PES_OTHER]; + u16 pids[DMX_TS_PES_OTHER]; + int playing; + int recording; + +#define DMX_MAX_PID 0x2000 + dvb_demux_feed_t *pid2feed[DMX_MAX_PID+1]; + u8 tsbuf[188]; + int tsbufp; + + struct semaphore mutex; +} dvb_demux_t; + + +int DvbDmxInit(dvb_demux_t *dvbdemux); +int DvbDmxRelease(dvb_demux_t *dvbdemux); +void DvbDmxSWFilterPackets(dvb_demux_t *dvbdmx, const u8 *buf, int count); + +#endif /* _DVB_DEMUX_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dvbdev.c linux.20pre2-ac1/drivers/media/video/margi/dvbdev.c --- linux.20pre2/drivers/media/video/margi/dvbdev.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dvbdev.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,233 @@ +/* + * dvbdev.c + * + * Copyright (C) 2000 Ralph Metzler + * & Marcus Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvbdev.h" + +#ifdef MODULE +MODULE_DESCRIPTION("Device registrar for DVB drivers"); +MODULE_AUTHOR("Marcus Metzler, Ralph Metzler"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("LGPL"); +#endif +#endif + +#define DVB_MAJOR 250 + +static struct dvb_device *dvb_device[DVB_NUM_DEVICES]; +static devfs_handle_t dvb_devfs_handle; + +static inline struct dvb_device * +inode2dev (struct inode *inode) +{ + int minor=(MINOR(inode->i_rdev)>>6); + + return dvb_device[minor]; +} + +static inline int +inode2num(struct inode *inode) +{ + return (0x3f&MINOR(inode->i_rdev)); +} + +static ssize_t +dvb_device_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct inode *inode=file->f_dentry->d_inode; + struct dvb_device *dvbdev=inode2dev(inode); + + if (!dvbdev) + return -ENODEV; + return dvbdev->read(dvbdev, inode2num(inode), file, buf, count, ppos); +} + +static ssize_t +dvb_device_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode=file->f_dentry->d_inode; + struct dvb_device *dvbdev=inode2dev(inode); + + if (!dvbdev) + return -ENODEV; + return dvbdev->write(dvbdev, inode2num(inode), file, buf, count, ppos); +} + +static int +dvb_device_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev=inode2dev(inode); + + if (!dvbdev) + return -ENODEV; + return dvbdev->open(dvbdev, inode2num(inode), inode, file); +} + +static int +dvb_device_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev=inode2dev(inode); + + if (!dvbdev) + return -ENODEV; + return dvbdev->close(dvbdev, inode2num(inode), inode, file); +} + +static int +dvb_device_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct dvb_device *dvbdev=inode2dev(inode); + + if (!dvbdev) + return -ENODEV; + return dvbdev->ioctl(dvbdev, inode2num(inode), file, cmd, arg); +} + +static unsigned int +dvb_device_poll(struct file *file, poll_table *wait) +{ + struct inode *inode=file->f_dentry->d_inode; + struct dvb_device *dvbdev=inode2dev(inode); + + if (!dvbdev) + return -ENODEV; + return dvbdev->poll(dvbdev, inode2num(inode), file, wait); +} + + +static struct file_operations dvb_device_fops = +{ + owner: THIS_MODULE, + read: dvb_device_read, + write: dvb_device_write, + ioctl: dvb_device_ioctl, + open: dvb_device_open, + release: dvb_device_release, + poll: dvb_device_poll, +}; + + +static char *dnames[] = { + "video", "audio", "sec", "frontend", "demux", "dvr", "ca", + "net", "osd" +}; + + +static void dvb_init_device(dvb_device_t *dev) +{ + int i, type; + char name[64]; + + sprintf(name, "card%d", dev->minor); + dev->devfsh = devfs_mk_dir (dvb_devfs_handle, name, NULL); + + for (i=0; (type=dev->device_type(dev,i))>-2; i++) { + if (type==-1) + continue; + + sprintf(name, "%s%d", dnames[type>>2], type&3); + devfs_register(dev->devfsh, name, DEVFS_FL_DEFAULT, + DVB_MAJOR, (dev->minor<<6)+i, + S_IFCHR | S_IRUSR | S_IWUSR, + &dvb_device_fops, NULL); + } + +} + +int dvb_register_device(dvb_device_t *dev) +{ + int i=0; + + for (i=0; iminor=i; + dvb_init_device(dev); + MOD_INC_USE_COUNT; + return 0; + } + } + return -ENFILE; +} + +void dvb_unregister_device(dvb_device_t *dev) +{ + if (dvb_device[dev->minor]!=dev) { + printk("dvbdev: bad unregister\n"); + return; + } + devfs_unregister(dev->devfsh); + dvb_device[dev->minor]=NULL; + MOD_DEC_USE_COUNT; +} + +int __init dvbdev_init(void) +{ + int i=0; + + for(i=0; i + * & Marcus Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Lesser Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _DVBDEV_H_ +#define _DVBDEV_H_ + +#include +#include +#include +#include + +#define DVB_NUM_DEVICES 16 + +struct dvb_device +{ + char name[32]; + int type; + int hardware; + + void *priv; + int minor; + devfs_handle_t devfs_handle; + + int (*open)(struct dvb_device *, int, struct inode *, struct file *); + int (*close)(struct dvb_device *, int, struct inode *, struct file *); + ssize_t (*read)(struct dvb_device *, int, struct file *, char *, + size_t, loff_t *); + ssize_t (*write)(struct dvb_device *, int, struct file *, const char *, + size_t, loff_t *); + int (*ioctl)(struct dvb_device *, int, struct file *, + unsigned int , unsigned long); + unsigned int (*poll)(struct dvb_device *, int type, + struct file *file, poll_table * wait); + + int (*device_type)(struct dvb_device *, unsigned int device_num); +#define DVB_DEVICE_VIDEO_0 0 +#define DVB_DEVICE_AUDIO_0 4 +#define DVB_DEVICE_SEC_0 8 +#define DVB_DEVICE_FRONTEND_0 12 +#define DVB_DEVICE_DEMUX_0 16 +#define DVB_DEVICE_DEMUX_1 17 +#define DVB_DEVICE_DEMUX_2 18 +#define DVB_DEVICE_DEMUX_3 19 +#define DVB_DEVICE_DVR_0 20 +#define DVB_DEVICE_CA_0 24 +#define DVB_DEVICE_NET_0 28 +#define DVB_DEVICE_OSD_0 32 + devfs_handle_t devfsh; +}; + +typedef struct dvb_device dvb_device_t; + +int dvb_register_device(struct dvb_device *); +void dvb_unregister_device(struct dvb_device *); + +#endif /* #ifndef __DVBDEV_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dvb_filter.c linux.20pre2-ac1/drivers/media/video/margi/dvb_filter.c --- linux.20pre2/drivers/media/video/margi/dvb_filter.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dvb_filter.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,769 @@ +#include +#include +#include "dvb_filter.h" +#if 0 +#ifdef MODULE +MODULE_DESCRIPTION(""); +MODULE_AUTHOR("Marcus Metzler, Ralph Metzler"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif +#endif +#endif + +unsigned int bitrates[3][16] = +{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, + {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, + {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; + +uint32_t freq[4] = {441, 480, 320, 0}; + +unsigned int ac3_bitrates[32] = + {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, + 0,0,0,0,0,0,0,0,0,0,0,0,0}; + +uint32_t ac3_freq[4] = {480, 441, 320, 0}; +uint32_t ac3_frames[3][32] = + {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, + 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, + 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, + 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + + + +void pes2ts_init(pes2ts_t *p2ts, unsigned short pid, + pes2ts_cb_t *cb, void *priv) +{ + unsigned char *buf=p2ts->buf; + + buf[0]=0x47; + buf[1]=(pid>>8); + buf[2]=pid&0xff; + p2ts->cc=0; + p2ts->cb=cb; + p2ts->priv=priv; +} + +int pes2ts(pes2ts_t *p2ts, unsigned char *pes, int len) +{ + unsigned char *buf=p2ts->buf; + int ret=0, rest; + + //len=6+((pes[4]<<8)|pes[5]); + + buf[1]|=0x40; + while (len>=184) { + buf[3]=0x10|((p2ts->cc++)&0x0f); + memcpy(buf+4, pes, 184); + if ((ret=p2ts->cb(p2ts->priv, buf))) + return ret; + len-=184; pes+=184; + buf[1]&=~0x40; + } + if (!len) + return 0; + buf[3]=0x30|((p2ts->cc++)&0x0f); + rest=183-len; + if (rest) { + buf[5]=0x00; + if (rest-1) + memset(buf+6, 0xff, rest-1); + } + buf[4]=rest; + memcpy(buf+5+rest, pes, len); + return p2ts->cb(p2ts->priv, buf); +} + +void reset_ipack(ipack *p) +{ + p->found = 0; + p->cid = 0; + p->plength = 0; + p->flag1 = 0; + p->flag2 = 0; + p->hlength = 0; + p->mpeg = 0; + p->check = 0; + p->which = 0; + p->done = 0; + p->count = 0; +} + +void init_ipack(ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)) +{ + if ( !(p->buf = vmalloc(size*sizeof(u8))) ){ + printk ("Couldn't allocate memory for ipack\n"); + } + p->size = size; + p->func = func; + p->repack_subids = 0; + reset_ipack(p); +} + +void free_ipack(ipack * p) +{ + if (p->buf) vfree(p->buf); +} + +void send_ipack(ipack *p) +{ + int off; + AudioInfo ai; + int ac3_off = 0; + int streamid=0; + int nframes= 0; + int f=0; + + switch ( p->mpeg ){ + case 2: + if (p->count < 10) return; + p->buf[3] = p->cid; + + p->buf[4] = (u8)(((p->count-6) & 0xFF00) >> 8); + p->buf[5] = (u8)((p->count-6) & 0x00FF); + if (p->repack_subids && p->cid == PRIVATE_STREAM1){ + + off = 9+p->buf[8]; + streamid = p->buf[off]; + if ((streamid & 0xF8) == 0x80){ + ai.off = 0; + ac3_off = ((p->buf[off+2] << 8)| + p->buf[off+3]); + if (ac3_off < p->count) + f=get_ac3info(p->buf+off+3+ac3_off, + p->count-ac3_off, &ai,0); + if ( !f ){ + nframes = (p->count-off-3-ac3_off)/ + ai.framesize + 1; + p->buf[off+2] = (ac3_off >> 8)& 0xFF; + p->buf[off+3] = (ac3_off)& 0xFF; + p->buf[off+1] = nframes; + + ac3_off += nframes * ai.framesize - + p->count; + } + } + } + p->func(p->buf, p->count, p->data); + + p->buf[6] = 0x80; + p->buf[7] = 0x00; + p->buf[8] = 0x00; + p->count = 9; + if (p->repack_subids && p->cid == PRIVATE_STREAM1 + && (streamid & 0xF8)==0x80 ){ + p->count += 4; + p->buf[9] = streamid; + p->buf[10] = (ac3_off >> 8)& 0xFF; + p->buf[11] = (ac3_off)& 0xFF; + p->buf[12] = 0; + } + + break; + case 1: + if (p->count < 8) return; + p->buf[3] = p->cid; + + p->buf[4] = (u8)(((p->count-6) & 0xFF00) >> 8); + p->buf[5] = (u8)((p->count-6) & 0x00FF); + p->func(p->buf, p->count, p->data); + + p->buf[6] = 0x0F; + p->count = 7; + break; + } +} + +void send_ipack_rest(ipack *p) +{ + if (p->plength != MMAX_PLENGTH-6 || p->found<=6) + return; + p->plength = p->found-6; + p->found = 0; + send_ipack(p); + reset_ipack(p); +} + +static void write_ipack(ipack *p, u8 *data, int count) +{ + u8 headr[3] = { 0x00, 0x00, 0x01} ; + + if (p->count < 6){ + memcpy(p->buf, headr, 3); + p->count = 6; + } + + if (p->count + count < p->size){ + memcpy(p->buf+p->count, data, count); + p->count += count; + } else { + int rest = p->size - p->count; + memcpy(p->buf+p->count, data, rest); + p->count += rest; + send_ipack(p); + if (count - rest > 0) + write_ipack(p, data+rest, count-rest); + } +} + +int instant_repack(u8 *buf, int count, ipack *p) +{ + int l; + int c=0; + + while (c < count && (p->mpeg == 0 || + (p->mpeg == 1 && p->found < 7) || + (p->mpeg == 2 && p->found < 9)) + && (p->found < 5 || !p->done)){ + switch ( p->found ){ + case 0: + case 1: + if (buf[c] == 0x00) p->found++; + else p->found = 0; + c++; + break; + case 2: + if (buf[c] == 0x01) p->found++; + else if (buf[c] == 0) { + p->found = 2; + } else p->found = 0; + c++; + break; + case 3: + p->cid = 0; + switch (buf[c]){ + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + p->done = 1; + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + p->found++; + p->cid = buf[c]; + c++; + break; + default: + p->found = 0; + break; + } + break; + + case 4: + if (count-c > 1){ + p->plen[0] = buf[c]; + c++; + p->plen[1] = buf[c]; + c++; + p->found+=2; + p->plength=(p->plen[0]<<8)|p->plen[1]; + } else { + p->plen[0] = buf[c]; + p->found++; + return count; + } + break; + case 5: + p->plen[1] = buf[c]; + c++; + p->found++; + p->plength=(p->plen[0]<<8)|p->plen[1]; + break; + case 6: + if (!p->done){ + p->flag1 = buf[c]; + c++; + p->found++; + if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; + else { + p->hlength = 0; + p->which = 0; + p->mpeg = 1; + p->flag2 = 0; + } + } + break; + + case 7: + if ( !p->done && p->mpeg == 2) { + p->flag2 = buf[c]; + c++; + p->found++; + } + break; + + case 8: + if ( !p->done && p->mpeg == 2) { + p->hlength = buf[c]; + c++; + p->found++; + } + break; + + default: + + break; + } + } + + if (c == count) return count; + + if (!p->plength) p->plength = MMAX_PLENGTH-6; + + if ( p->done || ((p->mpeg == 2 && p->found >= 9) || + (p->mpeg == 1 && p->found >= 7)) ){ + switch (p->cid){ + + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + + if (p->mpeg == 2 && p->found == 9) { + write_ipack(p, &p->flag1, 1); + write_ipack(p, &p->flag2, 1); + write_ipack(p, &p->hlength, 1); + } + + if (p->mpeg == 1 && p->found == 7) + write_ipack(p, &p->flag1, 1); + + if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && + p->found < 14) { + while (c < count && p->found < 14) { + p->pts[p->found-9] = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + } + if (c == count) return count; + } + + if (p->mpeg == 1 && p->which < 2000) { + + if (p->found == 7) { + p->check = p->flag1; + p->hlength = 1; + } + + while (!p->which && c < count && + p->check == 0xFF){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + } + + if ( c == count) return count; + + if ( (p->check & 0xC0) == 0x40 && !p->which){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + + p->which = 1; + if ( c == count) return count; + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return count; + } + + if (p->which == 1){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return count; + } + + if ( (p->check & 0x30) && p->check != 0xFF){ + p->flag2 = (p->check & 0xF0) << 2; + p->pts[0] = p->check; + p->which = 3; + } + + if ( c == count) return count; + if (p->which > 2){ + if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_ONLY){ + while (c < count && + p->which < 7){ + p->pts[p->which-2] = + buf[c]; + write_ipack(p,buf+c,1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return count; + } else if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_DTS){ + while (c < count && + p->which< 12){ + if (p->which< 7) + p->pts[p->which + -2] = + buf[c]; + write_ipack(p,buf+c,1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return count; + } + p->which = 2000; + } + + } + + while (c < count && p->found < p->plength+6){ + l = count -c; + if (l+p->found > p->plength+6) + l = p->plength+6-p->found; + write_ipack(p, buf+c, l); + p->found += l; + c += l; + } + + break; + } + + + if ( p->done ){ + if( p->found + count - c < p->plength+6){ + p->found += count-c; + c = count; + } else { + c += p->plength+6 - p->found; + p->found = p->plength+6; + } + } + + if (p->plength && p->found == p->plength+6) { + send_ipack(p); + reset_ipack(p); + if (c < count) + instant_repack(buf+c, count-c, p); + } + } + return count; +} + + + +void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, + void (*pes_write)(u8 *buf, int count, void *data), + void *priv) +{ + init_ipack(pa, IPACKS, pes_write); + init_ipack(pv, IPACKS, pes_write); + pa->pid = pida; + pv->pid = pidv; + pa->data = priv; + pv->data = priv; +} + +void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) +{ + u8 off = 0; + + if (!buf || !p ){ + printk("NULL POINTER IDIOT\n"); + return; + } + if (buf[1]&PAY_START) { + if (p->plength == MMAX_PLENGTH-6 && p->found>6){ + p->plength = p->found-6; + p->found = 0; + send_ipack(p); + reset_ipack(p); + } + } + if (buf[3] & ADAPT_FIELD) { // adaptation field? + off = buf[4] + 1; + if (off+4 > 187) return; + } + instant_repack(buf+4+off, TS_SIZE-4-off, p); +} + +int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) +{ + uint8_t *headr; + int found = 0; + int sw; + int form = -1; + int c = 0; + + while (found < 4 && c+4 < count){ + uint8_t *b; + + b = mbuf+c; + if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 + && b[3] == 0xb3) found = 4; + else { + c++; + } + } + + if (! found) return -1; + c += 4; + if (c+12 >= count) return -1; + headr = mbuf+c; + + vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); + vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); + + sw = (int)((headr[3]&0xF0) >> 4) ; + + switch( sw ){ + case 1: + if (pr) + printk("Videostream: ASPECT: 1:1"); + vi->aspect_ratio = 100; + break; + case 2: + if (pr) + printk("Videostream: ASPECT: 4:3"); + vi->aspect_ratio = 133; + break; + case 3: + if (pr) + printk("Videostream: ASPECT: 16:9"); + vi->aspect_ratio = 177; + break; + case 4: + if (pr) + printk("Videostream: ASPECT: 2.21:1"); + vi->aspect_ratio = 221; + break; + + case 5 ... 15: + if (pr) + printk("Videostream: ASPECT: reserved"); + vi->aspect_ratio = 0; + break; + + default: + vi->aspect_ratio = 0; + return -1; + } + + if (pr) + printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); + + sw = (int)(headr[3]&0x0F); + + switch ( sw ) { + case 1: + if (pr) + printk(" FRate: 23.976 fps"); + vi->framerate = 24000/1001.; + form = -1; + break; + case 2: + if (pr) + printk(" FRate: 24 fps"); + vi->framerate = 24; + form = -1; + break; + case 3: + if (pr) + printk(" FRate: 25 fps"); + vi->framerate = 25; + form = VIDEO_MODE_PAL; + break; + case 4: + if (pr) + printk(" FRate: 29.97 fps"); + vi->framerate = 30000/1001.; + form = VIDEO_MODE_NTSC; + break; + case 5: + if (pr) + printk(" FRate: 30 fps"); + vi->framerate = 30; + form = VIDEO_MODE_NTSC; + break; + case 6: + if (pr) + printk(" FRate: 50 fps"); + vi->framerate = 50; + form = VIDEO_MODE_PAL; + break; + case 7: + if (pr) + printk(" FRate: 60 fps"); + vi->framerate = 60; + form = VIDEO_MODE_NTSC; + break; + } + + vi->bit_rate = 400*(((headr[4] << 10) & 0x0003FC00UL) + | ((headr[5] << 2) & 0x000003FCUL) | + (((headr[6] & 0xC0) >> 6) & 0x00000003UL)); + + if (pr){ + printk(" BRate: %d Mbit/s",(vi->bit_rate)); + printk("\n"); + } + vi->video_format = form; + + vi->off = c-4; + return 0; +} + +int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) +{ + uint8_t *headr; + int found = 0; + int c = 0; + int fr = 0; + + while (found < 2 && c < count){ + uint8_t b[2]; + memcpy( b, mbuf+c, 2); + + if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) + found = 2; + else { + c++; + } + } + + if (!found) return -1; + + if (c+3 >= count) return -1; + headr = mbuf+c; + + ai->layer = (headr[1] & 0x06) >> 1; + + if (pr) + printk("Audiostream: Layer: %d", 4-ai->layer); + + + ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; + + if (pr){ + if (ai->bit_rate == 0) + printk(" Bit rate: free"); + else if (ai->bit_rate == 0xf) + printk(" BRate: reserved"); + else + printk(" BRate: %d kb/s", ai->bit_rate/1000); + } + + fr = (headr[2] & 0x0c ) >> 2; + ai->frequency = freq[fr]*100; + if (pr){ + if (ai->frequency == 3) + printk(" Freq: reserved\n"); + else + printk(" Freq: %d kHz\n",ai->frequency); + + } + ai->off = c; + return 0; +} + +int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr) +{ + uint8_t *headr; + int found = 0; + int c = 0; + uint8_t frame = 0; + int fr = 0; + + while ( !found && c < count){ + uint8_t *b = mbuf+c; + + if ( b[0] == 0x0b && b[1] == 0x77 ) + found = 1; + else { + c++; + } + } + + if (!found) return -1; + if (pr) + printk("Audiostream: AC3"); + + ai->off = c; + if (c+5 >= count) return -1; + + ai->layer = 0; // 0 for AC3 + headr = mbuf+c+2; + + frame = (headr[2]&0x3f); + ai->bit_rate = ac3_bitrates[frame >> 1]*1000; + + if (pr) + printk(" BRate: %d kb/s", ai->bit_rate/1000); + + ai->frequency = (headr[2] & 0xc0 ) >> 6; + fr = (headr[2] & 0xc0 ) >> 6; + ai->frequency = freq[fr]*100; + if (pr) printk (" Freq: %d Hz\n", ai->frequency); + + + ai->framesize = ac3_frames[fr][frame >> 1]; + if ((frame & 1) && (fr == 1)) ai->framesize++; + ai->framesize = ai->framesize << 1; + if (pr) printk (" Framesize %d\n", ai->framesize); + + + return 0; +} + +uint8_t *skip_pes_header(uint8_t **bufp) +{ + uint8_t *inbuf = *bufp; + uint8_t *buf = inbuf; + uint8_t *pts = NULL; + int skip = 0; + +int mpeg1_skip_table[16] = { + 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff +}; + + + if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ + if (buf[7] & PTS_ONLY) + pts = buf+9; + else pts = NULL; + buf = inbuf + 9 + inbuf[8]; + } else { /* mpeg1 */ + for (buf = inbuf + 6; *buf == 0xff; buf++) + if (buf == inbuf + 6 + 16) { + break; + } + if ((*buf & 0xc0) == 0x40) + buf += 2; + skip = mpeg1_skip_table [*buf >> 4]; + if (skip == 5 || skip == 10) pts = buf; + else pts = NULL; + + buf += mpeg1_skip_table [*buf >> 4]; + } + + *bufp = buf; + return pts; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dvb_filter.h linux.20pre2-ac1/drivers/media/video/margi/dvb_filter.h --- linux.20pre2/drivers/media/video/margi/dvb_filter.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dvb_filter.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,146 @@ +#ifndef _DVB_FILTER_H_ +#define _DVB_FILTER_H_ + +#include +#include + +#include "ost/demux.h" + +typedef int (pes2ts_cb_t) (void *, unsigned char *); + +typedef struct pes2ts_s { + unsigned char buf[188]; + unsigned char cc; + pes2ts_cb_t *cb; + void *priv; +} pes2ts_t; + +void pes2ts_init(pes2ts_t *p2ts, unsigned short pid, + pes2ts_cb_t *cb, void *priv); +int pes2ts(pes2ts_t *p2ts, unsigned char *pes, int len); + + +#define PROG_STREAM_MAP 0xBC +#define PRIVATE_STREAM1 0xBD +#define PADDING_STREAM 0xBE +#define PRIVATE_STREAM2 0xBF +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +//flags2 +#define PTS_DTS_FLAGS 0xC0 +#define ESCR_FLAG 0x20 +#define ES_RATE_FLAG 0x10 +#define DSM_TRICK_FLAG 0x08 +#define ADD_CPY_FLAG 0x04 +#define PES_CRC_FLAG 0x02 +#define PES_EXT_FLAG 0x01 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 + +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +#define MAX_PLENGTH 0xFFFF +#define MMAX_PLENGTH (256*MAX_PLENGTH) + +#ifndef IPACKS +#define IPACKS 2048 +#endif + +typedef struct ipack_s { + int size; + int found; + u8 *buf; + u8 cid; + uint32_t plength; + u8 plen[2]; + u8 flag1; + u8 flag2; + u8 hlength; + u8 pts[5]; + u16 *pid; + int mpeg; + u8 check; + int which; + int done; + void *data; + void (*func)(u8 *buf, int size, void *priv); + int count; + int repack_subids; +} ipack; + +typedef struct video_i{ + u32 horizontal_size; + u32 vertical_size ; + u32 aspect_ratio ; + double framerate ; + u32 video_format; + u32 bit_rate ; + u32 comp_bit_rate ; + u32 vbv_buffer_size; + u32 CSPF ; + u32 off; +} VideoInfo; + +typedef struct audio_i{ + int layer ; + u32 bit_rate ; + u32 frequency ; + u32 mode ; + u32 mode_extension ; + u32 emphasis ; + u32 framesize; + u32 off; +} AudioInfo; + +void reset_ipack(ipack *p); +int instant_repack(u8 *buf, int count, ipack *p); +void init_ipack(ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)); +void free_ipack(ipack * p); +void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, + void (*pes_write)(u8 *buf, int count, void *data), + void *priv); +void ts_to_pes(ipack *p, u8 *buf); +void send_ipack(ipack *p); +void send_ipack_rest(ipack *p); +int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr); +int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr); +int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr); +uint8_t *skip_pes_header(uint8_t **bufp); +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/dvb_formats.h linux.20pre2-ac1/drivers/media/video/margi/dvb_formats.h --- linux.20pre2/drivers/media/video/margi/dvb_formats.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/dvb_formats.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,152 @@ +/* + * + * Copyright (C) 2000, 2001 Marcus Metzler + * for convergence integrated media GmbH + * + * 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. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + + * The author can be reached at marcus@convergence.de, + + * the project's page is at http://linuxtv.org/dvb/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _DVB_FORMATS_H_ +#define _DVB_FORMATS_H_ + + +#define PROG_STREAM_MAP 0xBC +#ifndef PRIVATE_STREAM1 +#define PRIVATE_STREAM1 0xBD +#endif +#define PADDING_STREAM 0xBE +#ifndef PRIVATE_STREAM2 +#define PRIVATE_STREAM2 0xBF +#endif +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define BUFFYSIZE 10*MAX_PLENGTH +//#define MAX_PTS 8192 +#define MAX_FRAME 8192 +#define MAX_PACK_L 4096 +#define PS_HEADER_L1 14 +#define PS_HEADER_L2 (PS_HEADER_L1+18) +#define MAX_H_SIZE (PES_H_MIN + PS_HEADER_L1 + 5) +#define PES_MIN 7 +#define PES_H_MIN 9 + +//flags2 +#define PTS_DTS_FLAGS 0xC0 +#define ESCR_FLAG 0x20 +#define ES_RATE_FLAG 0x10 +#define DSM_TRICK_FLAG 0x08 +#define ADD_CPY_FLAG 0x04 +#define PES_CRC_FLAG 0x02 +#define PES_EXT_FLAG 0x01 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 + +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +#define MAX_PLENGTH 0xFFFF +#define MMAX_PLENGTH (4*MAX_PLENGTH) + +#define IPACKS 2048 + +typedef struct ipack_s { + int size; + int found; + uint8_t *buf; + uint8_t cid; + uint32_t plength; + uint8_t plen[2]; + uint8_t flag1; + uint8_t flag2; + uint8_t hlength; + uint8_t pts[5]; + uint16_t *pid; + int mpeg; + uint8_t check; + int which; + int done; + void *data; + void (*func)(uint8_t *buf, int size, void *priv); + int count; +} ipack; + +void instant_repack (uint8_t *buf, int count, ipack *p); +void init_ipack(ipack *p, int size, + void (*func)(uint8_t *buf, int size, void *priv)); +void free_ipack(ipack * p); +void setup_ts2pes( ipack *pa, ipack *pv, uint16_t *pida, uint16_t *pidv, + void (*pes_write)(uint8_t *buf, int count, void *data), + void *priv); +void ts_to_pes( ipack *p, uint8_t *buf); // don't need count (=188) +uint16_t get_pid(uint8_t *pid); + + +#endif /* _DVB_FORMATS_H_*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/i2c.c linux.20pre2-ac1/drivers/media/video/margi/i2c.c --- linux.20pre2/drivers/media/video/margi/i2c.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/i2c.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,186 @@ +/* + i2c.h + + Copyright (C) Marcus Metzler for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define __NO_VERSION__ + +#include "i2c.h" + +void out(struct cvdv_cards *card) +{ + write_indexed_register(card, IIO_GPIO_PINS, + (card->scl ? SCL : 0) | + (card->sda ? SDA : 0) | 1); + udelay(10); +} + +void clkon(struct cvdv_cards *card) +{ + card->scl = 1; +} + +void clkoff(struct cvdv_cards *card) +{ + card->scl = 0; +} + +void dat(struct cvdv_cards *card, u_char data) +{ + card->sda = data; +} + +int rdat(struct cvdv_cards *card) +{ + return ((read_indexed_register(card, IIO_GPIO_PINS) & SDA) ? 1 : + 0); +} + + +void I2CStart(struct cvdv_cards *card) +{ + dat(card, 1); + out(card); + clkon(card); + out(card); + dat(card, 0); + out(card); + clkoff(card); + out(card); +} + +void I2CStop(struct cvdv_cards *card) +{ + dat(card, 0); + out(card); + clkon(card); + out(card); + dat(card, 1); + out(card); + clkoff(card); + out(card); +} + +int I2CAck(struct cvdv_cards *card, int ack) +{ + dat(card, ack); + out(card); + write_indexed_register(card, IIO_GPIO_CONTROL, (~SDA) & 0x07); + clkon(card); + out(card); + ack = rdat(card); + clkoff(card); + out(card); + write_indexed_register(card, IIO_GPIO_CONTROL, 0x07); + out(card); + return ack; +} + +u_char I2CReadByte(struct cvdv_cards * card, int ack) +{ + int i; + u_char data = 0; + + clkoff(card); + dat(card, 1); + out(card); + write_indexed_register(card, IIO_GPIO_CONTROL, (~SDA) & 0x07); + for (i = 7; i >= 0; i--) { + clkon(card); + out(card); + data |= (rdat(card) << i); + clkoff(card); + out(card); + } + write_indexed_register(card, IIO_GPIO_CONTROL, 0x07); + I2CAck(card, ack); + return data; +} + + +int I2CSendByte(struct cvdv_cards *card, u_char data) +{ + int i; + + for (i = 7; i >= 0; i--) { + dat(card, data & (1 << i)); + out(card); + clkon(card); + out(card); + clkoff(card); + out(card); + } + i = I2CAck(card, 1); + return i; +} + +void I2CWrite(struct cvdv_cards *card, int adr, int reg, int val) +{ + I2CStart(card); + I2CSendByte(card, adr); + I2CSendByte(card, reg); + I2CSendByte(card, val); + I2CStop(card); +} + + +u_char I2CRead(struct cvdv_cards *card, int adr, int reg) +{ + u_char c; + + I2CStart(card); + I2CSendByte(card, adr); + I2CSendByte(card, reg); + I2CStart(card); + I2CSendByte(card, adr | 1); + c = I2CReadByte(card, 1); + I2CStop(card); + return c; +} + + +int I2CScan(struct cvdv_cards *card, int adr) +{ + int result; + I2CStart(card); + result = I2CSendByte(card, adr); + I2CStop(card); + return result; +} + +void I2CScanBus(struct cvdv_cards *card) +{ + int i; + + for (i = 0; i < 0xff; i += 2) { + if (!I2CScan(card, i)) + MDEBUG(0,"Found i2c device at %d\n", i); + } +} + +void I2CSend(struct cvdv_cards *card, int adr, u_char * vals) +{ + int reg, val; + while (*vals != 0xff) { + reg = *vals; + vals++; + val = *vals; + vals++; + I2CWrite(card, adr, reg, val); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/i2c.h linux.20pre2-ac1/drivers/media/video/margi/i2c.h --- linux.20pre2/drivers/media/video/margi/i2c.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/i2c.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,43 @@ +/* + i2c.h + + Copyright (C) Marcus Metzler for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef I2C_H +#define I2C_H +#include "cardbase.h" +#include "l64014.h" +#include "margi.h" + +void out(struct cvdv_cards *card); +void clkon(struct cvdv_cards *card); +void clkoff(struct cvdv_cards *card); +void dat(struct cvdv_cards *card, u_char data); +int rdat(struct cvdv_cards *card); +void I2CStart(struct cvdv_cards *card); +void I2CStop(struct cvdv_cards *card); +int I2CAck(struct cvdv_cards *card, int ack); +u_char I2CReadByte(struct cvdv_cards *card, int ack); +int I2CSendByte(struct cvdv_cards *card, u_char data); +void I2CWrite(struct cvdv_cards *card, int adr, int reg, int val); +u_char I2CRead(struct cvdv_cards *card, int adr, int reg); +int I2CScan(struct cvdv_cards *card, int adr); +void I2CScanBus(struct cvdv_cards *card); +void I2CSend(struct cvdv_cards *card, int adr, u_char * vals); + +#endif /* I2C_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/l64014.h linux.20pre2-ac1/drivers/media/video/margi/l64014.h --- linux.20pre2/drivers/media/video/margi/l64014.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/l64014.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,188 @@ +/* + l64014.h + + Copyright (C) Marcus Metzler for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef L64014_h +#define L64014_h + +#include +#include +#include + + +#define DIO_CONTROL_INDEX 0x00 +#define DIO_CONTROL_DATA 0x02 +#define DIO_LSI_STATUS 0x04 +#define DIO_LSI_CHANNEL_DATA 0x04 +#define DIO_LSI_INDEX_LOW 0x08 +#define DIO_LSI_DATA 0x0A +#define DIO_LSI_INDEX_HIGH 0x0C + +#define LSI_READY 0x08 +#define LSI_WAIT 0x04 +#define LSI_ARQ 0x02 +#define LSI_VRQ 0x01 + +#define IIO_ID 0x00 +#define IIO_MODE 0x01 +#define IIO_IRQ_CONTROL 0x02 +#define IIO_IRQ_STATUS 0x03 +#define IIO_LSI_CONTROL 0x06 +#define IIO_OSC_AUD 0x08 +#define IIO_VIDEO_CONTROL0 0x09 +#define IIO_VIDEO_CONTROL1 0x0A +#define IIO_VIDEO_LOOKUP 0x0B +#define IIO_EEPROM_CONTROL 0x0C +#define IIO_VIDEO_HOR_DELAY 0x0D +#define IIO_VIDEO_HOR_ACTIVE 0x0E +#define IIO_VIDEO_HOR_HIGH 0x0F +#define IIO_GPIO_CONTROL 0x10 +#define IIO_GPIO_PINS 0x11 +#define IIO_CSS_COMMAND 0x12 +#define IIO_CSS_STATUS 0x13 +#define IIO_CSS_KEY 0x14 + +#define SCL 0x02 +#define SDA 0x04 + +#define CS_CONTROL0 0x00 +#define CS_CONTROL1 0x01 +#define CS_CONTROL2 0x02 +#define CS_DAC 0x04 +#define CS_STATUS 0x07 +#define CS_BKG_COL 0x08 +#define CS_GPIO_CTRL 0x09 +#define CS_GPIO_DATA 0x0A +#define CS_C_AMP 0x0D +#define CS_Y_AMP 0x0E +#define CS_I2C_ADR 0x0F +#define CS_SC_AMP 0x10 +#define CS_SC_SYNTH0 0x11 +#define CS_SC_SYNTH1 0x12 +#define CS_SC_SYNTH2 0x13 +#define CS_SC_SYNTH3 0x14 +#define CS_HUE_LSB 0x15 +#define CS_HUE_MSB 0x16 +#define CS_CC_EN 0x18 +#define CS_CC_21_1 0x19 +#define CS_CC_21_2 0x1A +#define CS_CC_284_1 0x1B +#define CS_CC_284_2 0x1C +#define CS_INT_EN 0x3B +#define CS_INT_CLR 0x3C +#define CS_ID_REG 0x3D + + +#define CSS_COMMAND 0x12 +#define CSS_STATUS 0x13 +#define CSS_KEY 0x14 + +#define L14_CSS_NONE 0x00 +#define L14_CSS_PASSTHRU 0x01 +#define L14_CSS_DESCRAM 0x05 +#define L14_CSS_GEN_CH 0x08 +#define L14_CSS_RD_CH 0x09 +#define L14_CSS_WR_CH 0x0a +#define L14_CSS_WR_DRVREF 0x0b +#define L14_CSS_DRVAUTH 0x0c +#define L14_CSS_DECAUTH 0x0d +#define L14_CSS_DISCKEY 0x0e +#define L14_CSS_TITLEKEY 0x0f +#define L14_CSS_CMD_START 0x10 + +#define L14_CSS_BUSY 0x01 +#define L14_CSS_SUCCESS 0x02 + +#define DSVC 0x40 +#define RR 0x20 +#define DR 0x01 +#define AF1 0x20 +#define AF0 0x10 +#define SLEEP 0x08 +#define AFS2 0x04 +#define AFS1 0x02 +#define AFS0 0x01 + +#define ZVCLK13 0x04 +#define ZVCLKINV 0x08 +#define ZV16BIT 0x10 +#define ZVVREF_INVERT 0x08 +#define ZVHREF_INVERT 0x10 +#define HSYNC_INVERT 0x20 +#define ZV_OVERRIDE 0x40 +#define ZV_ENABLE 0x80 + + +#define IRQ_EN 0x04 +#define IRQ_MSK 0x08 +#define IRQ_POL 0x10 +#define DEC_EN 0x20 +#define DEC_INT 0x10 +#define VSYNC_EN 0x80 +#define VSYNC_INT 0x40 + +#define VMS_NOSY 0x00 +#define VMS_NTSC 0x01 +#define VMS_PAL 0x02 +#define VMS_PAL24 0x03 + +#define MAUDIO_PAUSE 0 +#define MAUDIO_PLAY 1 +#define MAUDIO_FAST 2 +#define MAUDIO_SLOW 3 + + +#define RegisterReadByte(card,where) read_indexed_register(&(card->link),(where)) +#define RegisterWriteByte(card,where,what) write_indexed_register(&(card->link),where,what) +#define RegisterMaskByte(card,where,mask,bits) RegisterWriteByte(card,where,(RegisterReadByte(card,where)&~(mask))|(bits)) +#define RegisterSetByte(card,where,bits) RegisterWriteByte(card,where,RegisterReadByte(card,where)|(bits)) +#define RegisterDelByte(card,where,mask) RegisterWriteByte(card,where,RegisterReadByte(card,where)&~(mask)) + +#define RegisterReadWord(card,where) (\ + (u16)RegisterReadByte(card,where)|\ + ((u16)RegisterReadByte(card,(where)+1)<<8)) +#define RegisterWriteWord(card,where,what) {\ + RegisterWriteByte(card,where,(what) & 0xFF);\ + RegisterWriteByte(card,(where)+1,((what)>>8) & 0xFF);} + +// 3-byte-wide (medium word, 24 Bit) access to the card's registers, LSB first +#define RegisterReadMWord(card,where) (\ + (u32)RegisterReadByte(card,where)|\ + ((u32)RegisterReadByte(card,(where)+1)<<8)|\ + ((u32)RegisterReadByte(card,(where)+2)<<16)) +#define RegisterWriteMWord(card,where,what) {\ + RegisterWriteByte(card,where,(what) & 0xFF);\ + RegisterWriteByte(card,(where)+1,((what)>>8) & 0xFF);\ + RegisterWriteByte(card,(where)+2,((what)>>16) & 0xFF);} + +// double-word-wide access to the card's registers, LSB first +//#define RegisterReadDWord(card,where) le32_to_cpu(readl(card->addr+(where))) +//#define RegisterWriteDWord(card,where,what) writel(cpu_to_le32(what),card->addr+(where)) +#define RegisterReadDWord(card,where) (\ + (u32)RegisterReadByte(card,where)|\ + ((u32)RegisterReadByte(card,(where)+1)<<8)|\ + ((u32)RegisterReadByte(card,(where)+2)<<16)|\ + ((u32)RegisterReadByte(card,(where)+3)<<24)) +#define RegisterWriteDWord(card,where,what) {\ + RegisterWriteByte(card,where,(what) & 0xFF);\ + RegisterWriteByte(card,(where)+1,((what)>>8) & 0xFF);\ + RegisterWriteByte(card,(where)+2,((what)>>16) & 0xFF);\ + RegisterWriteByte(card,(where)+3,((what)>>24) & 0xFF);} + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/l64021.h linux.20pre2-ac1/drivers/media/video/margi/l64021.h --- linux.20pre2/drivers/media/video/margi/l64021.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/l64021.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,108 @@ +/* + l64021.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _L64021_H_ +#define _L64021_H_ + +#include "margi.h" +#include "l64014.h" +// L64021 DRAM definitions + +#define DRAMMaxSize 0x00200000 // 2 MWords of DRAM + +// definitions for the L64021 + +#define DECODER_OFFSET 0x400 + +#define L21INTR0 0x000 +#define L21INTR1 0x001 +#define L21INTR2 0x002 +#define L21INTR3 0x003 +#define L21INTR4 0x004 + + +// Host interface registers + +// Video Decoder Registers + +// CSS Regs + +// Memory Interface + +// Microcontroller + +// Video Interface + +// Audio Decoder + +// RAM Test + +// SPU Decoder + + + + + //////////////////////////////////////////////////// + // // + // Access to the L64021 registers (0x400-0x7FF) // + // // +//////////////////////////////////////////////////// + +#define DecoderWriteByte(card,where,what) WriteByte(card,where,what) +#define DecoderReadByte(card,where) ReadByte(card,where) +#define DecoderMaskByte(card,where,mask,bits) MaskByte(card,where,mask,bits) +#define DecoderSetByte(card,addr,bits) DecoderWriteByte(card,addr,DecoderReadByte(card,addr)|(bits)) +#define DecoderDelByte(card,addr,mask) DecoderWriteByte(card,addr,DecoderReadByte(card,addr)&~(mask)) + +#define DecoderReadWord(card,addr) ((u16)DecoderReadByte(card,addr)|\ + ((u16)DecoderReadByte(card,(addr)+1)<<8)) + +#define DecoderWriteWord(card,addr,data) {\ + DecoderWriteByte(card,addr,(data) & 0xFF);\ + DecoderWriteByte(card,(addr)+1,((data)>>8) & 0xFF);} + + +#define DecoderReadMWord(card, addr)(\ + (u32)DecoderReadByte(card,addr)|\ + ((u32)DecoderReadByte(card,(addr)+1)<<8)|\ + ((u32)DecoderReadByte(card,(addr)+2)<<16)) + +#define DecoderWriteMWord(card,addr,data) {\ + DecoderWriteByte(card,addr,(data) & 0xFF);\ + DecoderWriteByte(card,(addr)+1,((data)>>8) & 0xFF);\ + DecoderWriteByte(card,(addr)+2,((data)>>16) & 0xFF);} + +#define DecoderReadDWord(card,addr) (\ + (u32)DecoderReadByte(card,addr)|\ + ((u32)DecoderReadByte(card,(addr)+1)<<8)|\ + ((u32)DecoderReadByte(card,(addr)+2)<<16)|\ + ((u32)DecoderReadByte(card,(addr)+3)<<24)) + +#define DecoderWriteDWord(card,addr,data) {\ + DecoderWriteByte(card,addr,(data) & 0xFF);\ + DecoderWriteByte(card,(addr)+1,((data)>>8) & 0xFF);\ + DecoderWriteByte(card,(addr)+2,((data)>>16) & 0xFF);\ + DecoderWriteByte(card,(addr)+3,((data)>>24) & 0xFF);} + + +void l64020Reset(struct cvdv_cards *card); + + +#endif // _L64021_H_ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/makedev.napi linux.20pre2-ac1/drivers/media/video/margi/makedev.napi --- linux.20pre2/drivers/media/video/margi/makedev.napi 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/makedev.napi 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,28 @@ +mkdir /dev/ost +chmod 755 /dev/ost +mknod -m 0666 /dev/ost/video0 c 250 0 +mknod -m 0666 /dev/ost/audio0 c 250 1 +mknod -m 0666 /dev/ost/sec0 c 250 2 +mknod -m 0666 /dev/ost/qpskfe0 c 250 3 +mknod -m 0666 /dev/ost/qamfe0 c 250 7 +mknod -m 0666 /dev/ost/demux0 c 250 4 +mknod -m 0666 /dev/ost/dvr0 c 250 5 +mknod -m 0666 /dev/ost/ca0 c 250 6 + +mknod -m 0666 /dev/ost/video1 c 250 64 +mknod -m 0666 /dev/ost/audio1 c 250 65 +mknod -m 0666 /dev/ost/sec1 c 250 66 +mknod -m 0666 /dev/ost/qpskfe1 c 250 67 +mknod -m 0666 /dev/ost/qamfe1 c 250 71 +mknod -m 0666 /dev/ost/demux1 c 250 68 +mknod -m 0666 /dev/ost/dvr1 c 250 69 +mknod -m 0666 /dev/ost/ca1 c 250 70 + +cd /dev/ost +ln -sf ca0 ca +ln -sf video0 video +ln -sf sec0 sec +ln -sf audio0 audio +ln -sf qpskfe0 qpskfe +ln -sf demux0 demux +ln -sf dvr0 dvr diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/Makefile linux.20pre2-ac1/drivers/media/video/margi/Makefile --- linux.20pre2/drivers/media/video/margi/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/Makefile 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,33 @@ +# +# Makefile for the Margi DVD-to-Go driver +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := margilib.o + +CFLAGS_margi_cs.o = -DUSE_OSD -DNOINT -DDVB -DUSE_ZV + +obj-y := +obj-m := +obj-n := +obj- := + +list-multi := margi_cs.o + +margi_cs-objs := margi.o cardbase.o i2c.o dram.o osd.o audio.o \ + video.o streams.o decoder.o spu.o crc.o ringbuffy.o \ + dvb_filter.o cvdv.o + +export-objs := dvbdev.o + +obj-m += margi_cs.o dvbdev.o dmxdev.o dvb_demux.o + +include $(TOPDIR)/Rules.make + +margi_cs.o: $(margi_cs-objs) + $(LD) $(LD_RFLAG) -r -o $@ $(margi_cs-objs) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/margi linux.20pre2-ac1/drivers/media/video/margi/margi --- linux.20pre2/drivers/media/video/margi/margi 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/margi 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,5 @@ +#!/bin/sh +# +# + +exit 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/margi.c linux.20pre2-ac1/drivers/media/video/margi/margi.c --- linux.20pre2/drivers/media/video/margi/margi.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/margi.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,1493 @@ +/* + margi.c + + Copyright (C) Marcus Metzler for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "margi.h" + +#include +#include +#include +#include +#include +#include +#include + + + +#include "l64014.h" +#include "l64021.h" +#include "i2c.h" +#include "decoder.h" +#include "dram.h" +#include "video.h" +#include "cvdv.h" + + +static char *version = "margi_cs.c 0.6 02/04/2000 (Marcus Metzler)"; + +//#define USE_BH 1 +#ifdef USE_BH +#define MARGI_BH 31 +// shouldn't be a number, but then MARGI_BH must be entered into interrupt.h +#endif + +MODULE_AUTHOR(AUTHOR); +MODULE_DESCRIPTION(MEDDEVNAME " Driver V." DVERSION); +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#define MAX_DEV 4 +#define DEVICE_NR(minor) ((minor)>>4) + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ +static int svhs = 1; +MODULE_PARM(svhs,"i"); +static int composite = 1; +MODULE_PARM(composite,"i"); +static int use_zv = 1; +MODULE_PARM(use_zv,"i"); + +/* Release IO ports after configuration? */ +static int free_ports = 0; + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_int irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; + +MODULE_PARM(free_ports, "i"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +extern unsigned int major_device_number; +extern struct file_operations cvdv_fileops; + +typedef struct margi_info_t { + dev_link_t link; + dev_node_t node; + struct cvdv_cards card; + int stop; +} margi_info_t; + + + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card + insertion and ejection events. They are invoked from the margi + event handler. +*/ + +static void margi_config(dev_link_t * link); +static void margi_release(u_long arg); +static int margi_event(event_t event, int priority, + event_callback_args_t * args); +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *margi_attach(void); +static void margi_detach(dev_link_t *); +static u_char read_lsi_status(struct cvdv_cards *card); + +/* + You'll also need to prototype all the functions that will actually + be used to talk to your device. See 'memory_cs' for a good example + of a fully self-sufficient driver; the other drivers rely more or + less on other parts of the kernel. +*/ + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_link_t *dev_table[MAX_DEV] = { NULL, /* ... */ }; + +static dev_info_t dev_info = "margi_cs"; + +/* + A linked list of "instances" of the margi device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + To simplify the data structure handling, we actually include the + dev_link_t structure in the device's private data structure. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally shouldn't be allocated dynamically. + + In this case, we also provide a flag to indicate if a device is + "stopped" due to a power management event, or card ejection. The + device IO routines can use a flag like this to throttle IO to a + card that is not ready to accept it. + + The bus_operations pointer is used on platforms for which we need + to use special socket-specific versions of normal IO primitives + (inb, outb, readb, writeb, etc) for card IO. +*/ + +void DACSetFrequency(struct cvdv_cards *card, int khz, int multiple) { + uint8_t b = read_indexed_register(card, IIO_OSC_AUD); + + b &= 0xf8; + + switch (khz){ + case 32: + b |= 0x04; + break; + case 48: + b |= 0x00; + break; + case 44: + b |= 0x01; + break; + case 96: + b |= 0x02; + break; + default: + b |= 0x00; + break; + } + write_indexed_register(card, IIO_OSC_AUD, b); + +} + +int MargiFreeBuffers(struct cvdv_cards *card) +{ + MDEBUG(1, ": -- MargiFreeBuffers\n"); + + ring_destroy(&(card->rbufB)); + card->use_ringB = 0; + ring_destroy(&(card->rbufA)); + card->use_ringA = 0; + + return 0; +} + + +int MargiSetBuffers(struct cvdv_cards *card, uint32_t size, int isB) +{ + int err = 0; + + MDEBUG(0, ": -- MargiSetBuffers(%d) %d\n", + size, isB); + + if (isB){ + err = ring_init(&(card->rbufB),size); + if (!err) card->use_ringB = 1; + } else { + err = ring_init(&(card->rbufA),size); + if (!err) card->use_ringA = 1; + } + + MDEBUG(0,"set buffers: %d use_ringA: %d use_ringB: %d\n",err, +card->use_ringA,card->use_ringB); + return err; +} + + +int MargiFlush (struct cvdv_cards *card) +{ + int co = 0; + int i; + for (i=0;i<100;i++){ + MargiPushA(card, 32, FlushPacket); + MargiPushB(card, 32, FlushPacket); + } + while ( (ring_write_rest(&(card->rbufA))|| ring_write_rest(&(card->rbufB))) && co<100) + co++; + VideoSetBackground(card, 1, 0, 0, 0); // black + + if (card->use_ringA) ring_flush(&(card->rbufA)); + if (card->use_ringB) ring_flush(&(card->rbufB)); + card->DMAABusy = 0; + card->DMABBusy = 0; + + + DecoderStopChannel(card); + DecoderStreamReset(card); + DecoderSetupReset(card); + card->channelrun = 0; + + MDEBUG(1, ": Margi Flush \n"); + return 0; +} + + +int MargiPushA(struct cvdv_cards *card, int count, const char *data) +{ + int fill; + + fill = ring_read_rest(&(card->rbufA)); + + if (!card->use_ringA) + return 0; + if ((count>fill || fill > 3*card->rbufA.size/4) + && !card->channelrun){ + DecoderStartChannel(card); + card->DMAABusy = 1; + } + + count = ring_write(&(card->rbufA),data,count); + + return count; +} + +int MargiPushB(struct cvdv_cards *card, int count, const char *data) +{ + int fill; + + fill = ring_read_rest(&(card->rbufB)); + + if (!card->use_ringB) + return 0; + if ((count>fill || fill > 3*card->rbufB.size/4) + && !card->channelrun){ + DecoderStartChannel(card); + card->DMABBusy = 1; + } + + count = ring_write(&(card->rbufB),data,count); + + return count; +} + +int DecoderStartChannel(struct cvdv_cards *card) +{ + DecoderMaskByte(card, 0x007, 0xC3, 0xC3); // channel start + +#ifdef BYPASS + DecoderMaskByte(card,0x005,0x0F,0x08); +#else + DecoderMaskByte(card,0x005,0x0F,0x01); +#endif + card->channelrun = 1; + return 0; +} + +int DecoderStopChannel(struct cvdv_cards *card) +{ + DecoderMaskByte(card, 0x007, 0xC3, 0xC2); // channel reset + DecoderSetByte(card, 0x005, 0x04); // channel pause + card->channelrun = 0; + return 0; +} + +uint32_t DecoderGetAudioBufferSpace(struct cvdv_cards *card) +{ + + uint32_t MaxSize, Size; + + MaxSize = card->AudioESSize; + Size = DecoderGetAudioESLevel(card); + + if (Size>MaxSize) + return 0; + return (MaxSize - Size); + +} + +uint32_t DecoderGetVideoBufferSpace(struct cvdv_cards *card) +{ + + uint32_t MaxSize, Size; + + MaxSize = card->VideoESSize; + Size = DecoderGetVideoESLevel(card); + + if (Size>MaxSize) + return 0; + return (MaxSize - Size); + +} + +uint32_t DecoderGetBufferSpace(struct cvdv_cards *card) +{ + uint32_t audio,video; + + audio = DecoderGetAudioBufferSpace(card); + video = DecoderGetVideoBufferSpace(card); + + if (audio > 2048) audio -= 2048; + if (video > 2048) video -= 2048; + + if (audio < video) return audio; + return video; +} + + + +static int ringDMA (struct cvdv_cards *card){ + + uint32_t size = 0; + u_char stat; + dev_link_t *link = &(((margi_info_t *) card->margi)->link); + uint32_t acount=0; + uint32_t vcount=0; + uint8_t data; + ringbuffy *buffy; + int stype; + wait_queue_head_t *wq; + stat = read_lsi_status(card); + + + stype = card->setup.streamtype; + + if (stat & LSI_ARQ) { + stat = read_lsi_status(card); + } + + if (stat & LSI_READY){ + data = read_indexed_register(card, IIO_LSI_CONTROL); + data |= RR; + write_indexed_register(card, IIO_LSI_CONTROL, data); + return 0; + } + + if ((stat & LSI_ARQ) == 0) { + switch(stype){ + case stream_PES: + case stream_ES: + data = read_indexed_register(card, IIO_LSI_CONTROL); + data &= ~DSVC; + write_indexed_register(card, IIO_LSI_CONTROL, data); + buffy = &card->rbufB; + wq = &(card->wqB); + acount = ring_read_rest(buffy); + size = DecoderGetAudioBufferSpace(card); + if (size > 2048) size -= 2048; + break; + default: + buffy = &card->rbufA; + wq = &(card->wqA); + acount = ring_read_rest(buffy); + size = DecoderGetBufferSpace(card); + break; + } + if (acount > size) acount = size & 0xfffffffc; + if (acount>=2048) acount &=0xfffff800; + acount &=0xfffffffc; + + if (acount > size) acount = size & 0xfffffffc; + if (acount) { + ring_read_direct(buffy, + link->io.BasePort1+DIO_LSI_STATUS, + acount); + } else { + wake_up_interruptible(wq); + acount = 0; + } + } else { + acount = 0; + } + + if ((stat & LSI_VRQ) == 0 && + (stype == stream_PES || stype == stream_ES)) { + data = read_indexed_register(card, IIO_LSI_CONTROL); + data |= DSVC; + write_indexed_register(card, IIO_LSI_CONTROL, data); + buffy = &card->rbufA; + wq = &(card->wqA); + vcount = ring_read_rest(buffy); + + size = DecoderGetVideoBufferSpace(card); + if (size > 2048) size -= 2048; + if (vcount > size) vcount = size & 0xfffffffc; + if (vcount>=2048) vcount &=0xfffff800; + vcount &=0xfffffffc; + + if (vcount > size) vcount = size & 0xfffffffc; + if (vcount) { + ring_read_direct(buffy, + link->io.BasePort1+DIO_LSI_STATUS, + vcount); + } else { + wake_up_interruptible(wq); + vcount = 0; + } + } else { + vcount = 0; + } + + return vcount+acount; +} + + +u_char read_indexed_register(struct cvdv_cards * card, int addr) +{ + dev_link_t *link = &(((margi_info_t *) card->margi)->link); + u_char data; +#ifdef NOINT + spin_lock(&card->timelock); +#endif + outb(addr, link->io.BasePort1 + DIO_CONTROL_INDEX); + data = (inb(link->io.BasePort1 + DIO_CONTROL_DATA)); +#ifdef NOINT + spin_unlock(&card->timelock); +#endif + return data; +} + + +void write_indexed_register(struct cvdv_cards *card, int addr, u_char data) +{ + dev_link_t *link = &(((margi_info_t *) card->margi)->link); +#ifdef NOINT + spin_lock(&card->timelock); +#endif + outb(addr, link->io.BasePort1 + DIO_CONTROL_INDEX); + outb(data, link->io.BasePort1 + DIO_CONTROL_DATA); + +#ifdef NOINT + spin_unlock(&card->timelock); +#endif +} + +void WriteByte(struct cvdv_cards *card, int addr, u_char data) +{ + dev_link_t *link = &(((margi_info_t *) card->margi)->link); + +#ifdef NOINT + spin_lock(&card->timelock); +#endif + outb((u_char) (addr & 255), + link->io.BasePort1 + DIO_LSI_INDEX_LOW); + outb(((addr & 256) ? 1 : 0), + link->io.BasePort1 + DIO_LSI_INDEX_HIGH); + outb(data, link->io.BasePort1 + DIO_LSI_DATA); +#ifdef NOINT + spin_unlock(&card->timelock); +#endif +} + +u_char ReadByte(struct cvdv_cards *card, int addr) +{ + dev_link_t *link = &(((margi_info_t *) card->margi)->link); + u_char data; + +#ifdef NOINT + spin_lock(&card->timelock); +#endif + outb((u_char) (addr & 255), + link->io.BasePort1 + DIO_LSI_INDEX_LOW); + outb(((addr & 256) ? 1 : 0), + link->io.BasePort1 + DIO_LSI_INDEX_HIGH); + data = inb(link->io.BasePort1 + DIO_LSI_DATA); +#ifdef NOINT + spin_unlock(&card->timelock); +#endif + return data; +} + +void MaskByte(struct cvdv_cards *card, int addr, u_char mask, u_char bits) +{ + WriteByte(card, addr, (ReadByte(card, addr) & ~(mask)) | (bits)); +} + + + +#define MAXWRITE CHANNELBUFFERSIZE/2 +#define MAX_COUNT 400 + +#ifdef USE_BH +struct cvdv_cards *bh_card; + +static void do_margi_bh(void) +{ + struct cvdv_cards *card = bh_card; +#else + +static void do_margi(struct cvdv_cards *card) +{ + +#endif + int countA; + int try; + int stype = card->setup.streamtype; + + countA = 0; + + card->currentType = 0; + for ( try = 0; try < MAX_COUNT ;try++) + if (countA < MAXWRITE){ + int count = 0; + switch (stype){ + case stream_PES: + case stream_ES: + count = ringDMA(card); + countA += count; + if (!count) + try=MAX_COUNT; + break; + case stream_PS: + case stream_DVD: + count = ringDMA(card); + countA += count; + if (!count) + try=MAX_COUNT; + break; + } + } else break; + +} + + + + +void L64014Intr_function(struct cvdv_cards *card) +{ + uint8_t control,mask,stat; + int try; + + + control= read_indexed_register(card, IIO_IRQ_CONTROL); + if (control & IRQ_EN){ + mask = 0; + if ( control & DEC_EN ) mask |= DEC_INT; + if ( control & VSYNC_EN ) mask |= VSYNC_INT; + stat = read_indexed_register(card, IIO_IRQ_STATUS); + try = 0; + while ( (try++ < 100) && (stat & mask) ){ + + if (stat & VSYNC_INT) { + + write_indexed_register(card,IIO_IRQ_CONTROL, + control & (~VSYNC_EN)); + write_indexed_register(card,IIO_IRQ_CONTROL, + control); + + + if (card->DMAABusy || card->DMABBusy){ + +#ifdef USE_BH + bh_card = card; + mark_bh(MARGI_BH); +#else + do_margi(card); +#endif + if(card->use_ringA || card->use_ringB){ + L64021Intr(card); + } + } + } + + if (stat & DEC_INT) { + write_indexed_register(card,IIO_IRQ_CONTROL, + control & (~DEC_EN)); + write_indexed_register(card,IIO_IRQ_CONTROL, + control); + + if(card->use_ringA || card->use_ringB){ + L64021Intr(card); + } + } + + stat = read_indexed_register(card, IIO_IRQ_STATUS); + } + } + +} + + +#ifdef NOINT +void Timerfunction(unsigned long data) +{ + struct cvdv_cards *card = (struct cvdv_cards *) data; + + L64014Intr_function(card); + + card->timer.function = Timerfunction; + card->timer.data=(unsigned long) card; + card->timer.expires=jiffies+10; + if ( card->open) + add_timer(&card->timer); + +} +#endif + + +void L64014Intr(int irq, void *dev_id, struct pt_regs *regs) +{ + margi_info_t *margi = dev_id; + struct cvdv_cards *card = &(margi->card); + u_char dio_index, lsi_index_low, lsi_index_high; + +#ifdef NOINT + spin_lock(&card->timelock); +#endif + //save registers + dio_index = inb(margi->link.io.BasePort1 + DIO_CONTROL_INDEX); + lsi_index_low = inb(margi->link.io.BasePort1 + DIO_LSI_INDEX_LOW); + lsi_index_high = inb(margi->link.io.BasePort1 + DIO_LSI_INDEX_HIGH); + + + L64014Intr_function(card); + + //load registers + outb(dio_index, margi->link.io.BasePort1 + DIO_CONTROL_INDEX); + outb(lsi_index_low, margi->link.io.BasePort1 + DIO_LSI_INDEX_LOW); + outb(lsi_index_high,margi->link.io.BasePort1 + DIO_LSI_INDEX_HIGH); +#ifdef NOINT + spin_unlock(&card->timelock); +#endif +} + +int L64014RemoveIntr(struct cvdv_cards *card) +{ + MDEBUG(1, ": -- L64014RemoveIntr\n"); + // Disable the IRQ's + write_indexed_register(card, IIO_IRQ_CONTROL, 0x00); + if (!card->IntInstalled) + return 1; + L64021RemoveIntr(card); + return 0; +} + +void l64020Reset(struct cvdv_cards *card){ + uint8_t data; + + + data = read_indexed_register(card, IIO_LSI_CONTROL); + data &= ~(RR | DR); + write_indexed_register(card, IIO_LSI_CONTROL, data); + mdelay(100); + data = read_indexed_register(card, IIO_LSI_CONTROL); + data |= DR; + write_indexed_register(card, IIO_LSI_CONTROL, data); + + data = read_indexed_register(card,IIO_GPIO_PINS); + data &= ~0x01; + write_indexed_register(card,IIO_GPIO_PINS,data); + data |= 0x01; + write_indexed_register(card,IIO_GPIO_PINS,data); + + //write_indexed_register(card, IIO_LSI_CONTROL, DR); + + data = read_indexed_register(card, IIO_LSI_CONTROL); + data &= ~DSVC; + write_indexed_register(card, IIO_LSI_CONTROL, data); + +} + +void ZV_init(struct cvdv_cards *card) +{ + uint32_t delay, activel; + uint8_t reg; + delay = 235; + activel = delay + 1448; + + // init delay and active lines + write_indexed_register(card, IIO_VIDEO_HOR_DELAY, + (uint8_t)(delay & 0x00FF)); + write_indexed_register(card, IIO_VIDEO_HOR_ACTIVE, + (uint8_t)(activel & 0x00FF)); + reg = ((uint8_t)((activel >> 4) & 0x0070))|((uint8_t)((delay >> 8) & 0x0007)); + write_indexed_register(card, IIO_VIDEO_HOR_HIGH, reg); + + //init video + reg = read_indexed_register(card, IIO_VIDEO_CONTROL0); + reg |= (ZVCLK13 | ZV16BIT | ZVCLKINV); + write_indexed_register(card, IIO_VIDEO_CONTROL0, reg); + reg = read_indexed_register(card, IIO_VIDEO_CONTROL1); + reg |= (ZV_OVERRIDE | ZV_ENABLE); + write_indexed_register(card, IIO_VIDEO_CONTROL1, reg); +} + +void set_svhs(struct cvdv_cards *card, int onoff) +{ + uint8_t val; + + val = I2CRead(card, card->i2c_addr, CS_DAC)&0x0f; + MDEBUG(1, ": --svhs val 0x%02x\n",val); + + if (onoff){ + if (!card->svhs){ + I2CWrite(card, card->i2c_addr, CS_DAC, val|0x03); + card->svhs = 1; + } + } else { + if (!card->svhs){ + I2CWrite(card, card->i2c_addr, CS_DAC, val|0x30); + card->svhs = 1; + } + } + +} + +void set_composite(struct cvdv_cards *card, int onoff) +{ + uint8_t val; + + val = I2CRead(card, card->i2c_addr, CS_DAC)&0x0f; + MDEBUG(1, ": --composite val 0x%02x\n",val); + + + if (onoff){ + if (!card->composite){ + I2CWrite(card, card->i2c_addr, CS_DAC, val|0x84); + card->composite = 1; + } + } else { + if (!card->svhs){ + I2CWrite(card, card->i2c_addr, CS_DAC, val|0xE0); + card->composite = 1; + } + } + +} + + +int L64014Init(struct cvdv_cards *card) +{ + uint16_t testram[16]; + int i, err; + + MDEBUG(1, ": -- L64014Init\n"); + card->videomode = VIDEO_MODE; + + /* Reset 64020 */ + write_indexed_register(card, IIO_GPIO_CONTROL, 0x01); + l64020Reset(card); + /* init GPIO */ + write_indexed_register(card, IIO_GPIO_CONTROL, 0x01); + write_indexed_register(card, IIO_GPIO_PINS, 0xff); + + /* Set to PAL */ + write_indexed_register(card, IIO_VIDEO_CONTROL0, 0); + write_indexed_register(card, IIO_VIDEO_CONTROL1, VMS_PAL); + + /* Set Audio freq */ + write_indexed_register(card, IIO_OSC_AUD, 0x12); + + write_indexed_register(card, CSS_COMMAND, 0x01); + + + MDEBUG(0, "CSID: %02x\n", I2CRead(card, 0, 0x3d)); + card->i2c_addr = I2CRead(card, 0, 0x0f); + MDEBUG(0, "I2CADDR: %02x\n", card->i2c_addr); + + I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x4a); + I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04); + I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x96); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x15); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0x13); + I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x54); + +// I2CWrite(card, card->i2c_addr, CS_DAC, 0x87); + if (svhs) set_svhs(card, 1); + if (composite) set_composite(card, 1); + I2CWrite(card, card->i2c_addr, CS_BKG_COL, 0x03); + + MDEBUG(0,"Decoder Status: %d\n", read_lsi_status(card)); + MDEBUG(0,"lsi stat %d\n", DecoderReadByte(card, 0x005)); + + if (use_zv) ZV_init(card); + L64021Init(card); + + // Find out how much DRAM we have + card->DRAMSize = 0x00100000; // maximum size + do { + MDEBUG(0, + ": Probing DRAM Size: 0x%08X (%d kByte) ... ", + card->DRAMSize, card->DRAMSize / 512); + for (i = 0; i < 8; i++) + testram[i] = rnd(0x100) | (rnd(0x100) << 8); + if (DRAMWriteWord(card, 0, 4, &testram[0], 0)) + MDEBUG(0, ": DRAM Write error.\n"); + if (DRAMWriteWord + (card, card->DRAMSize - 4, 4, &testram[4], + 0)) MDEBUG(0, + ": DRAM Write error.\n"); + if (DRAMReadWord(card, 0, 4, &testram[8], 0)) + MDEBUG(0, ": DRAM Read error.\n"); + if (DRAMReadWord + (card, card->DRAMSize - 4, 4, &testram[12], + 0)) MDEBUG(0, ": DRAM Read error.\n"); + err = 0; + for (i = 0; (!err) && (i < 8); i++) + if (testram[i] != testram[i + 8]) + err = i + 1; + if (err) { + MDEBUG(0," failed\n"); + } else { + MDEBUG(0," ok\n"); + } + if (err) + MDEBUG(2,": DRAM compare error at cell %d: 0x%04X %04X %04X %04X->0x%04X %04X %04X %04X / 0x%04X %04X %04X %04X->0x%04X %04X %04X %04X\n", + err, testram[0], testram[1], testram[2], + testram[3], testram[8], testram[9], + testram[10], testram[11], testram[4], + testram[5], testram[6], testram[7], + testram[12], testram[13], testram[14], + testram[15]); + if (err) + card->DRAMSize >>= 1; + } while (err && (card->DRAMSize >= 0x00100000)); + printk(KERN_INFO LOGNAME ": DRAM Size: 0x%08X (%d kByte)\n", + card->DRAMSize, card->DRAMSize / 512); + if (card->DRAMSize < 0x00100000) { // minimum size + printk(KERN_INFO LOGNAME + ": DRAM ERROR: Not enough memory on card!\n"); + return 1; + } + return 0; +} + + +void CardDeInit(struct cvdv_cards *card) +{ + CloseCard(card); + MargiFlush(card); + MargiFreeBuffers(card); + + L64014RemoveIntr(card); + card_init(card, 0); +} + + +static u_char read_lsi_status(struct cvdv_cards *card) +{ + margi_info_t *margi = (margi_info_t *) card->margi; + return (inb(margi->link.io.BasePort1 + DIO_LSI_STATUS) & 15); + +} + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + margi_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *margi_attach(void) +{ + margi_info_t *local; + dev_link_t *link; + client_reg_t client_reg; + int ret, i; + + MDEBUG(0, "margi_attach()\n"); + + for (i = 0; i < MAX_DEV; i++) + if (dev_table[i] == NULL) + break; + if (i == MAX_DEV) { + printk(KERN_NOTICE "margi_cs: no devices available\n"); + return NULL; + } + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(margi_info_t), GFP_KERNEL); + if (!local) + return NULL; + memset(local, 0, sizeof(margi_info_t)); + link = &local->link; + link->priv = local; + local->card.margi = (void *) local; + dev_table[i] = link; + + /* Initialize the dev_link_t structure */ + link->release.function = &margi_release; + link->release.data = (u_long) link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->conf.Attributes = 0; + link->conf.Vcc = 50; + + if(use_zv==0) + link->conf.IntType = INT_MEMORY_AND_IO; + else + link->conf.IntType = INT_ZOOMED_VIDEO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &margi_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + margi_detach(link); + return NULL; + } + + return link; +} /* margi_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void margi_detach(dev_link_t * link) +{ + dev_link_t **linkp; + + int nd; + + MDEBUG(0, "margi_detach(0x%p)\n", link); + + for (nd = 0; nd < MAX_DEV; nd++) + if (dev_table[nd] == link) + break; + if (nd == MAX_DEV) + return; + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + return; + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { + MDEBUG(2, "margi_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, and free it */ + *linkp = link->next; + /* This points to the parent struct cvdv_cards struct */ + dev_table[nd] = NULL; + + kfree(link->priv); + +} /* margi_detach */ + +/*====================================================================== + + margi_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + +======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void margi_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + margi_info_t *dev = link->priv; + struct cvdv_cards *card = &(dev->card); + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret, i; + u_char buf[64]; + config_info_t conf; + win_req_t req; + memreq_t map; + int minor = 0; + + MDEBUG(0, "margi_config(0x%p)\n", link); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + dflt = *cfg; + if (cfg->index == 0) + goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + cfg->vcc.param[CISTPL_POWER_VNOM] / + 10000) goto next_entry; + } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + dflt.vcc.param[CISTPL_POWER_VNOM] / + 10000) goto next_entry; + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ +#ifndef NOINT + link->irq.Attributes = + IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Handler = &L64014Intr; + link->irq.Instance = link; + link->conf.Attributes |= CONF_ENABLE_IRQ; +#ifdef USE_BH + init_bh(MARGI_BH, do_margi_bh); +#endif + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, link->handle, &link->irq); +#endif + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = + (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = + IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = + io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = + link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + + /* + Now set up a common memory window, if needed. There is room + in the dev_link_t structure for one memory window handle, + but if the base addresses need to be saved, or if multiple + windows are needed, the info should go in the private data + structure for this device. + + Note that the memory window base is a physical address, and + needs to be mapped to virtual space with ioremap() before it + is used. + */ + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; + req.Attributes = + WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM; + req.Attributes |= WIN_ENABLE; + req.Base = mem->win[0].host_addr; + req.Size = mem->win[0].len; + req.AccessSpeed = 0; + link->win = (window_handle_t) link->handle; + CFG_CHECK(RequestWindow, &link->win, &req); + map.Page = 0; + map.CardOffset = mem->win[0].card_addr; + CFG_CHECK(MapMemPage, link->win, &map); + } + /* If we got this far, we're cool! */ + break; + + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + /* + We can release the IO port allocations here, if some other + driver for the card is going to loaded, and will expect the + ports to be available. + */ + if (free_ports) { + if (link->io.BasePort1) + release_region(link->io.BasePort1, + link->io.NumPorts1); + if (link->io.BasePort2) + release_region(link->io.BasePort2, + link->io.NumPorts2); + } + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + + first_card = card; + minor=0; + card->next = NULL; + card_init(card, minor); + if ((i = register_chrdev(CVDV_MAJOR, CVDV_PROCNAME, &cvdv_fileops)) + >= 0) { + major_device_number = ((i) ? i : CVDV_MAJOR); + printk(KERN_INFO LOGNAME + ": Char-device with major number %d installed\n", + major_device_number); + } else { + printk(KERN_ERR LOGNAME + ": ERROR: Failed to install Char-device %d, error %d\n", + CVDV_MAJOR, i); + } + + + sprintf(dev->node.dev_name, "margi"); + dev->node.major = major_device_number; + dev->node.minor = minor; + link->dev = &dev->node; +#ifdef DVB + dvb_register(card); +#endif + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + dev->node.dev_name, link->conf.ConfigIndex, + link->conf.Vcc / 10, link->conf.Vcc % 10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1 / 10, + link->conf.Vpp1 % 10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1 + link->io.NumPorts1 - 1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2 + link->io.NumPorts2 - 1); + if (link->win) + printk(", mem 0x%06lx-0x%06lx", req.Base, + req.Base + req.Size - 1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + if (0xdd == read_indexed_register(card, IIO_ID)) { + printk("L64014 Version %d in mode %d detected\n", + (read_indexed_register(card, IIO_MODE) & 248) >> 3, + read_indexed_register(card, IIO_MODE) & 7); + write_indexed_register(card, IIO_GPIO_CONTROL, 0x07); + + L64014Init(card); + + // default: color bars + VideoSetBackground(card, 1, 0, 0, 0); // black + SetVideoSystem(card); + minorlist[minor] = card; // fast access for the char driver + + + /*enable L64014 IRQ */ + write_indexed_register(card, IIO_IRQ_CONTROL, + IRQ_POL | IRQ_EN | VSYNC_EN); +// write_indexed_register(card, IIO_IRQ_CONTROL, 0x24); + + OSDOpen(card, 50, 50, 150, 150, 2, 1); + OSDTest(card); + } + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + margi_release((u_long) link); + +} /* margi_config */ + +/*====================================================================== + + After a card is removed, margi_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void margi_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + margi_info_t *dev = link->priv; + struct cvdv_cards *card = &(dev->card); + + MDEBUG(0, "margi_release(0x%p)\n", link); + /* + If the device is currently in use, we won't release until it + is actually closed, because until then, we can't be sure that + no one will try to access the device or its data structures. + */ + if (link->open) { + MDEBUG(1, "margi_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ + link->dev = NULL; + + /* + In a normal driver, additional code may be needed to release + other kernel data structures associated with this device. + */ + + MDEBUG(1,": Unloading device driver\n"); + if (major_device_number) + unregister_chrdev(major_device_number, CVDV_PROCNAME); + CardDeInit(card); + +#ifndef NOINT +#ifdef USE_BH + remove_bh(MARGI_BH); +#endif + mdelay(100); +#endif + CloseCard(card); +#ifdef DVB + dvb_unregister(card); +#endif + /* Don't bother checking to see if these succeed or not */ + if (link->win) + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); +#ifndef NOINT + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); +#endif + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + margi_detach(link); + +} /* margi_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private flag to block future accesses to this device. All the + functions that actually access the device should check this flag + to make sure the card is still present. + +======================================================================*/ + +static int margi_event(event_t event, int priority, + event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + margi_info_t *dev = link->priv; + + MDEBUG(1, "margi_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((margi_info_t *) link->priv)->stop = 1; + link->release.expires = jiffies + HZ / 20; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dev->card.bus = args->bus; + margi_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + dev->stop = 1; + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + CardServices(RequestConfiguration, link->handle, + &link->conf); + dev->stop = 0; + /* + In a normal driver, additional code may go here to restore + the device state and restart IO. + */ + break; + } + return 0; +} /* margi_event */ + +/*====================================================================*/ + +static int __init init_margi_cs(void) +{ + servinfo_t serv; + MDEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "margi_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &margi_attach, &margi_detach); + return 0; +} + +static void __exit exit_margi_cs(void) +{ + MDEBUG(0, "margi_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + margi_release((u_long) dev_list); + margi_detach(dev_list); + } +} + +module_init(init_margi_cs); +module_exit(exit_margi_cs); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/margi.conf linux.20pre2-ac1/drivers/media/video/margi/margi.conf --- linux.20pre2/drivers/media/video/margi/margi.conf 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/margi.conf 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,9 @@ +device "margi_cs" + class "margi" module "margi_cs" + +# Margi +card "MARGI-Billionton" +manfid 0x01d8, 0x1000 +bind "margi_cs" + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/margi_cs.4 linux.20pre2-ac1/drivers/media/video/margi/margi_cs.4 --- linux.20pre2/drivers/media/video/margi/margi_cs.4 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/margi_cs.4 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,34 @@ +.\" Copyright (c) 1997,1998,1999 Koji OKAMURA +.\" +.TH ISCC_CS 4 "1997/09/28" "" +.SH NAME +iscc_cs \- IBM Smart Capture Card device driver +.SH SYNOPSIS +.B insmod iscc_cs.o +.RB [ pc_debug=n ] +.RB [ mem_speed=n ] +.SH DESCRIPTION +.B Iscc_cs +is the low-level Card Services driver for the IBM Smart Capture Card +PCMCIA Video Capture adapter. When this driver is attached to a card, it +allocates the next available Video Capture Card device +.RB ( iscc0 .. iscc# ). +This +device name will be reported in the kernel log file, and passed on to +.BR cardmgr (8). +.SH PARAMETERS +.TP +.B pc_debug=n +Selects the PCMCIA debugging level. This parameter is only available +if the module is compiled with debugging enabled. A non-zero value +enables debugging. +.TP +.B mem_speed=n +Sets the access speed of the shared memory window, in nanoseconds. +The default is 0 (i.e., no extra wait states). Values of up to 1000 +are legal. +.SH AUTHOR +Koji OKAMURA \- Kyushu University + +.SH "SEE ALSO" +cardmgr(8), pcmcia(5). diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/margi_cs.mk linux.20pre2-ac1/drivers/media/video/margi/margi_cs.mk --- linux.20pre2/drivers/media/video/margi/margi_cs.mk 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/margi_cs.mk 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,113 @@ +# +# Makefile for margi_cs +# Marcus Metzler +# + +include ../config.mk + +CC = $(KCC) $(AFLAGS) $(KFLAGS) + +CFLAGS += -g -O2 -Wall -Wstrict-prototypes -pipe -Wall -D__DVB_PACK__ -DUSE_OSD -DNOINT -DDVB -DUSE_ZV + +CPPFLAGS += $(PCDEBUG) -D__KERNEL__ -DMODULE -DMODVERSIONS -I../include \ + -I$(LINUX)/include -I$(LINUX) -Iinclude + +CC_MODULE = $(CC) -c $(CFLAGS) $(CPPFLAGS) + +ETC = $(PREFIX)/etc/pcmcia +MANDIR = $(PREFIX)/usr/man +MX_OBJS = dmxdev.o dvb_demux.o dvbdev.o + +all: margi_cs.o $(MX_OBJS) + +install-modules: $(MODULES) $(MX_OBJS) + mkdir -p $(PREFIX)/$(MODDIR)/pcmcia + cp $(MODULES) $(PREFIX)/$(MODDIR)/pcmcia + su -c "mkdir -p $(MODDIR)/misc; cp -v $(MX_OBJS) $(MX_OBJS) $(MODDIR)/misc" + +install-clients: + for f in $(CLIENTS) ; do \ + [ -r $$f.conf ] && cp $$f.conf $(ETC)/$$f.conf ; \ + cmp -s $$f $(ETC)/$$f && continue ; \ + [ -r $(ETC)/$$f ] && mv $(ETC)/$$f $(ETC)/$$f.O ; \ + cp $$f $(ETC)/$$f ; \ + OPTS=$(ETC)/$$f.opts ; \ + test -r $$OPTS || cp $$f.opts $$OPTS ; \ + done + cp cvdvext.h cvdvtypes.h /usr/include/linux + mkdir -p /usr/include/ost/ + cp include/ost/*.h /usr/include/ost + rm -rf /dev/ost + makedev.napi + depmod -a + +install-man4: $(MAN4) + mkdir -p $(MANDIR)/man4 + cp $(MAN4) $(MANDIR)/man4 + + +MMODULES = margi.o cvdv.o cardbase.o i2c.o dram.o osd.o audio.o video.o streams.o decoder.o spu.o crc.o ringbuffy.o dvb_formats.o + +margi_cs.o: $(MMODULES) + $(LD) -r -o margi_cs.o $(MMODULES) + chmod -x margi_cs.o + + +margi.o: margi.h cardbase.h l64014.h l64021.h i2c.h decoder.h dram.h\ + video.h cvdv.h margi.c + $(CC_MODULE) margi.c + +cvdv.o: cvdv.c cvdv.h cardbase.h cvdvtypes.h l64021.h l64014.h dram.h\ + osd.h audio.h video.h streams.h decoder.h spu.h \ + crc.h + $(CC_MODULE) cvdv.c + +cardbase.o: cardbase.c cardbase.h cvdvtypes.h + $(CC_MODULE) cardbase.c + +i2c.o: i2c.c i2c.h cardbase.h cvdvtypes.h l64014.h + $(CC_MODULE) i2c.c + +dram.o: dram.c dram.h cardbase.h cvdvtypes.h l64021.h l64014.h + $(CC_MODULE) dram.c + +osd.o: osd.c osd.h cardbase.h cvdvtypes.h dram.h l64021.h l64014.h + $(CC_MODULE) osd.c + +audio.o: audio.c audio.h cardbase.h cvdvtypes.h l64021.h l64014.h + $(CC_MODULE) audio.c + +video.o: video.c video.h cardbase.h cvdvtypes.h dram.h l64021.h l64014.h + $(CC_MODULE) video.c + +streams.o: streams.c streams.h cardbase.h cvdvtypes.h dram.h l64021.h l64014.h \ +video.h dram.h audio.h + $(CC_MODULE) streams.c + +decoder.o: decoder.c decoder.h cardbase.h cvdvtypes.h dram.h l64021.h l64014.h \ +video.h dram.h audio.h streams.h i2c.h osd.h dram.h + $(CC_MODULE) decoder.c + +spu.o: spu.c spu.h cardbase.h cvdvtypes.h l64021.h l64014.h + $(CC_MODULE) spu.c + +crc.o: crc.c crc.h + $(CC_MODULE) crc.c + +ringbuffy.o: ringbuffy.h ringbuffy.c + $(CC_MODULE) ringbuffy.c + +dvb_formats.o: dvb_formats.h dvb_formats.c + $(CC_MODULE) dvb_formats.c + +dmxdev.o: dmxdev.h dvb_demux.h + $(CC_MODULE) -include $(LINUX)/include/linux/modversions.h dmxdev.c + +dvb_demux.o: dvb_demux.h dmxdev.h dvbdev.h + $(CC_MODULE) -include $(LINUX)/include/linux/modversions.h dvb_demux.c + +dvbdev.o: dvbdev.h + $(CC_MODULE) -include $(LINUX)/include/linux/modversions.h -DEXPORT_SYMTAB -c dvbdev.c + +clean: + rm -f core core.* *.o .*.o *.s *.a *~ .depend .depfiles/*.d diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/margi_cs.mk.MAIN linux.20pre2-ac1/drivers/media/video/margi/margi_cs.mk.MAIN --- linux.20pre2/drivers/media/video/margi/margi_cs.mk.MAIN 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/margi_cs.mk.MAIN 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,43 @@ +# +# Makefile for margi_cs +# Marcus Metzler +# + +VER = 0.5.0 + +FILES = margi_cs.mk margi2/margi_cs.mk \ + margi2/margi margi2/margi.opts margi2/margi.conf margi2/margi_cs.4\ + margi2/audio.c margi2/audio.h margi2/cardbase.c margi2/cardbase.h\ + margi2/crc.c margi2/crc.h margi2/cvdv.c\ + margi2/cvdv.h margi2/cvdvtypes.h margi2/decoder.c margi2/decoder.h\ + margi2/dram.c margi2/dram.h margi2/i2c.c margi2/i2c.h margi2/l64014.h\ + margi2/l64021.h margi2/margi.c margi2/margi.h margi2/video.c \ + margi2/video.h \ + margi2/osd.c margi2/osd.h margi2/spu.c margi2/spu.h margi2/streams.c\ + margi2/streams.h margi2/ringbuffy.c margi2/ringbuffy.h \ + margi2/README margi2/COPYING margi2/AUTHORS margi2/CHANGES\ + margi2/cvdvext.h\ + margi2/testsuite/Makefile margi2/testsuite/cvdvutil.c \ + margi2/testsuite/cvdvutil.h margi2/testsuite/osdtest.c \ + margi2/testsuite/osdwrap.c margi2/testsuite/osdwrap.h \ + margi2/testsuite/showpic.c margi2/testsuite/showpicmovie.c\ + margi2/testsuite/showstill.c margi2/testsuite/testpattern.c\ + margi2/testsuite/showstill.c margi2/testsuite/playfile.c\ + margi2/include/ost/audio.h margi2/include/ost/video.h \ + margi2/include/ost/ca.h margi2/include/ost/demux.h\ + margi2/include/ost/dmx.h margi2/include/ost/frontend.h\ + margi2/dvb_demux.h margi2/dvb_demux.c margi2/dvbdev.h margi2/dvbdev.c\ + margi2/include/ost/sec.h margi2/dmxdev.h margi2/dmxdev.c \ + margi2/include/ost/osd.h margi2/dvb_formats.h margi2/dvb_formats.c + +all: + $(MAKE) -C margi2 -f margi_cs.mk + +install: + $(MAKE) -C margi2 install-modules MODULES="margi_cs.o" -f margi_cs.mk + $(MAKE) -C margi2 install-clients CLIENTS=margi -f margi_cs.mk + $(MAKE) -C margi2 install-man4 MAN4=margi_cs.4 -f margi_cs.mk + +dist: + tar czvf margi_cs-$(VER).tar.gz $(FILES) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/margi.h linux.20pre2-ac1/drivers/media/video/margi/margi.h --- linux.20pre2/drivers/media/video/margi/margi.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/margi.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,62 @@ +/* + margi.h + + Copyright (C) Marcus Metzler for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef margi_cs_h +#define margi_cs_h + +#include "cardbase.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PBUFFER 100 + +u_char read_indexed_register(struct cvdv_cards *card, int addr); +void write_indexed_register(struct cvdv_cards *card, int addr, + u_char data); +void WriteByte(struct cvdv_cards *card, int addr, u_char data); +u_char ReadByte(struct cvdv_cards *card, int addr); +void MaskByte(struct cvdv_cards *card, int addr, u_char mask, u_char bits); +int MargiFreeBuffers(struct cvdv_cards *card); +int MargiSetBuffers(struct cvdv_cards *card, uint32_t size, int isB); +int MargiFlush (struct cvdv_cards *card); +int MargiPushA(struct cvdv_cards *card, int count, const char *data); +int MargiPushB(struct cvdv_cards *card, int count, const char *data); +int DecoderStartChannel(struct cvdv_cards *card); +int DecoderStopChannel(struct cvdv_cards *card); +void DACSetFrequency(struct cvdv_cards *card, int khz, int multiple); +stream_type get_stream_type(struct cvdv_cards *card); +audio_type get_audio_type(struct cvdv_cards *card); + +#ifdef NOINT +void Timerfunction(unsigned long data); +#endif + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/margi.opts linux.20pre2-ac1/drivers/media/video/margi/margi.opts --- linux.20pre2/drivers/media/video/margi/margi.opts 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/margi.opts 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,4 @@ +# +# Option for margi +# + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/osd.c linux.20pre2-ac1/drivers/media/video/margi/osd.c --- linux.20pre2/drivers/media/video/margi/osd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/osd.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,947 @@ +/* + osd.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + //////////////////////////////////////////////////////////////// + // // + // Functions to Draw on the On Screen Display of the L64021 // + // CLUT-Mode with 2, 4, or 8 bit per pixel, up to 720*576 // + // // +//////////////////////////////////////////////////////////////// +// OSD Pixel Aspect Ratio: +// CCIR601 525 Lines (NTSC,PAL-M): 11/10 (100*100 appears as 100*110) +// CCIR601 625 Lines (PAL): 11/12 (100*100 appears as 100*91.6) +// +// OSD functions for external use: +// int OSDOpen(struct cvdv_cards *card); +// int OSDClose(struct cvdv_cards *card); +// int OSDQuery(struct cvdv_cards *card, int *x0, int *y0, int *x1, int *y1, int *aspx, int *aspy); +// int OSDStartPicture(struct cvdv_cards *card, int left, int top, int width, int height, int bit, int mix); +// void OSDShow(struct cvdv_cards *card); +// void OSDHide(struct cvdv_cards *card); +// void OSDClear(struct cvdv_cards *card); +// void OSDFill(struct cvdv_cards *card, int col); +// int OSDSetColor(struct cvdv_cards *card, int num, int R, int G, int B, int mix, int trans); +// int OSDSetPixel(struct cvdv_cards *card, int x, int y, int col); +// int OSDGetPixel(struct cvdv_cards *card, int x, int y); +// int OSDSetRow(struct cvdv_cards *card, int x0, int y, int x1, u8 *data); +// int OSDFillRow(struct cvdv_cards *card, int x0, int y, int x1, int col); +// void OSDLine(struct cvdv_cards *card, int x0, int y0, int x1, int y1, int col); +// +// Return codes: (unless otherwise specified) +// 0: OK +// -1: Range error +// -2: OSD not open +// + +#define __NO_VERSION__ + +#include "osd.h" +#include "dram.h" +#include "l64021.h" + + // Builds a 4-word picture header in buf +// returns number of words in pixel field on success, -1 on error +int OSDHeader(u16 * buf, // 4 words + int *bit, // bit per pixel: 2, 4, or 8 + int *startrow, // position of our block, + int *stoprow, // row: 0..313 + int *startcol, // col: 0..864 + int *stopcol, // + int *mix, // opacity for mixed pixel, 0..15 (0%..94% resp.) + int nopal) +{ // 1: use previous palette + int count; + if (buf != NULL) { + if (*bit == 8) + *bit = 1; + else if (*bit == 2) + *bit = 0; + else + *bit = 2; + if (*startrow < 0) + *startrow = 0; + if (*startrow > 312) + *startrow = 312; + if (*stoprow <= *startrow) + *stoprow = *startrow + 1; + if (*stoprow > 313) + *stoprow = 313; + if (*startcol < 0) + *startcol = 0; + if (*startcol > 863) + *startcol = 863; + if (*stopcol <= *startcol) + *stopcol = *startcol + 2; + if (*stopcol > 864) + *stopcol = 864; + if ((*stopcol - *startcol + 1) & 1) + (*stopcol)--; + if (*mix < 0) + *mix = 0; + if (*mix > 15) + *mix = 15; + buf[0] = ((*bit << 14) & 0x8000) | (*startrow & 0x01FF); + buf[1] = + ((*mix << 12) & 0xF000) | ((*bit << 11) & 0x0800) | + ((nopal) ? 0x0400 : 0x0000) | (*stoprow & 0x01FF); + buf[2] = *startcol & 0x03FF; + buf[3] = *stopcol & 0x03FF; + count = + (*stoprow - *startrow + 1) * (*stopcol - *startcol + + 1); + if (*bit == 1) { + count = + ((count >> 3) + ((count & 0x07) ? 1 : 0)) << 2; + *bit = 8; + } else if (*bit == 0) { + count = + ((count >> 5) + ((count & 0x1F) ? 1 : 0)) << 2; + *bit = 2; + } else if (*bit == 2) { + count = + ((count >> 4) + ((count & 0x0F) ? 1 : 0)) << 2; + *bit = 4; + } + return count; // word count of pixel data + } else + return -1; +} + +// enables OSD mode +int OSDShow(struct cvdv_cards *card) +{ + if (card->OSD.open) { + DecoderMaskByte(card, 0x109, 0x03, 0x01); + DecoderDelByte(card, 0x112, 0x10); // no filter + return 0; + } else + return -2; +} + +// disables OSD mode +int OSDHide(struct cvdv_cards *card) +{ + if (card->OSD.open) { + DecoderMaskByte(card, 0x109, 0x03, 0x00); + return 0; + } else + return -2; +} + +// creates an empty picture in the memory of the card +// ONLY ONE PICTURE PER CARD! +// maximum sizes: NTSC: 720*525 PAL: 720*576 +// maximum positions: NTSC: 858*525 PAL: 864*625 +// returns 0 on success, -1 on DRAM allocation error +int OSDStartPicture(struct cvdv_cards *card, int left, int top, int width, + int height, int bit, int mix) +{ + u16 TermHeader[] = { 0x01FF, 0x05FF, 0x0000, 0x0000 }; + u16 header[4]; + int size, pixelsize, palsize, frametop, startrow, stoprow, + startcol, stopcol; + + if (card->OSD.open) + return -2; + if (top & 1) { + card->OSD.evenfirst = 0; + card->OSD.evenheight = height / 2; + card->OSD.oddheight = height - card->OSD.evenheight; + } else { + card->OSD.evenfirst = 1; + card->OSD.oddheight = height / 2; + card->OSD.evenheight = height - card->OSD.oddheight; + } + + // Setting the picture for the lines in the even field + frametop = top / 2; + startrow = frametop; + stoprow = frametop + card->OSD.evenheight - 1; + startcol = left; + stopcol = left + width - 1; + pixelsize = + OSDHeader(header, &bit, &startrow, &stoprow, &startcol, + &stopcol, &mix, 0); + card->OSD.evenheight = stoprow - startrow + 1; + card->OSD.bpp = bit; + if (bit == 8) + palsize = 256; + else if (bit == 2) + palsize = 4; + else + palsize = 16; + size = 8 + palsize + pixelsize; + card->OSD.evenmem = DRAMAlloc(card, size, 32); + if (card->OSD.evenmem == BLANK) + return -1; + card->OSD.evendata = card->OSD.evenmem; + card->OSD.evenpalette = card->OSD.evendata + 4; + card->OSD.evenbitmap = card->OSD.evenpalette + palsize; + card->OSD.eventerm = card->OSD.evenbitmap + pixelsize; + DecoderWriteWord(card, 0x110, (u16) (card->OSD.evendata >> 5)); + DRAMWriteWord(card, card->OSD.evendata, 4, header, 0); + DRAMFillByte(card, card->OSD.evenpalette, + (palsize + pixelsize) * 2, 0x00); + DRAMWriteWord(card, card->OSD.eventerm, 4, TermHeader, 0); + + // Setting the picture for the lines in the odd frame + frametop += card->OSD.evenfirst; + startrow = frametop; + stoprow = frametop + card->OSD.oddheight - 1; + pixelsize = + OSDHeader(header, &bit, &startrow, &stoprow, &startcol, + &stopcol, &mix, 0); + card->OSD.oddheight = stoprow - startrow + 1; + size = 8 + palsize + pixelsize; + card->OSD.oddmem = DRAMAlloc(card, size, 32); + if (card->OSD.oddmem == BLANK) + return -1; + card->OSD.odddata = card->OSD.oddmem; + card->OSD.oddpalette = card->OSD.odddata + 4; + card->OSD.oddbitmap = card->OSD.oddpalette + palsize; + card->OSD.oddterm = card->OSD.oddbitmap + pixelsize; + DecoderWriteWord(card, 0x10E, (u16) (card->OSD.odddata >> 5)); + DRAMWriteWord(card, card->OSD.odddata, 4, header, 0); + DRAMFillByte(card, card->OSD.oddpalette, (palsize + pixelsize) * 2, + 0x00); + DRAMWriteWord(card, card->OSD.oddterm, 4, TermHeader, 0); + + // Update of the picture dimensions + card->OSD.width = stopcol - startcol + 1; + card->OSD.height = card->OSD.evenheight + card->OSD.oddheight; + card->OSD.open = 1; + + MDEBUG(1,": OSD Open %dX%d, %d bit, mem 0x%08X/0x%08X\n", + card->OSD.width, card->OSD.height, card->OSD.bpp, + card->OSD.evendata, card->OSD.odddata); + return 0; +} + +// Disables OSD and releases the buffers +// returns 0 on success, 1 on "not open" +int OSDClose(struct cvdv_cards *card) +{ + if (card->OSD.open) { + OSDHide(card); + DRAMFree(card, card->OSD.evenmem); + DRAMFree(card, card->OSD.oddmem); + card->OSD.open = 0; + return 0; + } else + return -2; +} + +// Opens OSD with this size and bit depth +// returns 0 on success, 1 on DRAM allocation error, 2 on "already open" +int OSDOpen(struct cvdv_cards *card, int x0, int y0, int x1, int y1, + int bit, int mix) +{ + int ret; + if (card->OSD.open) + OSDClose(card); + if (bit < 0) + bit = 8; + else if (bit < 2) + bit = 2; + else if (bit < 4) + bit = 4; + else + bit = 8; + if (x0 < 0) + x0 = 0; + if (x1 < 0) + x1 = 720 - 1; + if (x1 < x0) + x1 = x0; + if (y0 < 0) + y0 = 0; + if (y1 < 0) + y1 = 576 - 1; + if (y1 < y0) + y1 = y0; + if ((x1 + 1) > 720) + x1 = 720 - 1; + if (x0 > x1) + x0 = x1; + if (CCIR601Lines(card->videomode) == 625) { // PAL + if ((y1 + 1) > 576) + y1 = 576 - 1; + if (y0 > y1) + y0 = y1; + if (! + (ret = + OSDStartPicture(card, 134 + x0, 48 + y0, x1 - x0 + 1, + y1 - y0 + 1, bit, mix))) + card->OSD.aspectratio = 12; // pixel aspect ratio 12/11 + } else { // NTSC + if ((y1 + 1) > 484) + y1 = 484 - 1; + if (y0 > y1) + y0 = y1; + if (! + (ret = + OSDStartPicture(card, 126 + x0, 44 + y0, x1 - x0 + 1, + y1 - y0 + 1, bit, mix))) + card->OSD.aspectratio = 10; // pixel aspect ratio 10/11 + } + return ret; +} + +// fills parameters with the picture dimensions and the pixel aspect ratio (aspy=11) +int OSDQuery(struct cvdv_cards *card, int *x0, int *y0, int *x1, int *y1, + int *aspx) +{ + if (!card->OSD.open) + return -2; + *x0 = 0; + *x1 = card->OSD.width - 1; + *y0 = 0; + *y1 = card->OSD.height - 1; + *aspx = card->OSD.aspectratio; + return 0; +} + +// Sets all pixel to color 0 +int OSDClear(struct cvdv_cards *card) +{ + if (!card->OSD.open) + return -2; + DRAMFillByte(card, card->OSD.oddbitmap, + (int) (card->OSD.oddterm - card->OSD.oddbitmap) * 2, + 0x00); + DRAMFillByte(card, card->OSD.evenbitmap, + (int) (card->OSD.eventerm - card->OSD.evenbitmap) * 2, + 0x00); + return 0; +} + +// Sets all pixel to color +int OSDFill(struct cvdv_cards *card, int col) +{ + u8 color; + if (!card->OSD.open) + return -2; + if (card->OSD.bpp == 8) { + color = col & 0xFF; + } else if (card->OSD.bpp == 4) { + color = (col & 0xF); + color |= (color << 4); + } else if (card->OSD.bpp == 2) { + color = (col & 0x03); + for (col = 1; col <= 3; col++) + color |= (color << 2); + } else + color = 0x00; + DRAMFillByte(card, card->OSD.oddbitmap, + (int) (card->OSD.oddterm - card->OSD.oddbitmap) * 2, + color); + DRAMFillByte(card, card->OSD.evenbitmap, + (int) (card->OSD.eventerm - card->OSD.evenbitmap) * 2, + color); + return 0; +} + +// converts RGB(8 bit) to YCrCb(OSD format) +// mix: 0=opacity 100% 1=opacity at mix value +// trans: 0=mix bit applies 1=opacity 0% +// returns word in OSD palette format +u16 OSDColor(u8 R, u8 G, u8 B, int mix, int trans) +{ + u16 Y, Cr, Cb; + Y = R * 77 + G * 150 + B * 29; // Luma=0.299R+0.587G+0.114B 0..65535 + Cb = 2048 + B * 8 - (Y >> 5); // Cr 0..4095 + Cr = 2048 + R * 10 - (Y >> 5); // Cb 0..4095 + return ((trans) ? 0 : // transparent pixel + (Y & 0xFC00) | // Luma 0..63 + ((mix) ? 0x0100 : 0x0000) | // Opacity applies + ((Cb >> 4) & 0x00F0) | // Cb 0..15 + ((Cr >> 8) & 0x000F) // Cr 0..15 + ); +} + +// set palette entry to , and apply +// R,G,B: 0..255 +// RGB=1: R=Red, G=Green, B=Blue RGB=0: R=Y G=Cb B=Cr +// mix=0, trans=0: pixel opacity 100% (only OSD pixel shows) +// mix=1, trans=0: pixel opacity as specified in header +// trans=1: pixel opacity 0% (only video pixel shows) +// returns 0 on success, 1 on error +int OSDSetColor(struct cvdv_cards *card, int num, int R, int G, int B, + int YUV, int mix, int trans) +{ + u16 burst[4]; // minimal memory unit + u32 addr; + u16 color; + if (!card->OSD.open) + return -2; + if (R < 0) + R = 0; + if (R > 255) + R = 255; + if (G < 0) + G = 0; + if (G > 255) + G = 255; + if (B < 0) + B = 0; + if (B > 255) + B = 255; + if ((num >= 0) && (num < (1 << card->OSD.bpp))) { + if (num==0) MDEBUG(4,"OSD SetColor num=%d, R=%d, G=%d, B=%d, YUV=%d, mix=%d, trans=%d\n", + num,R,G,B,YUV,mix,trans); + color = ((YUV) + ? ((trans) ? 0 : ((R << 8) & 0xFC00) | + ((mix) ? 0x0100 : 0x0000) | (G & 0x00F0) | + ((B >> 4) & 0x000F)) : OSDColor(R, G, B, mix, + trans)); + + addr = card->OSD.oddpalette + num; + DRAMReadWord(card, addr & ~3, 4, burst, 0); + burst[addr & 3] = color; + DRAMWriteWord(card, addr & ~3, 4, burst, 0); + + addr = card->OSD.evenpalette + num; + DRAMReadWord(card, addr & ~3, 4, burst, 0); + burst[addr & 3] = color; + DRAMWriteWord(card, addr & ~3, 4, burst, 0); + + return 0; + } else + return -1; +} + +// Set a number of entries in the palette +// sets the entries "firstcolor" through "lastcolor" from the array "data" +// data has 4 byte for each color: +// R,G,B, and a transparency value: 0->tranparent, 1..254->mix, 255->no mix +int OSDSetPalette(struct cvdv_cards *card, int firstcolor, int lastcolor, + u8 * data) +{ + u16 burst[4]; // minimal memory unit + u32 addr; + u16 color; + int num, i = 0; + if (!card->OSD.open) + return -2; + for (num = firstcolor; num <= lastcolor; num++) + if ((num >= 0) && (num < (1 << card->OSD.bpp))) { + color = + OSDColor(data[i], data[i + 1], data[i + 2], + ((data[i + 3] < 255) ? 1 : 0), + ((data[i + 3] == 0) ? 1 : 0)); + i += 4; + + addr = card->OSD.oddpalette + num; + DRAMReadWord(card, addr & ~3, 4, burst, 0); + burst[addr & 3] = color; + DRAMWriteWord(card, addr & ~3, 4, burst, 0); + + addr = card->OSD.evenpalette + num; + DRAMReadWord(card, addr & ~3, 4, burst, 0); + burst[addr & 3] = color; + DRAMWriteWord(card, addr & ~3, 4, burst, 0); + } + return 0; +} + +// Sets transparency of mixed pixel (0..15) +int OSDSetTrans(struct cvdv_cards *card, int trans) +{ + u16 burst[4]; // minimal memory unit + if (!card->OSD.open) + return -2; + trans &= 0x000F; + DRAMReadWord(card, card->OSD.evendata, 4, burst, 0); + burst[1] = (burst[1] & 0x0FFF) | (trans << 12); + DRAMWriteWord(card, card->OSD.evendata, 4, burst, 0); + + DRAMReadWord(card, card->OSD.odddata, 4, burst, 0); + burst[1] = (burst[1] & 0x0FFF) | (trans << 12); + DRAMWriteWord(card, card->OSD.odddata, 4, burst, 0); + return 0; +} + +// sets pixel , to color number +// returns 0 on success, 1 on error +int OSDSetPixel(struct cvdv_cards *card, int x, int y, int col) +{ + u16 burst[4]; // minimal memory unit od DRAM + u32 addr; + int offset, ppw, pos, shift, height, posmask; + u16 mask; + + if (!card->OSD.open) + return -2; + if ((y & 1) == card->OSD.evenfirst) { // even or odd frame? + addr = card->OSD.oddbitmap; + height = card->OSD.oddheight; + } else { + addr = card->OSD.evenbitmap; + height = card->OSD.evenheight; + } + y >>= 1; + if ((x >= 0) && (x < card->OSD.width) && (y >= 0) && (y < height)) { // clipping + ppw = + ((card->OSD.bpp == 4) ? 2 : ((card->OSD.bpp == 8) ? 1 : 3)); // OK, 4-(ln(bpp)/ln(2)) would have worked, too... + pos = x + y * card->OSD.width; // pixel number in bitfield + addr += (pos >> ppw); // 21 bit address of word with our pixel + offset = addr & 3; // offset in burst + addr &= ~3; // 21 bit burst address + posmask = (1 << ppw) - 1; // mask for position inside word + shift = ((posmask - (pos & posmask)) << (4 - ppw)); // pixel shift inside word + mask = (1 << (1 << (4 - ppw))) - 1; // pixel mask + DRAMReadWord(card, addr, 4, burst, 0); // get the burst with our pixel... + burst[offset] = + (burst[offset] & ~(mask << shift)) | ((col & mask) << + shift); + DRAMWriteWord(card, addr, 4, burst, 0); // ...and write it back + return 0; + } else + return -1; +} + +// returns color number of pixel ,, or -1 +int OSDGetPixel(struct cvdv_cards *card, int x, int y) +{ + u16 burst[4]; // minimal memory unit + u32 addr; + int offset, ppw, pos, shift, height, posmask; + u16 mask; + + if (!card->OSD.open) + return -2; + if ((y & 1) == card->OSD.evenfirst) { // even or odd frame? + addr = card->OSD.oddbitmap; + height = card->OSD.oddheight; + } else { + addr = card->OSD.evenbitmap; + height = card->OSD.evenheight; + } + y >>= 1; + if ((x >= 0) && (x < card->OSD.width) && (y >= 0) && (y < height)) { // clipping + ppw = + ((card->OSD.bpp == 4) ? 2 : ((card->OSD.bpp == 8) ? 1 : 3)); // OK, 4-(ln(bpp)/ln(2)) would have worked, too... + pos = x + y * card->OSD.width; // pixel number in bitfield + addr += (pos >> ppw); // 21 bit address of word with our pixel + offset = addr & 3; // offset in burst + addr &= ~3; // 21 bit burst address + posmask = (1 << ppw) - 1; // mask for position inside word + shift = ((posmask - (pos & posmask)) << (4 - ppw)); // pixel shift inside word + mask = (1 << (1 << (4 - ppw))) - 1; // pixel mask + DRAMReadWord(card, addr, 4, burst, 0); // get the burst with our pixel... + return (burst[offset] >> shift) & mask; // ...and return it's value + } else + return -1; +} + +// fills pixels x0,y through x1,y with the content of data[] +// returns 0 on success, -1 on clipping all pixel +int OSDSetRow(struct cvdv_cards *card, int x0, int y, int x1, u8 * data) +{ + u16 burst[4]; // minimal memory unit + u32 addr, addr1, bitmap; + int offset, offset1, ppw, pos, pos1, shift, shift0, shift1, + shiftstep, height, bpp, x, i, endburst, endword; + u16 mask, posmask; + + if (!card->OSD.open) + return -2; + if ((y & 1) == card->OSD.evenfirst) { + bitmap = card->OSD.oddbitmap; + height = card->OSD.oddheight; + } else { + bitmap = card->OSD.evenbitmap; + height = card->OSD.evenheight; + } + y >>= 1; + if ((y >= 0) && (y < height)) { + i = 0; + if (x0 > x1) { + x = x1; + x1 = x0; + x0 = x; + } + if ((x0 >= card->OSD.width) || (x1 < 0)) + return -1; + if (x0 < 0) { + i -= x0; + x0 = 0; + } + if (x1 >= card->OSD.width) + x1 = card->OSD.width - 1; + bpp = card->OSD.bpp; // bits per pixel + ppw = ((bpp == 4) ? 2 : ((bpp == 8) ? 1 : 3)); // positional parameter + mask = (1 << bpp) - 1; // mask for one pixel + posmask = (1 << ppw) - 1; // mask for position inside word + + pos = x0 + (y * card->OSD.width); // pixel number of first pixel + pos1 = pos + x1 - x0; // pixel number of last pixel + shift0 = ((posmask - (pos & posmask)) << (4 - ppw)); + shift1 = ((posmask - (pos1 & posmask)) << (4 - ppw)); + shiftstep = 1 << (4 - ppw); + + addr = bitmap + (pos >> ppw); // DRAM address of word with first pixel + addr1 = bitmap + (pos1 >> ppw); // " " " " " last " + offset = (int) (addr & 3); // word position inside burst + offset1 = (int) (addr1 & 3); // number of last word in the last burst + addr &= ~3; // burst address + addr1 &= ~3; // burst address of last pixel + + endburst = (addr1 != addr); // end in other burst + endword = (offset1 != offset); // end in other word + + // read old content of first burst if the row start after the beginning or + // end before the end of the first burst + if (offset || (pos & posmask) || + (!endburst + && ((offset1 != 3) + || ((pos1 & posmask) != posmask)))) { + DRAMReadWord(card, addr, 4, burst, 0); + } + // End beyond or at the end of this word? + if (endburst || endword || ((pos1 & posmask) == posmask)) { + // Fill first word + for (shift = shift0; shift >= 0; shift -= shiftstep) { // bit position inside word + burst[offset] = + (burst[offset] & ~(mask << shift)) | + ((data[i++] & mask) << shift); + } + if (endburst || endword) { // Any more words to fill? + shift0 = posmask << (4 - ppw); // from here on, we start at the beginning of each word + offset++; // fill the rest of the burst + if (endburst) { // end not in this burst? + while (offset <= 3) { // fill remaining words + burst[offset] = 0x0000; // clear first + for (shift = shift0; + shift >= 0; + shift -= shiftstep) { + burst[offset] |= + ((data + [i++] & mask) + << shift); + } + offset++; + } + DRAMWriteWord(card, addr, 4, burst, 0); // write first burst + addr += 4; // go on to the next burst + while (addr < addr1) { // all bursts between start and end burst + for (offset = 0; + offset <= 3; offset++) { // 4 words per burst + burst[offset] = 0x0000; // clear first + for (shift = + shift0; + shift >= 0; + shift -= + shiftstep) { + burst + [offset] + |= + ((data + [i++] + & + mask) + << + shift); + } + } + DRAMWriteWord(card, addr, + 4, burst, 0); // write full burst + addr += 4; // next burst + } + offset = 0; + if ((offset1 < 3) || shift1) { // does the row ends before the end of the burst? + DRAMReadWord(card, addr, 4, + burst, 0); // then we have to read the old content + } + } + while (offset < offset1) { // end not in this word + burst[offset] = 0x0000; // clear first + for (shift = shift0; shift >= 0; + shift -= shiftstep) { + burst[offset] |= + ((data[i++] & mask) << + shift); + } + offset++; + } + for (shift = shift0; shift >= shift1; + shift -= shiftstep) { // last word + burst[offset] = + (burst[offset] & + ~(mask << shift)) | + ((data[i++] & mask) << shift); + } + } + } else { // row starts and ends in one word + for (shift = shift0; shift >= shift1; shift -= shiftstep) { // bit position inside word + burst[offset] = + (burst[offset] & ~(mask << shift)) | + ((data[i++] & mask) << shift); + } + } + DRAMWriteWord(card, addr, 4, burst, 0); // write only/last burst + return 0; + } else + return -1; +} + +// fills pixels x0,y0 through x1,y1 with the content of data[] +// inc contains the width of one line in the data block, +// inc<=0 uses blockwidth as linewidth +// returns 0 on success, -1 on clipping all pixel +int OSDSetBlock(struct cvdv_cards *card, int x0, int y0, int x1, int y1, + int inc, u8 * data) +{ + int i, w = x1 - x0 + 1, ret = 0; + if (inc > 0) + w = inc; + for (i = y0; i <= y1; i++) { + ret |= OSDSetRow(card, x0, i, x1, data); + data += w; + } + return ret; +} + +// fills pixels x0,y through x1,y with the color +// returns 0 on success, -1 on clipping all pixel +int OSDFillRow(struct cvdv_cards *card, int x0, int y, int x1, int col) +{ + u16 burst[4]; // minimal memory unit + u32 addr, addr1, bitmap; + int offset, offset1, ppw, pos, pos1, shift, shift0, shift1, + shiftstep, height, bpp, x, i, endburst, endword; + u16 mask, posmask; + + if (!card->OSD.open) + return -2; + if ((y & 1) == card->OSD.evenfirst) { + bitmap = card->OSD.oddbitmap; + height = card->OSD.oddheight; + } else { + bitmap = card->OSD.evenbitmap; + height = card->OSD.evenheight; + } + y >>= 1; + if ((y >= 0) && (y < height)) { + i = 0; + if (x0 > x1) { + x = x1; + x1 = x0; + x0 = x; + } + if ((x0 >= card->OSD.width) || (x1 < 0)) + return -1; + if (x0 < 0) { + i -= x0; + x0 = 0; + } + if (x1 >= card->OSD.width) + x1 = card->OSD.width - 1; + bpp = card->OSD.bpp; // bits per pixel + ppw = ((bpp == 4) ? 2 : ((bpp == 8) ? 1 : 3)); // positional parameter + mask = (1 << bpp) - 1; // mask for one pixel + posmask = (1 << ppw) - 1; // mask for position inside word + + pos = x0 + (y * card->OSD.width); // pixel number of first pixel + pos1 = pos + x1 - x0; // pixel number of last pixel + shift0 = ((posmask - (pos & posmask)) << (4 - ppw)); + shift1 = ((posmask - (pos1 & posmask)) << (4 - ppw)); + shiftstep = 1 << (4 - ppw); + + addr = bitmap + (pos >> ppw); // DRAM address of word with first pixel + addr1 = bitmap + (pos1 >> ppw); // " " " " " last " + offset = (int) (addr & 3); // word position inside burst + offset1 = (int) (addr1 & 3); // number of last word in the last burst + addr &= ~3; // burst address + addr1 &= ~3; // burst address of last pixel + + endburst = (addr1 != addr); // end in other burst + endword = (offset1 != offset); // end in other word + + // read old content of first burst if the row start after the beginning or + // end before the end of the first burst + if (offset || (pos & posmask) || + (!endburst + && ((offset1 != 3) + || ((pos1 & posmask) != posmask)))) { + DRAMReadWord(card, addr, 4, burst, 0); + } + if (endburst || endword || ((pos1 & posmask) == posmask)) { // end beyond or at the end of this word? + for (shift = shift0; shift >= 0; shift -= shiftstep) { // bit position inside word + burst[offset] = + (burst[offset] & ~(mask << shift)) | + ((col & mask) << shift); + } + if (endburst || endword) { + shift0 = posmask << (4 - ppw); // from here on, we start at the beginning of each word + offset++; // fill the rest of the burst + if (endburst) { // end not in this burst? + while (offset <= 3) { // fill remaining words + burst[offset] = 0x0000; // clear first + for (shift = shift0; + shift >= 0; + shift -= shiftstep) { + burst[offset] |= + ((col & mask) + << shift); + } + offset++; + } + DRAMWriteWord(card, addr, 4, burst, 0); // write first burst + addr += 4; // next burst + while (addr < addr1) { // write all the bursts between start and end burst + for (offset = 0; + offset <= 3; offset++) { + burst[offset] = + 0x0000; + for (shift = + shift0; + shift >= 0; + shift -= + shiftstep) { + burst + [offset] + |= + ((col + & + mask) + << + shift); + } + } + DRAMWriteWord(card, addr, + 4, burst, 0); + addr += 4; + } + offset = 0; + if ((offset1 < 3) || shift1) { // does the row ends before the end of the burst? + DRAMReadWord(card, addr, 4, + burst, 0); // then we have to read the old content + } + } + while (offset < offset1) { // end not in this word + burst[offset] = 0x0000; + for (shift = shift0; shift >= 0; + shift -= shiftstep) { + burst[offset] |= + ((col & mask) << + shift); + } + offset++; + } + for (shift = shift0; shift >= shift1; + shift -= shiftstep) { + burst[offset] = + (burst[offset] & + ~(mask << shift)) | ((col & + mask) << + shift); + } + } + } else { // row starts and ends in one word + for (shift = shift0; shift >= shift1; shift -= shiftstep) { // bit position inside word + burst[offset] = + (burst[offset] & ~(mask << shift)) | + ((col & mask) << shift); + } + } + DRAMWriteWord(card, addr, 4, burst, 0); + return 0; + } else + return -1; +} + +// fills pixels x0,y0 through x1,y1 with the color +// returns 0 on success, -1 on clipping all pixel +int OSDFillBlock(struct cvdv_cards *card, int x0, int y0, int x1, int y1, + int col) +{ + int i, ret = 0; + for (i = y0; i <= y1; i++) + ret |= OSDFillRow(card, x0, i, x1, col); + return ret; +} + +// draw a line from x0,y0 to x1,y1 with the color +int OSDLine(struct cvdv_cards *card, int x0, int y0, int x1, int y1, + int col) +{ + int ct, ix, iy, ax, ay, dx, dy, off; +#define sgn(a) ((a)?(((a)>0)?1:-1):0) + if (!card->OSD.open) + return -2; + dx = x1 - x0; + dy = y1 - y0; + if (dx == 0) { + if (dy < 0) + for (iy = y1; iy <= y0; iy++) + OSDSetPixel(card, x0, iy, col); + else + for (iy = y0; iy <= y1; iy++) + OSDSetPixel(card, x0, iy, col); + } else if (dy == 0) { + OSDFillRow(card, x0, y0, x1, col); + } else { + ay = 0; + ax = 0; + ix = sgn(dx); + dx = abs(dx); + iy = sgn(dy); + dy = abs(dy); + if (dx < dy) { + off = dx; + dx = dy; + dy = off; + ay = ix; + ax = iy; + ix = 0; + iy = 0; + } + off = dx >> 1; + ct = 1; + OSDSetPixel(card, x0, y0, col); + x1 = x0; + y1 = y0; + while (dx >= ct) { + x0 += ix; + y0 += ax; + ct++; + off += dy; + if (off > dx) { + off -= dx; + x0 += ay; + y0 += iy; + } + if (ax) { + OSDSetPixel(card, x0, y0, col); + } else { + if (y0 != y1) { + OSDFillRow(card, x1, y1, x0 - ay, + col); + x1 = x0; + y1 = y0; + } + } + } + if (!ax) + OSDFillRow(card, x1, y0, x0, col); + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/osd.h linux.20pre2-ac1/drivers/media/video/margi/osd.h --- linux.20pre2/drivers/media/video/margi/osd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/osd.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,148 @@ +/* + osd.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CVDV_OSD_H +#define CVDV_OSD_H + + //////////////////////////////////////////////////////////////// + // // + // Functions to Draw on the On Screen Display of the L64021 // + // CLUT-Mode with 2, 4, or 8 bit per pixel, up to 720*576 // + // // +//////////////////////////////////////////////////////////////// +// OSD Pixel Aspect Ratio: +// CCIR601 525 Lines (NTSC,PAL-M): 11/10 (100*100 appears as 100*110) +// CCIR601 625 Lines (PAL): 11/12 (100*100 appears as 100*91.6) +// +// OSD functions for external use: +// int OSDOpen(struct cvdv_cards *card); +// int OSDClose(struct cvdv_cards *card); +// int OSDQuery(struct cvdv_cards *card, int *x0, int *y0, int *x1, int *y1, int *aspx, int *aspy); +// int OSDStartPicture(struct cvdv_cards *card, int left, int top, int width, int height, int bit, int mix); +// void OSDShow(struct cvdv_cards *card); +// void OSDHide(struct cvdv_cards *card); +// void OSDClear(struct cvdv_cards *card); +// void OSDFill(struct cvdv_cards *card, int col); +// int OSDSetColor(struct cvdv_cards *card, int num, int R, int G, int B, int mix, int trans); +// int OSDSetPixel(struct cvdv_cards *card, int x, int y, int col); +// int OSDGetPixel(struct cvdv_cards *card, int x, int y); +// int OSDSetRow(struct cvdv_cards *card, int x0, int y, int x1, u8 *data); +// int OSDFillRow(struct cvdv_cards *card, int x0, int y, int x1, int col); +// void OSDLine(struct cvdv_cards *card, int x0, int y0, int x1, int y1, int col); +// +// Return codes: (unless otherwise specified) +// 0: OK +// -1: Range error +// -2: OSD not open +// + +#include "cardbase.h" + +// enables OSD mode +int OSDShow(struct cvdv_cards *card); + +// disables OSD mode +int OSDHide(struct cvdv_cards *card); + +// creates an empty picture in the memory of the card +// ONLY ONE PICTURE PER CARD! ( might be changed in the future, if i find time...) +// maximum sizes: NTSC: 720*525 PAL: 720*576 +// maximum positions: NTSC: 858*525 PAL: 864*625 +// returns 0 on success, -1 on DRAM allocation error +int OSDStartPicture(struct cvdv_cards *card, int left, int top, int width, + int height, int bit, int mix); + +// Disables OSD and releases the buffers +// returns 0 on success, 1 on "not open" +int OSDClose(struct cvdv_cards *card); + +// Opens OSD with this size and bit depth +// returns 0 on success, 1 on DRAM allocation error, 2 on "already open" +int OSDOpen(struct cvdv_cards *card, int x0, int y0, int x1, int y1, + int bit, int mix); + +// fills parameters with the picture dimensions and the pixel aspect ratio (aspy=11) +int OSDQuery(struct cvdv_cards *card, int *x0, int *y0, int *x1, int *y1, + int *aspx); + +// Sets all pixel to color 0 +int OSDClear(struct cvdv_cards *card); + +// Sets all pixel to color +int OSDFill(struct cvdv_cards *card, int col); + +// converts RGB(8 bit) to YCrCb(OSD format) +// mix: 0=opacity 100% 1=opacity at mix value +// trans: 0=mix bit applies 1=opacity 0% +// returns word in OSD palette format +u16 OSDColor(u8 R, u8 G, u8 B, int mix, int trans); + +// set palette entry to , and apply +// R,G,B: 0..255 +// RGB=1: R=Red, G=Green, B=Blue RGB=0: R=Y G=Cb B=Cr +// mix=0, trans=0: pixel opacity 100% (only OSD pixel shows) +// mix=1, trans=0: pixel opacity as specified in header +// trans=1: pixel opacity 0% (only video pixel shows) +// returns 0 on success, 1 on error +int OSDSetColor(struct cvdv_cards *card, int num, int R, int G, int B, + int YUV, int mix, int trans); + +// Set a number of entries in the palette +// sets the entries "firstcolor" through "lastcolor" from the array "data" +// data has 4 byte for each color: +// R,G,B, and a transparency value: 0->tranparent, 1..254->mix, 255->no mix +int OSDSetPalette(struct cvdv_cards *card, int firstcolor, int lastcolor, + u8 * data); + +// Sets transparency of mixed pixel (0..15) +int OSDSetTrans(struct cvdv_cards *card, int trans); + +// sets pixel , to color number +// returns 0 on success, 1 on error +int OSDSetPixel(struct cvdv_cards *card, int x, int y, int col); + +// returns color number of pixel ,, or -1 +int OSDGetPixel(struct cvdv_cards *card, int x, int y); + +// fills pixels x0,y through x1,y with the content of data[] +// returns 0 on success, -1 on clipping all pixel +int OSDSetRow(struct cvdv_cards *card, int x0, int y, int x1, u8 * data); + +// fills pixels x0,y0 through x1,y1 with the content of data[] +// inc contains the width of one line in the data block, +// inc<=0 uses blockwidth as linewidth +// returns 0 on success, -1 on clipping all pixel +int OSDSetBlock(struct cvdv_cards *card, int x0, int y0, int x1, int y1, + int inc, u8 * data); + +// fills pixels x0,y through x1,y with the color +// returns 0 on success, -1 on clipping all pixel +int OSDFillRow(struct cvdv_cards *card, int x0, int y, int x1, int col); + +// fills pixels x0,y0 through x1,y1 with the color +// returns 0 on success, -1 on clipping all pixel +int OSDFillBlock(struct cvdv_cards *card, int x0, int y0, int x1, int y1, + int col); + +// draw a line from x0,y0 to x1,y1 with the color +int OSDLine(struct cvdv_cards *card, int x0, int y0, int x1, int y1, + int col); + +#endif /* CVDV_OSD_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ost/audio.h linux.20pre2-ac1/drivers/media/video/margi/ost/audio.h --- linux.20pre2/drivers/media/video/margi/ost/audio.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ost/audio.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,120 @@ +/* + * audio.h + * + * Copyright (C) 2000 Ralph Metzler + * & Marcus Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Lesser Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _OST_AUDIO_H_ +#define _OST_AUDIO_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#define boolean int +#define true 1 +#define false 0 + +typedef enum { + AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */ + AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */ +} audioStreamSource_t; + +typedef enum { + AUDIO_STOPPED, /* Device is stopped */ + AUDIO_PLAYING, /* Device is currently playing */ + AUDIO_PAUSED /* Device is paused */ +} audioPlayState_t; + +typedef enum { + AUDIO_STEREO, + AUDIO_MONO_LEFT, + AUDIO_MONO_RIGHT, +} audioChannelSelect_t; + +typedef struct audioStatus { + boolean AVSyncState; /* sync audio and video? */ + boolean muteState; /* audio is muted */ + audioPlayState_t playState; /* current playback state */ + audioStreamSource_t streamSource; /* current stream source */ + audioChannelSelect_t channelSelect; /* currently selected channel */ + boolean bypassMode; /* pass on audio data to separate + decoder hardware */ +} audioStatus_t; + +typedef struct audioMixer { + unsigned int volume_left; + unsigned int volume_right; + // what else do we need? bass, pass-through, ... +} audioMixer_t; + +typedef +struct audioKaraoke{ /* if Vocal1 or Vocal2 are non-zero, they get mixed */ + int vocal1; /* into left and right t at 70% each */ + int vocal2; /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets */ + int melody; /* mixed into the left channel and */ + /* Vocal2 into the right channel at 100% each. */ + /* if Melody is non-zero, the melody channel gets mixed */ /* into left and right */ +} audioKaraoke_t; + +typedef uint16_t audioAttributes_t; +/* bits: descr. */ +/* 15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, */ +/* 12 multichannel extension */ +/* 11-10 audio type (0=not spec, 1=language included) */ +/* 9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) */ +/* 7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit, */ +/* 5- 4 Sample frequency fs (0=48kHz, 1=96kHz) */ +/* 2- 0 number of audio channels (n+1 channels) */ + + +/* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */ +#define AUDIO_CAP_DTS 1 +#define AUDIO_CAP_LPCM 2 +#define AUDIO_CAP_MP1 4 +#define AUDIO_CAP_MP2 8 +#define AUDIO_CAP_MP3 16 +#define AUDIO_CAP_AAC 32 +#define AUDIO_CAP_OGG 64 +#define AUDIO_CAP_SDDS 128 +#define AUDIO_CAP_AC3 256 + +#define AUDIO_STOP _IO('o', 1) +#define AUDIO_PLAY _IO('o', 2) +#define AUDIO_PAUSE _IO('o', 3) +#define AUDIO_CONTINUE _IO('o', 4) +#define AUDIO_SELECT_SOURCE _IOW('o', 5, audioStreamSource_t) +#define AUDIO_SET_MUTE _IOW('o', 6, boolean) +#define AUDIO_SET_AV_SYNC _IOW('o', 7, boolean) +#define AUDIO_SET_BYPASS_MODE _IOW('o', 8, boolean) +#define AUDIO_CHANNEL_SELECT _IOW('o', 9, audioChannelSelect_t) +#define AUDIO_GET_STATUS _IOR('o', 10, audioStatus_t *) + +#define AUDIO_GET_CAPABILITIES _IOR('o', 11, unsigned int *) +#define AUDIO_CLEAR_BUFFER _IO('o', 12) +#define AUDIO_SET_ID _IOW('o', 13, int) +#define AUDIO_SET_MIXER _IOW('o', 14, audioMixer_t *) +#define AUDIO_SET_STREAMTYPE _IOW('o', 15, unsigned int) +#define AUDIO_SET_EXT_ID _IOW('o', 16, int) +#define AUDIO_SET_ATTRIBUTES _IOW('o', 17, audioAttributes_t) +#define AUDIO_SET_KARAOKE _IOW('o', 18, audioKaraoke_t *) +#endif /* _OST_AUDIO_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ost/ca.h linux.20pre2-ac1/drivers/media/video/margi/ost/ca.h --- linux.20pre2/drivers/media/video/margi/ost/ca.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ost/ca.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,85 @@ +/* + * ca.h + * + * Copyright (C) 2000 Ralph Metzler + * & Marcus Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Lesser Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _OST_CA_H_ +#define _OST_CA_H_ + +/* slot interface types and info */ + +typedef struct ca_slot_info_s { + int num; /* slot number */ + + int type; /* CA interface this slot supports */ +#define CA_CI 1 /* CI high level interface */ +#define CA_CI_LINK 2 /* CI link layer level interface */ +#define CA_CI_PHYS 4 /* CI physical layer level interface */ +#define CA_SC 128 /* simple smart card interface */ + + unsigned int flags; +#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */ +#define CA_CI_MODULE_READY 2 +} ca_slot_info_t; + + +/* descrambler types and info */ + +typedef struct ca_descr_info_s { + unsigned int num; /* number of available descramblers (keys) */ + unsigned int type; /* type of supported scrambling system */ +#define CA_ECD 1 +#define CA_NDS 2 +#define CA_DSS 4 +} ca_descr_info_t; + +typedef struct ca_cap_s { + unsigned int slot_num; /* total number of CA card and module slots */ + unsigned int slot_type; /* OR of all supported types */ + unsigned int descr_num; /* total number of descrambler slots (keys) */ + unsigned int descr_type; /* OR of all supported types */ +} ca_cap_t; + +/* a message to/from a CI-CAM */ +typedef struct ca_msg_s { + unsigned int index; + unsigned int type; + unsigned int length; + unsigned char msg[256]; +} ca_msg_t; + +typedef struct ca_descr_s { + unsigned int index; + unsigned int parity; + unsigned char cw[8]; +} ca_descr_t; + +#define CA_RESET _IOW('o', 128, int) +#define CA_GET_CAP _IOR('o', 129, ca_cap_t *) +#define CA_GET_SLOT_INFO _IOR('o', 130, ca_slot_info_t *) +#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t *) +#define CA_GET_MSG _IOR('o', 132, ca_msg_t *) +#define CA_SEND_MSG _IOW('o', 133, ca_msg_t *) +#define CA_SET_DESCR _IOW('o', 134, ca_descr_t *) +#define CA_SELECT_SLOT _IOW('o', 135, int) + +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ost/demux.h linux.20pre2-ac1/drivers/media/video/margi/ost/demux.h --- linux.20pre2/drivers/media/video/margi/ost/demux.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ost/demux.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,346 @@ +/* * demux.h * * Copyright (c) 2000 Nokia Research Center + * Tampere, FINLAND + * + * Project: + * Universal Broadcast Access + * + * Contains: + * Type definitions of a Linux kernel-level API for filtering MPEG-2 TS + * packets and MPEG-2 sections. Support for PES packet filtering will be + * added later. + * + * History: + * 12.01.2000/JPL File created - Initial version. + * 18.02.2000/JPL Minor corrections. + * 21.02.2000/JPL DMX_NAME_SIZE and dmx_in_use() removed, typos fixed, + * some names changed. + * 23.02.2000/JPL Added a parameter indicating the callback source in + * the callback functions. + * 10.03.2000/JPL Added the macros DMX_DIR_ENTRY() and DMX_FE_ENTRY(). + * 15.03.2000/JPL Added the capabilities field to dmx_demux_t. + * 22.03.2000/JPL Corrected the callback parameter in the + * allocate_x_feed() functions. + * 03.04.2000/JPL Added support for optional resource conflict resolution + * and scarce resource handling. + * 05.04.2000/JPL Changed the dmx_resolve_conflict() to use resource + * type as a parameter. + * 12.04.2000/JPL Added a second buffer parameter for dmx_x_callback() + * functions to better handle buffer wrapping. + * 26.04.2000/JPL Added functions for section-level descrambling. + * 03.09.2000/JPL Removed support for conflict resolution and scarce + * resource handling. Otherwise only minor changes to + * data structures and function prototypes. + * + * + * Author: + * Juha-Pekka Luoma (JPL) + * Nokia Research Center + * + * Notes: + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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. + * + */ +/* $Id: demux.h,v 1.14 2002/02/03 11:38:56 mocm Exp $ */ + +#ifndef __DEMUX_H +#define __DEMUX_H + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include /* __u8, __u16, ... */ +#include /* list_entry(), struct list_head */ +#include /* struct timespec */ +#include /* Function return values */ + +/*--------------------------------------------------------------------------*/ +/* Common definitions */ +/*--------------------------------------------------------------------------*/ + +/* + * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter. + */ + +#ifndef DMX_MAX_FILTER_SIZE +#define DMX_MAX_FILTER_SIZE 18 +#endif +/* + * dmx_success_t: Success codes for the Demux Callback API. + */ + +typedef enum { + DMX_OK = 0, /* Received Ok */ + DMX_LENGTH_ERROR, /* Incorrect length */ + DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ + DMX_CRC_ERROR, /* Incorrect CRC */ + DMX_FRAME_ERROR, /* Frame alignment error */ + DMX_FIFO_ERROR, /* Receiver FIFO overrun */ + DMX_MISSED_ERROR /* Receiver missed packet */ +} dmx_success_t; + +/*--------------------------------------------------------------------------*/ +/* TS packet reception */ +/*--------------------------------------------------------------------------*/ + +/* TS filter type for set_type() */ + +#define TS_PACKET 1 /* send TS packets (188 bytes) to callback (default) */ +#define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS + payload (<=184 bytes per packet) to callback */ +#define TS_DECODER 4 /* send stream to built-in decoder (if present) */ + +/* PES type for filters which write to built-in decoder */ +/* these should be kept identical to the types in dmx.h */ + +typedef enum +{ + DMX_TS_PES_AUDIO, /* also send packets to audio decoder (if it exists) */ + DMX_TS_PES_VIDEO, /* ... */ + DMX_TS_PES_TELETEXT, + DMX_TS_PES_SUBTITLE, + DMX_TS_PES_PCR, + DMX_TS_PES_OTHER, +} dmx_ts_pes_t; + + +struct dmx_ts_feed_s { + int is_filtering; /* Set to non-zero when filtering in progress */ + struct dmx_demux_s* parent; /* Back-pointer */ + void* priv; /* Pointer to private data of the API client */ + int (*set) (struct dmx_ts_feed_s* feed, + __u16 pid, + size_t callback_length, + size_t circular_buffer_size, + int descramble, + struct timespec timeout); + int (*start_filtering) (struct dmx_ts_feed_s* feed); + int (*stop_filtering) (struct dmx_ts_feed_s* feed); + int (*set_type) (struct dmx_ts_feed_s* feed, + int type, + dmx_ts_pes_t pes_type); +}; + +typedef struct dmx_ts_feed_s dmx_ts_feed_t; + +/*--------------------------------------------------------------------------*/ +/* PES packet reception (not supported yet) */ +/*--------------------------------------------------------------------------*/ + +typedef struct dmx_pes_filter_s { + struct dmx_pes_s* parent; /* Back-pointer */ + void* priv; /* Pointer to private data of the API client */ +} dmx_pes_filter_t; + +typedef struct dmx_pes_feed_s { + int is_filtering; /* Set to non-zero when filtering in progress */ + struct dmx_demux_s* parent; /* Back-pointer */ + void* priv; /* Pointer to private data of the API client */ + int (*set) (struct dmx_pes_feed_s* feed, + __u16 pid, + size_t circular_buffer_size, + int descramble, + struct timespec timeout); + int (*start_filtering) (struct dmx_pes_feed_s* feed); + int (*stop_filtering) (struct dmx_pes_feed_s* feed); + int (*allocate_filter) (struct dmx_pes_feed_s* feed, + dmx_pes_filter_t** filter); + int (*release_filter) (struct dmx_pes_feed_s* feed, + dmx_pes_filter_t* filter); +} dmx_pes_feed_t; + +/*--------------------------------------------------------------------------*/ +/* Section reception */ +/*--------------------------------------------------------------------------*/ + +typedef struct { + __u8 filter_value [DMX_MAX_FILTER_SIZE]; + __u8 filter_mask [DMX_MAX_FILTER_SIZE]; + struct dmx_section_feed_s* parent; /* Back-pointer */ + void* priv; /* Pointer to private data of the API client */ +} dmx_section_filter_t; + +struct dmx_section_feed_s { + int is_filtering; /* Set to non-zero when filtering in progress */ + struct dmx_demux_s* parent; /* Back-pointer */ + void* priv; /* Pointer to private data of the API client */ + int (*set) (struct dmx_section_feed_s* feed, + __u16 pid, + size_t circular_buffer_size, + int descramble, + int check_crc); + int (*allocate_filter) (struct dmx_section_feed_s* feed, + dmx_section_filter_t** filter); + int (*release_filter) (struct dmx_section_feed_s* feed, + dmx_section_filter_t* filter); + int (*start_filtering) (struct dmx_section_feed_s* feed); + int (*stop_filtering) (struct dmx_section_feed_s* feed); +}; +typedef struct dmx_section_feed_s dmx_section_feed_t; + +/*--------------------------------------------------------------------------*/ +/* Callback functions */ +/*--------------------------------------------------------------------------*/ + +typedef int (*dmx_ts_cb) ( __u8 * buffer1, + size_t buffer1_length, + __u8 * buffer2, + size_t buffer2_length, + dmx_ts_feed_t* source, + dmx_success_t success); + +typedef int (*dmx_section_cb) ( __u8 * buffer1, + size_t buffer1_len, + __u8 * buffer2, + size_t buffer2_len, + dmx_section_filter_t * source, + dmx_success_t success); + +typedef int (*dmx_pes_cb) ( __u8 * buffer1, + size_t buffer1_len, + __u8 * buffer2, + size_t buffer2_len, + dmx_pes_filter_t* source, + dmx_success_t success); + +/*--------------------------------------------------------------------------*/ +/* DVB Front-End */ +/*--------------------------------------------------------------------------*/ + +typedef enum { + DMX_OTHER_FE = 0, + DMX_SATELLITE_FE, + DMX_CABLE_FE, + DMX_TERRESTRIAL_FE, + DMX_LVDS_FE, + DMX_ASI_FE, /* DVB-ASI interface */ + DMX_MEMORY_FE +} dmx_frontend_source_t; + +typedef struct { + /* The following char* fields point to NULL terminated strings */ + char* id; /* Unique front-end identifier */ + char* vendor; /* Name of the front-end vendor */ + char* model; /* Name of the front-end model */ + struct list_head connectivity_list; /* List of front-ends that can + be connected to a particular + demux */ + void* priv; /* Pointer to private data of the API client */ + dmx_frontend_source_t source; +} dmx_frontend_t; + +/*--------------------------------------------------------------------------*/ +/* MPEG-2 TS Demux */ +/*--------------------------------------------------------------------------*/ + +/* + * Flags OR'ed in the capabilites field of struct dmx_demux_s. + */ + +#define DMX_TS_FILTERING 1 +#define DMX_PES_FILTERING 2 +#define DMX_SECTION_FILTERING 4 +#define DMX_MEMORY_BASED_FILTERING 8 /* write() available */ +#define DMX_CRC_CHECKING 16 +#define DMX_TS_DESCRAMBLING 32 +#define DMX_SECTION_PAYLOAD_DESCRAMBLING 64 +#define DMX_MAC_ADDRESS_DESCRAMBLING 128 + +/* + * Demux resource type identifier. +*/ + +/* + * DMX_FE_ENTRY(): Casts elements in the list of registered + * front-ends from the generic type struct list_head + * to the type * dmx_frontend_t + *. +*/ + +#define DMX_FE_ENTRY(list) list_entry(list, dmx_frontend_t, connectivity_list) + +struct dmx_demux_s { + /* The following char* fields point to NULL terminated strings */ + char* id; /* Unique demux identifier */ + char* vendor; /* Name of the demux vendor */ + char* model; /* Name of the demux model */ + __u32 capabilities; /* Bitfield of capability flags */ + dmx_frontend_t* frontend; /* Front-end connected to the demux */ + struct list_head reg_list; /* List of registered demuxes */ + void* priv; /* Pointer to private data of the API client */ + int users; /* Number of users */ + int (*open) (struct dmx_demux_s* demux); + int (*close) (struct dmx_demux_s* demux); + int (*write) (struct dmx_demux_s* demux, const char* buf, size_t count); + int (*allocate_ts_feed) (struct dmx_demux_s* demux, + dmx_ts_feed_t** feed, + dmx_ts_cb callback); + int (*release_ts_feed) (struct dmx_demux_s* demux, + dmx_ts_feed_t* feed); + int (*allocate_pes_feed) (struct dmx_demux_s* demux, + dmx_pes_feed_t** feed, + dmx_pes_cb callback); + int (*release_pes_feed) (struct dmx_demux_s* demux, + dmx_pes_feed_t* feed); + int (*allocate_section_feed) (struct dmx_demux_s* demux, + dmx_section_feed_t** feed, + dmx_section_cb callback); + int (*release_section_feed) (struct dmx_demux_s* demux, + dmx_section_feed_t* feed); + int (*descramble_mac_address) (struct dmx_demux_s* demux, + __u8* buffer1, + size_t buffer1_length, + __u8* buffer2, + size_t buffer2_length, + __u16 pid); + int (*descramble_section_payload) (struct dmx_demux_s* demux, + __u8* buffer1, + size_t buffer1_length, + __u8* buffer2, size_t buffer2_length, + __u16 pid); + int (*add_frontend) (struct dmx_demux_s* demux, + dmx_frontend_t* frontend); + int (*remove_frontend) (struct dmx_demux_s* demux, + dmx_frontend_t* frontend); + struct list_head* (*get_frontends) (struct dmx_demux_s* demux); + int (*connect_frontend) (struct dmx_demux_s* demux, + dmx_frontend_t* frontend); + int (*disconnect_frontend) (struct dmx_demux_s* demux); + + + /* added because js cannot keep track of these himself */ + int (*get_pes_pids) (struct dmx_demux_s* demux, __u16 *pids); +}; +typedef struct dmx_demux_s dmx_demux_t; + +/*--------------------------------------------------------------------------*/ +/* Demux directory */ +/*--------------------------------------------------------------------------*/ + +/* + * DMX_DIR_ENTRY(): Casts elements in the list of registered + * demuxes from the generic type struct list_head* to the type dmx_demux_t + *. + */ + +#define DMX_DIR_ENTRY(list) list_entry(list, dmx_demux_t, reg_list) + +int dmx_register_demux (dmx_demux_t* demux); +int dmx_unregister_demux (dmx_demux_t* demux); +struct list_head* dmx_get_demuxes (void); + +#endif /* #ifndef __DEMUX_H */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ost/dmx.h linux.20pre2-ac1/drivers/media/video/margi/ost/dmx.h --- linux.20pre2/drivers/media/video/margi/ost/dmx.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ost/dmx.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,147 @@ +/* + * dmx.h + * + * Copyright (C) 2000 Marcus Metzler + * & Ralph Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _OST_DMX_H_ +#define _OST_DMX_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#ifndef EBUFFEROVERFLOW +#define EBUFFEROVERFLOW 769 +#endif + +typedef uint16_t dvb_pid_t; + +#define DMX_FILTER_SIZE 16 + +typedef enum +{ + DMX_OUT_DECODER, /* Streaming directly to decoder. */ + DMX_OUT_TAP, /* Output going to a memory buffer */ + /* (to be retrieved via the read command).*/ + DMX_OUT_TS_TAP /* Output multiplexed into a new TS */ + /* (to be retrieved by reading from the */ + /* logical DVR device). */ +} dmxOutput_t; + + +typedef enum +{ + DMX_IN_FRONTEND, /* Input from a front-end device. */ + DMX_IN_DVR /* Input from the logical DVR device. */ +} dmxInput_t; + + +typedef enum +{ + DMX_PES_AUDIO, + DMX_PES_VIDEO, + DMX_PES_TELETEXT, + DMX_PES_SUBTITLE, + DMX_PES_PCR, + DMX_PES_OTHER +} dmxPesType_t; + + +typedef enum +{ + DMX_SCRAMBLING_EV, + DMX_FRONTEND_EV +} dmxEvent_t; + + +typedef enum +{ + DMX_SCRAMBLING_OFF, + DMX_SCRAMBLING_ON +} dmxScramblingStatus_t; + + +typedef struct dmxFilter +{ + uint8_t filter[DMX_FILTER_SIZE]; + uint8_t mask[DMX_FILTER_SIZE]; +} dmxFilter_t; + + +struct dmxFrontEnd +{ + +}; + + +struct dmxSctFilterParams +{ + dvb_pid_t pid; + dmxFilter_t filter; + uint32_t timeout; + uint32_t flags; +#define DMX_CHECK_CRC 1 +#define DMX_ONESHOT 2 +#define DMX_IMMEDIATE_START 4 +#define DMX_KERNEL_CLIENT 0x8000 +}; + + +struct dmxPesFilterParams +{ + dvb_pid_t pid; + dmxInput_t input; + dmxOutput_t output; + dmxPesType_t pesType; + uint32_t flags; +}; + + +struct dmxEvent +{ + dmxEvent_t event; + time_t timeStamp; + union + { + dmxScramblingStatus_t scrambling; + } u; +}; + + +typedef struct dmxCaps_s +{ + uint32_t caps; /* */ + int num_decoders; +} dmxCaps_t; + + +#define DMX_START _IOW('o',41,int) +#define DMX_STOP _IOW('o',42,int) +#define DMX_SET_FILTER _IOW('o',43,struct dmxSctFilterParams *) +#define DMX_SET_PES_FILTER _IOW('o',44,struct dmxPesFilterParams *) +#define DMX_SET_BUFFER_SIZE _IOW('o',45,unsigned long) +#define DMX_GET_EVENT _IOR('o',46,struct dmxEvent *) +#define DMX_GET_PES_PIDS _IOR('o',47,dvb_pid_t *) +#define DMX_GET_CAPS _IOR('o',48,dmxCaps_t *) + +#endif /*_OST_DMX_H_*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ost/frontend.h linux.20pre2-ac1/drivers/media/video/margi/ost/frontend.h --- linux.20pre2/drivers/media/video/margi/ost/frontend.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ost/frontend.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,208 @@ +/* + * frontend.h + * + * Copyright (C) 2000 Marcus Metzler + * & Ralph Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _FRONTEND_H_ +#define _FRONTEND_H_ + +#include + + +#define ENOSIGNAL 768 +#ifndef EBUFFEROVERFLOW +#define EBUFFEROVERFLOW 769 +#endif + + +typedef __u32 FrontendStatus; + +/* bit definitions for FrontendStatus */ +#define FE_HAS_POWER 1 +#define FE_HAS_SIGNAL 2 +#define FE_SPECTRUM_INV 4 +#define FE_HAS_LOCK 8 +#define FE_HAS_CARRIER 16 +#define FE_HAS_VITERBI 32 +#define FE_HAS_SYNC 64 +#define FE_TUNER_HAS_LOCK 128 + + +/* possible values for spectral inversion */ +typedef enum { + INVERSION_OFF, + INVERSION_ON, + INVERSION_AUTO +} SpectralInversion; + +/* possible values for FEC_inner/FEC_outer */ +typedef enum { + FEC_AUTO, + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_5_6, + FEC_7_8, + FEC_NONE +} CodeRate; + + +typedef enum { + QPSK, + QAM_16, + QAM_32, + QAM_64, + QAM_128, + QAM_256 +} Modulation; + + +typedef enum { + TRANSMISSION_MODE_2K, + TRANSMISSION_MODE_8K +} TransmitMode; + +typedef enum { + BANDWIDTH_8_MHZ, + BANDWIDTH_7_MHZ, + BANDWIDTH_6_MHZ +} BandWidth; + + +typedef enum { + GUARD_INTERVAL_1_32, + GUARD_INTERVAL_1_16, + GUARD_INTERVAL_1_8, + GUARD_INTERVAL_1_4 +} GuardInterval; + + +typedef enum { + HIERARCHY_NONE, + HIERARCHY_1, + HIERARCHY_2, + HIERARCHY_4 +} Hierarchy; + + +typedef struct { + __u32 SymbolRate; /* symbol rate in Symbols per second */ + CodeRate FEC_inner; /* forward error correction (see above) */ +} QPSKParameters; + + +typedef struct { + __u32 SymbolRate; /* symbol rate in Symbols per second */ + CodeRate FEC_inner; /* forward error correction (see above) */ + Modulation QAM; /* modulation type (see above) */ +} QAMParameters; + + +typedef struct { + BandWidth bandWidth; + CodeRate HP_CodeRate; /* high priority stream code rate */ + CodeRate LP_CodeRate; /* low priority stream code rate */ + Modulation Constellation; /* modulation type (see above) */ + TransmitMode TransmissionMode; + GuardInterval guardInterval; + Hierarchy HierarchyInformation; +} OFDMParameters; + + +typedef enum { + FE_QPSK, + FE_QAM, + FE_OFDM +} FrontendType; + + +typedef struct { + __u32 Frequency; /* (absolute) frequency in Hz for QAM/OFDM */ + /* intermediate frequency in kHz for QPSK */ + SpectralInversion Inversion; /* spectral inversion */ + union { + QPSKParameters qpsk; + QAMParameters qam; + OFDMParameters ofdm; + } u; +} FrontendParameters; + + +typedef enum { + FE_UNEXPECTED_EV, /* unexpected event (e.g. loss of lock) */ + FE_COMPLETION_EV, /* completion event, tuning succeeded */ + FE_FAILURE_EV /* failure event, we couldn't tune */ +} EventType; + + +typedef struct { + EventType type; /* type of event, FE_UNEXPECTED_EV, ... */ + + long timestamp; /* time in seconds since 1970-01-01 */ + + union { + struct { + FrontendStatus previousStatus; /* status before event */ + FrontendStatus currentStatus; /* status during event */ + } unexpectedEvent; + FrontendParameters completionEvent; /* parameters for which the + tuning succeeded */ + FrontendStatus failureEvent; /* status at failure (e.g. no lock) */ + } u; +} FrontendEvent; + +typedef struct { + FrontendType type; + __u32 minFrequency; + __u32 maxFrequency; + __u32 maxSymbolRate; + __u32 minSymbolRate; + __u32 hwType; + __u32 hwVersion; +} FrontendInfo; + + +typedef enum { + FE_POWER_ON, + FE_POWER_STANDBY, + FE_POWER_SUSPEND, + FE_POWER_OFF +} FrontendPowerState; + + +#define FE_SELFTEST _IO('o', 61) +#define FE_SET_POWER_STATE _IOW('o', 62, FrontendPowerState) +#define FE_GET_POWER_STATE _IOR('o', 63, FrontendPowerState*) +#define FE_READ_STATUS _IOR('o', 64, FrontendStatus*) +#define FE_READ_BER _IOW('o', 65, __u32*) +#define FE_READ_SIGNAL_STRENGTH _IOR('o', 66, __s32*) +#define FE_READ_SNR _IOR('o', 67, __s32*) +#define FE_READ_UNCORRECTED_BLOCKS _IOW('o', 68, __u32*) +#define FE_GET_NEXT_FREQUENCY _IOW('o', 69, __u32*) +#define FE_GET_NEXT_SYMBOL_RATE _IOW('o', 70, __u32*) + +#define FE_SET_FRONTEND _IOW('o', 71, FrontendParameters*) +#define FE_GET_FRONTEND _IOR('o', 72, FrontendParameters*) +#define FE_GET_INFO _IOR('o', 73, FrontendInfo*) +#define FE_GET_EVENT _IOR('o', 74, FrontendEvent*) + +#endif /*_FRONTEND_H_*/ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ost/net.h linux.20pre2-ac1/drivers/media/video/margi/ost/net.h --- linux.20pre2/drivers/media/video/margi/ost/net.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ost/net.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,40 @@ +/* + * net.h + * + * Copyright (C) 2000 Marcus Metzler + * & Ralph Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _OST_NET_H_ +#define _OST_NET_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +struct dvb_net_if { + uint16_t pid; + uint16_t if_num; +}; + +#define NET_ADD_IF _IOWR('o', 52, struct dvb_net_if *) +#define NET_REMOVE_IF _IOW('o', 53, uint16_t) +#endif /*_OST_VIDEO_H_*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ost/osd.h linux.20pre2-ac1/drivers/media/video/margi/ost/osd.h --- linux.20pre2/drivers/media/video/margi/ost/osd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ost/osd.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,111 @@ +/* + * osd.h + * + * Copyright (C) 2001 Ralph Metzler + * & Marcus Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Lesser Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _OST_OSD_H_ +#define _OST_OSD_H_ + +typedef enum { + // All functions return -2 on "not open" + OSD_Close=1, // () + // Disables OSD and releases the buffers + // returns 0 on success + OSD_Open, // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) + // Opens OSD with this size and bit depth + // returns 0 on success, -1 on DRAM allocation error, -2 on "already open" + OSD_Show, // () + // enables OSD mode + // returns 0 on success + OSD_Hide, // () + // disables OSD mode + // returns 0 on success + OSD_Clear, // () + // Sets all pixel to color 0 + // returns 0 on success + OSD_Fill, // (color) + // Sets all pixel to color + // returns 0 on success + OSD_SetColor, // (color,R{x0},G{y0},B{x1},opacity{y1}) + // set palette entry to , and apply + // R,G,B: 0..255 + // R=Red, G=Green, B=Blue + // opacity=0: pixel opacity 0% (only video pixel shows) + // opacity=1..254: pixel opacity as specified in header + // opacity=255: pixel opacity 100% (only OSD pixel shows) + // returns 0 on success, -1 on error + OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data) + // Set a number of entries in the palette + // sets the entries "firstcolor" through "lastcolor" from the array "data" + // data has 4 byte for each color: + // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel + OSD_SetTrans, // (transparency{color}) + // Sets transparency of mixed pixel (0..15) + // returns 0 on success + OSD_SetPixel, // (x0,y0,color) + // sets pixel , to color number + // returns 0 on success, -1 on error + OSD_GetPixel, // (x0,y0) + // returns color number of pixel ,, or -1 + OSD_SetRow, // (x0,y0,x1,data) + // fills pixels x0,y through x1,y with the content of data[] + // returns 0 on success, -1 on clipping all pixel (no pixel drawn) + OSD_SetBlock, // (x0,y0,x1,y1,increment{color},data) + // fills pixels x0,y0 through x1,y1 with the content of data[] + // inc contains the width of one line in the data block, + // inc<=0 uses blockwidth as linewidth + // returns 0 on success, -1 on clipping all pixel + OSD_FillRow, // (x0,y0,x1,color) + // fills pixels x0,y through x1,y with the color + // returns 0 on success, -1 on clipping all pixel + OSD_FillBlock, // (x0,y0,x1,y1,color) + // fills pixels x0,y0 through x1,y1 with the color + // returns 0 on success, -1 on clipping all pixel + OSD_Line, // (x0,y0,x1,y1,color) + // draw a line from x0,y0 to x1,y1 with the color + // returns 0 on success + OSD_Query, // (x0,y0,x1,y1,xasp{color}}), yasp=11 + // fills parameters with the picture dimensions and the pixel aspect ratio + // returns 0 on success + OSD_Test, // () + // draws a test picture. for debugging purposes only + // returns 0 on success +// TODO: remove "test" in final version + OSD_Text, // (x0,y0,size,color,text) + OSD_SetWindow, // (x0) set window with number 0 + * & Marcus Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _OST_SEC_H_ +#define _OST_SEC_H_ + +#define SEC_MAX_DISEQC_PARAMS 3 + +struct secDiseqcCmd { + uint8_t addr; + uint8_t cmd; + uint8_t numParams; + uint8_t params[SEC_MAX_DISEQC_PARAMS]; +}; + +typedef uint32_t secVoltage; + +enum { + SEC_VOLTAGE_OFF, + SEC_VOLTAGE_LT, + SEC_VOLTAGE_13, + SEC_VOLTAGE_13_5, + SEC_VOLTAGE_18, + SEC_VOLTAGE_18_5 +}; + +#define SEC_VOLTAGE_HORIZONTAL SEC_VOLTAGE_18 +#define SEC_VOLTAGE_VERTICAL SEC_VOLTAGE_13 + +typedef uint32_t secToneMode; + +typedef enum { + SEC_TONE_ON, + SEC_TONE_OFF +} secToneMode_t; + + +typedef uint32_t secMiniCmd; + +typedef enum { + SEC_MINI_NONE, + SEC_MINI_A, + SEC_MINI_B +} secMiniCmd_t; + +struct secStatus { + int32_t busMode; + secVoltage selVolt; + secToneMode contTone; +}; + +enum { + SEC_BUS_IDLE, + SEC_BUS_BUSY, + SEC_BUS_OFF, + SEC_BUS_OVERLOAD +}; + +struct secCommand { + int32_t type; + union { + struct secDiseqcCmd diseqc; + uint8_t vsec; + uint32_t pause; + } u; +}; + +struct secCmdSequence { + secVoltage voltage; + secMiniCmd miniCommand; + secToneMode continuousTone; + + uint32_t numCommands; + struct secCommand* commands; +}; + +enum { + SEC_CMDTYPE_DISEQC, + SEC_CMDTYPE_VSEC, + SEC_CMDTYPE_PAUSE +}; + + +#define SEC_GET_STATUS _IOR('o',91,struct secStatus *) +#define SEC_RESET_OVERLOAD _IOW('o',92,void) +#define SEC_SEND_SEQUENCE _IOW('o',93,struct secCmdSequence *) +#define SEC_SET_TONE _IOW('o',94,secToneMode) +#define SEC_SET_VOLTAGE _IOW('o',95,secVoltage) + +typedef enum { + SEC_DISEQC_SENT, + SEC_VSEC_SENT, + SEC_PAUSE_COMPLETE, + SEC_CALLBACK_ERROR +} secCallback_t; + + +#endif /*_OST_SEC_H_*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ost/video.h linux.20pre2-ac1/drivers/media/video/margi/ost/video.h --- linux.20pre2/drivers/media/video/margi/ost/video.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ost/video.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,186 @@ +/* + * video.h + * + * Copyright (C) 2000 Marcus Metzler + * & Ralph Metzler + for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser 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 _OST_VIDEO_H_ +#define _OST_VIDEO_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#define boolean int +#define true 1 +#define false 0 + +typedef enum { + VIDEO_FORMAT_4_3, /* Select 4:3 format */ + VIDEO_FORMAT_16_9 /* Select 16:9 format. */ +} videoFormat_t; + +typedef enum { + VIDEO_SYSTEM_PAL, + VIDEO_SYSTEM_NTSC, + VIDEO_SYSTEM_PALN, + VIDEO_SYSTEM_PALNc, + VIDEO_SYSTEM_PALM, + VIDEO_SYSTEM_NTSC60, + VIDEO_SYSTEM_PAL60, + VIDEO_SYSTEM_PALM60 +} videoSystem_t; + +typedef enum { + VIDEO_PAN_SCAN, /* use pan and scan format */ + VIDEO_LETTER_BOX, /* use letterbox format */ + VIDEO_CENTER_CUT_OUT /* use center cut out format */ +} videoDisplayFormat_t; + +typedef enum { + VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ + VIDEO_SOURCE_MEMORY /* If this source is selected, the stream + comes from the user through the write + system call */ +} videoStreamSource_t; + +typedef enum { + VIDEO_STOPPED, /* Video is stopped */ + VIDEO_PLAYING, /* Video is currently playing */ + VIDEO_FREEZED /* Video is freezed */ +} videoPlayState_t; + +struct videoEvent { + int32_t type; + time_t timestamp; + union { + videoFormat_t videoFormat; + } u; +}; + +struct videoStatus { + boolean videoBlank; /* blank video on freeze? */ + videoPlayState_t playState; /* current state of playback */ + videoStreamSource_t streamSource; /* current source (demux/memory) */ + videoFormat_t videoFormat; /* current aspect ratio of stream */ + videoDisplayFormat_t displayFormat; /* selected cropping mode */ +}; + +/* pointer to and size of a single iframe in memory */ +struct videoDisplayStillPicture { + char *iFrame; + int32_t size; +}; + + +typedef +struct videoHighlight { + boolean active; /* 1=show highlight, 0=hide highlight */ + uint8_t contrast1; /* 7- 4 Pattern pixel contrast */ + /* 3- 0 Background pixel contrast */ + uint8_t contrast2; /* 7- 4 Emphasis pixel-2 contrast */ + /* 3- 0 Emphasis pixel-1 contrast */ + uint8_t color1; /* 7- 4 Pattern pixel color */ + /* 3- 0 Background pixel color */ + uint8_t color2; /* 7- 4 Emphasis pixel-2 color */ + /* 3- 0 Emphasis pixel-1 color */ + uint32_t ypos; /* 23-22 auto action mode */ + /* 21-12 start y */ + /* 9- 0 end y */ + uint32_t xpos; /* 23-22 button color number */ + /* 21-12 start x */ + /* 9- 0 end x */ +} videoHighlight_t; + + +typedef +struct videoSPU { + boolean active; + int streamID; +} videoSPU_t; + +typedef +struct videoSPUPalette{ /* SPU Palette information */ + int length; + uint8_t *palette; +} videoSPUPalette_t; + +typedef +struct videoNaviPack{ + int length; /* 0 ... 1024 */ + uint8_t data[1024]; +} videoNaviPack_t; + + +typedef uint16_t videoAttributes_t; +/* bits: descr. */ +/* 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */ +/* 13-12 TV system (0=525/60, 1=625/50) */ +/* 11-10 Aspect ratio (0=4:3, 3=16:9) */ +/* 9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca */ +/* 7 line 21-1 data present in GOP (1=yes, 0=no) */ +/* 6 line 21-2 data present in GOP (1=yes, 0=no) */ +/* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */ +/* 2 source letterboxed (1=yes, 0=no) */ +/* 0 film/camera mode (0=camera, 1=film (625/50 only)) */ + + +/* bit definitions for capabilities: */ +/* can the hardware decode MPEG1 and/or MPEG2? */ +#define VIDEO_CAP_MPEG1 1 +#define VIDEO_CAP_MPEG2 2 +/* can you send a system and/or program stream to video device? + (you still have to open the video and the audio device but only + send the stream to the video device) */ +#define VIDEO_CAP_SYS 4 +#define VIDEO_CAP_PROG 8 +/* can the driver also handle SPU, NAVI and CSS encoded data? + (CSS API is not present yet) */ +#define VIDEO_CAP_SPU 16 +#define VIDEO_CAP_NAVI 32 +#define VIDEO_CAP_CSS 64 + + +#define VIDEO_STOP _IOW('o', 21, boolean) +#define VIDEO_PLAY _IO('o', 22) +#define VIDEO_FREEZE _IO('o', 23) +#define VIDEO_CONTINUE _IO('o', 24) +#define VIDEO_SELECT_SOURCE _IOW('o', 25, videoStreamSource_t) +#define VIDEO_SET_BLANK _IOW('o', 26, boolean) +#define VIDEO_GET_STATUS _IOR('o', 27, struct videoStatus *) +#define VIDEO_GET_EVENT _IOR('o', 28, struct videoEvent *) +#define VIDEO_SET_DISPLAY_FORMAT _IOW('o', 29, videoDisplayFormat_t) +#define VIDEO_STILLPICTURE _IOW('o', 30, struct videoDisplayStillPicture *) +#define VIDEO_FAST_FORWARD _IOW('o', 31, int) +#define VIDEO_SLOWMOTION _IOW('o', 32, int) +#define VIDEO_GET_CAPABILITIES _IOR('o', 33, unsigned int *) +#define VIDEO_CLEAR_BUFFER _IO('o', 34) +#define VIDEO_SET_ID _IOW('o', 35, unsigned char) +#define VIDEO_SET_STREAMTYPE _IOW('o', 36, int) +#define VIDEO_SET_FORMAT _IOW('o', 37, videoFormat_t) +#define VIDEO_SET_SYSTEM _IOW('o', 38, videoSystem_t) +#define VIDEO_SET_HIGHLIGHT _IOW('o', 39, videoHighlight_t *) +#define VIDEO_SET_SPU _IOW('o', 50, videoSPU_t *) +#define VIDEO_SET_SPU_PALETTE _IOW('o', 51, videoSPUPalette_t *) +#define VIDEO_GET_NAVI _IOR('o', 52, videoNaviPack_t *) +#define VIDEO_SET_ATTRIBUTES _IOW('o', 53, videoAttributes_t) +#endif /*_OST_VIDEO_H_*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/README linux.20pre2-ac1/drivers/media/video/margi/README --- linux.20pre2/drivers/media/video/margi/README 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/README 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,97 @@ +This is the driver for the Margi/Billionton MPEG decoder PC-Card. +It is still in a beta state and may cause problems with your system. + +INSTALLING +---------- +0) From now on you will need a 2.4.x kernel to make everything work + +1) Install David Hinds` PCMCIA Card Services package. The current + version is at http://pcmcia.sourceforge.org/. + This driver is known to work under versions 3.1.25 and later. Earlier + version may work too. + + % tar zxvf pcmcia-cs-3.1.25.tar.gz + +2) Enter the pcmcia directory and unpack the margi driver. + + % cd pcmcia-cs-3.1.25 + % tar zxvf margi_cs-0.5.tar.gz + +3) In the pcmcia main directory: + + % make config + % make all + # make install + + +The files for the margi are in margi2. (The name has historical reasons.) + +ATTENTION You now need video4linux support in the kernel. +You can now use /dev/video for playback. + + +Using the driver +---------------- +The driver registers a character device with major number 162. You can +cat an MPEG2 program stream into that device. +If the device doesn`t exist (usually it`s /dev/raw) just + % mknod -m 0666 /dev/margi char 200 0 +Than you + % cat nicempg2.vob > /dev/margi +or + % cat nicempg.mpg > /dev/margi + +At the moment we do not recognize the audio format of the MPEG1/2, so +MPEG audio is hard-coded as default. You can change that in cvdv.c in the +Prepare() routine, or by using the ioctl Decoder_Set_Audiotype, e.g.: + +#include "cvdvext.h" + +main() +{ + struct decodercmd decmd; + + decmd.param1=audio_AC3; + decmd.cmd=Decoder_Set_Audiotype; + DecoderCommand(device,decmd); +... + +} + +In the directory testsuite are some example programs for using the driver. +I hope they are more or less self explanatory. Just use the --help option. + + +If you want the latest drivers apart from the release versions, use +the public CVS at linuxtv.org : http://linuxtv.org/cgi-bin/cvsweb.cgi/ + + +ZV-support +---------- + +You will faind patches for ZV support in the zv-diffs directory. The +ones with the version number for pcmcia-cs ar for the respective +versions of this package. The rest is for graphics chips or sound +chips, like the patches for the Neomagic graphics chip and YMF sound +chip submitted by Shigehiro Nomura. + +There now three module parameters that are all set to 1 (=on) but can +be set to off in /etc/pcmcia/config.opts +They are : "svhs" for switching the svhs output DAC on or off (0 or 1). + "composite" for switching the composite output DAC on or off. + "use_zv" for enabling zv output if you compiled with the + -DUSE_ZV setting in margi_cs.mk. + +E.g. +module "margi_cs" opts "use_zv=0" +turns off zv output. +or +module "margi_cs" opts "composite=0 svhs=0" +turns off the external outputs. + +WHO DO I BLAME/FLAME? +=== == = ============ + +Send comments, patches, free pizza to . + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/README.CVS linux.20pre2-ac1/drivers/media/video/margi/README.CVS --- linux.20pre2/drivers/media/video/margi/README.CVS 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/README.CVS 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,13 @@ +1) unpack pcmcia_cs distribution + % tar zxvf pcmcia-cs-3.1.14.tar.gz + +2) cd pcmcia-cs-3.1.14 + % cvs co margi2 + +3) cp margi2/margi_cs.mk.MAIN margi_cs.mk + +4) For ZV support in pcmcia-cs use zv.diff. Remember, this is just the + first step to get to watching the output on your notebook's screen. + If you have pcmcia-cs versio >= 3.1.25 you need to use zv.diff.3.1.25. + The patches currently only work for the Rigoch 5c478 controller. + Anybody with information about ZV regarding graphic chips, please tell me. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ringbuffy.c linux.20pre2-ac1/drivers/media/video/margi/ringbuffy.c --- linux.20pre2/drivers/media/video/margi/ringbuffy.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ringbuffy.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,212 @@ +/* + ringbuffy.c + + Copyright (C) Marcus Metzler for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define __NO_VERSION__ + +#include "margi.h" +#include "ringbuffy.h" + +#ifndef outsl_ns +#define outsl_ns outsl +#endif + +int ring_init (ringbuffy *rbuf, long size) +{ + rbuf->size = 0; + rbuf->read_pos = 0; + rbuf->write_pos = 0; + + if (size > 0){ + if( !(rbuf->buffy = (char *) vmalloc(sizeof(char)*size)) ){ + MDEBUG(0, + "Not enough memory for ringbuffy\n"); + return -1; + } + } else { + MDEBUG(0, "Wrong size for ringbuffy\n"); + return -1; + } + + rbuf->size = size; + return 0; +} + + +void ring_destroy(ringbuffy *rbuf) +{ + if (rbuf->size){ + vfree(rbuf->buffy); + rbuf->buffy = NULL; + } + rbuf->size = 0; + rbuf->read_pos = 0; + rbuf->write_pos = 0; +} + + +int ring_write(ringbuffy *rbuf, const char *data, int count) +{ + + long diff, free, pos, rest; + + + if (count <=0 || !rbuf->buffy) return 0; + pos = rbuf->write_pos; + rest = rbuf->size - pos; + diff = rbuf->read_pos - pos; + free = (diff > 0) ? diff-4 : rbuf->size+diff-4; + + if ( free <= 0 ) return 0; + if ( free < count ) count = free; + + if (count >= rest){ + if(copy_from_user (rbuf->buffy+pos, data, rest)) + return -EFAULT; + if (count - rest) + if(copy_from_user(rbuf->buffy, data+rest, + count - rest)) + return -EFAULT; + rbuf->write_pos = count - rest; + } else { + copy_from_user (rbuf->buffy+pos, data, count); + rbuf->write_pos += count; + } + + return count; +} + + +int ring_writek(ringbuffy *rbuf, const char *data, int count) +{ + + long diff, free, pos, rest; + + + if (count <=0 || !rbuf->buffy) return 0; + pos = rbuf->write_pos; + rest = rbuf->size - pos; + diff = rbuf->read_pos - pos; + free = (diff > 0) ? diff-4 : rbuf->size+diff-4; + + if ( free <= 0 ) return 0; + if ( free < count ) count = free; + + if (count >= rest){ + if(memcpy(rbuf->buffy+pos, data, rest)) + return -EFAULT; + if (count - rest) + if(memcpy(rbuf->buffy, data+rest, + count - rest)) + return -EFAULT; + rbuf->write_pos = count - rest; + } else { + memcpy(rbuf->buffy+pos, data, count); + rbuf->write_pos += count; + } + + return count; +} + + + + +int ring_read(ringbuffy *rbuf, char *data, int count) +{ + + long diff, free, pos, rest; + + + if (count <=0 || !rbuf->buffy) return 0; + pos = rbuf->read_pos; + rest = rbuf->size - pos; + diff = rbuf->write_pos - pos; + free = (diff >= 0) ? diff : rbuf->size+diff; + + if ( free <= 0 ) return 0; + if ( free < count ) count = free; + + if ( count >= rest ){ + memcpy(data,rbuf->buffy+pos,rest); + if ( count - rest) + memcpy(data+rest,rbuf->buffy,count-rest); + rbuf->read_pos = count - rest; + } else { + memcpy(data,rbuf->buffy+pos,count); + rbuf->read_pos += count; + } + + return count; +} + +int ring_read_direct(ringbuffy *rbuf, int addr, int count) +{ + + long diff, free, pos, rest; + + + if (count <=0 || !rbuf->buffy) return 0; + pos = rbuf->read_pos; + rest = rbuf->size - pos; + diff = rbuf->write_pos - pos; + free = (diff >= 0) ? diff : rbuf->size+diff; + + if ( free <= 0 ) return 0; + if ( free < count ) count = free; + + if ( count >= rest ){ + outsl_ns(addr,rbuf->buffy+pos,rest/4); + if ( count - rest) + outsl_ns(addr,rbuf->buffy,(count-rest)/4); + rbuf->read_pos = count - rest; + } else { + outsl_ns(addr,rbuf->buffy+pos,count/4); + rbuf->read_pos += count; + } + + return count; +} + + +long ring_read_rest(ringbuffy *rbuf){ + long diff, free, pos; + + if (!rbuf->buffy) return 0; + pos = rbuf->read_pos; + diff = rbuf->write_pos - pos; + free = (diff >= 0) ? diff : rbuf->size+diff; + + return free; +} + +long ring_write_rest(ringbuffy *rbuf){ + long diff, free, pos; + + if (!rbuf->buffy) return 0; + pos = rbuf->write_pos; + diff = rbuf->read_pos - pos; + free = (diff > 0) ? diff-4 : rbuf->size+diff-4; + + return free; +} + +void ring_flush(ringbuffy *rbuf){ + rbuf->read_pos = 0; + rbuf->write_pos = 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/ringbuffy.h linux.20pre2-ac1/drivers/media/video/margi/ringbuffy.h --- linux.20pre2/drivers/media/video/margi/ringbuffy.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/ringbuffy.h 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,43 @@ +/* + cvdv.h + + Copyright (C) Marcus Metzler for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef RINGBUFFY_H +#define RINGBUFFY_H + + +#define FULL_BUFFER -1000 +typedef struct ringbuffy{ + long read_pos; + long write_pos; + long size; + char *buffy; +} ringbuffy; + +int ring_init (ringbuffy *rbuf, long size); +void ring_destroy(ringbuffy *rbuf); +int ring_write(ringbuffy *rbuf, const char *data, int count); +int ring_writek(ringbuffy *rbuf, const char *data, int count); +int ring_read(ringbuffy *rbuf, char *data, int count); +long ring_read_rest(ringbuffy *rbuf); +long ring_write_rest(ringbuffy *rbuf); +void ring_flush(ringbuffy *rbuf); +int ring_read_direct(ringbuffy *rbuf, int addr, int count); + +#endif /* RINGBUFFY_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/spu.c linux.20pre2-ac1/drivers/media/video/margi/spu.c --- linux.20pre2/drivers/media/video/margi/spu.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/spu.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,103 @@ +/* + spu.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define __NO_VERSION__ + +#include "spu.h" +#include "l64021.h" + +int DecoderHighlight(struct cvdv_cards *card, int active, u8 * coli, + u8 * btn_posi) +{ + int i; + if ((coli == NULL) || (btn_posi == NULL)) + return 1; + MDEBUG(0,": -- DecoderHighlight: col 0x%02X%02X, contr 0x%02X%02X, act %d, %d,%d - %d,%d\n", + coli[0], coli[1], coli[2], coli[3], active, + (((int) btn_posi[0] & 0x3F) << 4) | (btn_posi[1] >> 4), + (((int) btn_posi[3] & 0x3F) << 4) | (btn_posi[4] >> 4), + (((int) btn_posi[1] & 0x03) << 8) | btn_posi[2], + (((int) btn_posi[4] & 0x03) << 8) | btn_posi[5]); + //for (i=0; i<4; i++) DecoderWriteByte(card,0x1C0+i,coli[i]); +// DecoderWriteByte(card,0x1C0,coli[1]); +// DecoderWriteByte(card,0x1C1,coli[0]); +// DecoderWriteByte(card,0x1C2,coli[3]); +// DecoderWriteByte(card,0x1C3,coli[2]); + //for (i=0; i<6; i++) DecoderWriteByte(card,0x1C4+i,btn_posi[i]); +// for (i=0; i<6; i++) DecoderWriteByte(card,0x1C4+i,btn_posi[5-i]); + //if (active) DecoderSetByte(card,0x1BF,0x01); + //else DecoderDelByte(card,0x1BF,0x01); + + //for (i=0; i<4; i++) card->highlight[i]=coli[3-i]; + card->highlight[0] = coli[1]; + card->highlight[1] = coli[0]; + card->highlight[2] = coli[3]; + card->highlight[3] = coli[2]; + for (i = 0; i < 6; i++) + card->highlight[4 + i] = btn_posi[5 - i]; + card->highlight_valid = 1; + if (active) + DecoderWriteByte(card, 0x1BF, 0x01); + else + DecoderWriteByte(card, 0x1BF, 0x00); +//DecoderSetByte(card,0x135,0x02); // Enable SPU Mix +//DecoderWriteByte(card,0x1A0,0x01); // decode start, display on + return 0; +} + +int DecoderSPUPalette(struct cvdv_cards *card, int length, u8 * palette) +{ + int i; + MDEBUG(1,": -- DecoderSPUPalette: setting up %d bytes of SPU palette(Y,Cr,Cb):", length); + for (i = 0; i < (length / 3); i++) + MDEBUG(1," %d=(%d,%d,%d)", i, palette[i * 3],palette[i * 3 + 1], + palette[i * 3 + 2]); + MDEBUG(1,"\n"); + DecoderDelByte(card, 0x1A0, 0x01); // SPU decode stop + DecoderSetByte(card, 0x1A0, 0x10); + for (i = 0; i < length; i++) + DecoderWriteByte(card, 0x1BE, palette[i]); + DecoderSetByte(card, 0x1A0, 0x01); // SPU decode start + return 0; +} + +int DecoderSPUStream(struct cvdv_cards *card, int stream, int active) +{ + MDEBUG(1,": -- DecoderSPUStream: stream %d, active %d\n", stream, + active); + if (stream < 32) { + card->reg092 |= (0x20 | (stream & 0x1F)); // stream ID and select + DecoderWriteByte(card, 0x092, card->reg092); + DecoderMaskByte(card, 0x112, 0x20, 0x20); // chroma filter enable + DecoderMaskByte(card, 0x1A1, 0x0F, 0x00); // SPU timeout + DecoderWriteByte(card, 0x1BF, 0x00); // HighLight off + DecoderSetByte(card, 0x135, 0x02); // Enable SPU Mix + if (active) + DecoderWriteByte(card, 0x1A0, 0x01); // decode start, display on + else + DecoderWriteByte(card, 0x1A0, 0x05); // decode start, display off + } else { + DecoderWriteByte(card, 0x1A0, 0x04); // decode stop, display off + card->reg092 &= (~0x20); // stream select off + DecoderWriteByte(card, 0x092, card->reg092); + DecoderDelByte(card, 0x135, 0x02); // Disable SPU Mix + } + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/spu.h linux.20pre2-ac1/drivers/media/video/margi/spu.h --- linux.20pre2/drivers/media/video/margi/spu.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/spu.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,33 @@ +/* + spu.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CVDV_SPU_H +#define CVDV_SPU_H + +#include "cardbase.h" + +int DecoderHighlight(struct cvdv_cards *card, int active, u8 * coli, + u8 * btn_posi); + +int DecoderSPUPalette(struct cvdv_cards *card, int length, u8 * palette); + +int DecoderSPUStream(struct cvdv_cards *card, int stream, int active); + +#endif /* CVDV_SPU_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/streams.c linux.20pre2-ac1/drivers/media/video/margi/streams.c --- linux.20pre2/drivers/media/video/margi/streams.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/streams.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,444 @@ +/* + streams.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define __NO_VERSION__ + +#include "streams.h" +#include "dram.h" +#include "l64021.h" +#include "video.h" +#include "audio.h" + +// Frees allocated channel buffers +int DecoderKillChannelBuffers(struct cvdv_cards *card) +{ + MDEBUG(1, ": -- DecoderKillChannelBuffers\n"); + DecoderStopDecode(card); + DRAMFree(card, card->VideoES); + card->VideoES = BLANK; + DRAMFree(card, card->AudioES); + card->AudioES = BLANK; + DRAMFree(card, card->VideoPES); + card->VideoPES = BLANK; + DRAMFree(card, card->DataDump); + card->DataDump = BLANK; + DRAMFree(card, card->AudioPES); + card->AudioPES = BLANK; + DRAMFree(card, card->NaviBank); + card->NaviBank = BLANK; + card->ChannelBuffersAllocated = 0; +// DecoderWriteWord( + return 0; +} + +// Allocates channel buffers +// All sizes in bytes, preferably multiple of 256 (will be rounded up otherwise) +int DecoderSetChannelBuffers(struct cvdv_cards *card, int VideoES, // Video ES Channel Buffer size, e.g. 229376 byte for NTSC + int AudioES, // Audio ES Channel Buffer size, 4096 byte + int VideoPES, // Video PES Header / SPU Channel Buffer size, 512 byte + int DataDump, // Data Dump Channel Buffer size, e.g. 80896 byte + int AudioPES, // Audio PES Header / System Channel Buffer size, 512 byte + int NaviBank) +{ // Navi Bank Channel Buffer size, 2048 byte +#define BUFFERSET(buf, id, adr,align) if (buf>0) {\ + if (buf&((1<buf=addr;\ + addr>>=align;\ + DecoderWriteByte(card,adr,addr&0xFF);\ + DecoderWriteByte(card,adr+1,(addr>>8)&(0x003F));\ + addr+=(buf>>align);\ + DecoderWriteByte(card,adr+2,(addr-1)&0xFF);\ + DecoderWriteByte(card,adr+3,((addr-1)>>8)&0x003F);\ +} + u32 addr; + MDEBUG(1, ": -- DecoderSetChannelBuffers\n"); + //DecoderStopDecode(card); + DecoderStopChannel(card); + VideoES >>= 1; // change to word sizes + AudioES >>= 1; + VideoPES >>= 1; + DataDump >>= 1; + AudioPES >>= 1; + NaviBank >>= 1; + if (card->ChannelBuffersAllocated) + DecoderKillChannelBuffers(card); + BUFFERSET(VideoES, "VideoES", 0x048, 7); + BUFFERSET(AudioES, "AudioES", 0x04C, 7); + BUFFERSET(VideoPES, "VideoPES", 0x050, 7); + BUFFERSET(DataDump, "DataDump", 0x054, 7); + BUFFERSET(AudioPES, "AudioPES", 0x058, 7); + BUFFERSET(NaviBank, "NaviBank", 0x05C, 7); + + card->VideoESSize = VideoES; + card->AudioESSize = AudioES; + card->VideoPESSize = VideoPES; + card->DataDumpSize = DataDump; + card->AudioPESSize = AudioPES; + card->NaviBankSize = NaviBank; + + DecoderWriteByte(card, 0x044, 0x7F); + DecoderWriteByte(card, 0x044, 0x01); + if (NaviBank) { + card->reg07B |= 0x10; // navi pack counter enable + DecoderWriteByte(card, 0x07B, card->reg07B); + //DecoderSetByte(card,0x07B,0x10); // navi pack counter enable + card->NaviPackAddress = + (DecoderReadWord(card, 0x05C) & 0x3FFF) << 7; + MDEBUG(4, ": navi bank init'ed: 0x%08X\n",card->NaviPackAddress); + } else { + card->reg07B &= ~0x10; // navi pack counter disable + DecoderWriteByte(card, 0x07B, card->reg07B); + //DecoderDelByte(card,0x07B,0x10); // navi pack counter disable + card->NaviPackAddress = 0; + } + card->ChannelBuffersAllocated = 1; +#undef BUFFERSET + return 0; +} + +//int DecoderReadFifo + +int DecoderUnPrepare(struct cvdv_cards *card) +{ + MDEBUG(0, ": -- DecoderUnPrepare\n"); + //DecoderStopDecode(card); + DecoderStopChannel(card); + DecoderKillChannelBuffers(card); + return 0; +} + +void DecoderPrepare(struct cvdv_cards *card) +{ + //VideoSetBackground(card,0,0,0,0); // Video on black + VideoSetBackground(card, 1, 0, 0, 0); // black + //VideoSetBackground(card,2,83,90,249); // Red + //VideoSetBackground(card,2,155,53,53); // Green + //VideoSetBackground(card,2,35,212,114); // Blue + //VideoSetBackground(card,2,4,128,128); // Black + //VideoSetBackground(card,3,155,53,53); // Video on Green + + //DecoderWriteByte(card,0x044,0x00); // Reset channel buffers on error +// DecoderWriteByte(card,0x044,0x01); // don't Reset channel buffers on error + + DecoderWriteByte(card, 0x040, 0x01); // Reset Aux FIFO + DecoderWriteByte(card, 0x041, 0x01); // Reset Data FIFO + //DecoderWriteByte(card,0x044,0x7E); // Reset channel buffers, Reset channel buffers on error + DecoderWriteByte(card, 0x044, 0x7F); // Reset channel buffers, don't Reset channel buffers on error +// udelay(100); +// DecoderWriteByte(card,0x040,0x00); // Reset Aux FIFO +// DecoderWriteByte(card,0x041,0x00); // Reset Data FIFO +// DecoderDelByte(card,0x044,0x7E); // Reset channel buffers +} + +// Selects audio type MPEG and sets stream ID's +// AID: -1=all MPEG, Audio Stream ID: 0..31 +// AExt: -1=unused, Audio Stream Extension ID: 0..31, only used if AType=5 +void DecoderSelectAudioID(struct cvdv_cards *card) +{ + int AID = card->setup.audioID; + int AExt = card->setup.audioIDext; + MDEBUG(1, ": -- SelectAudio %d %d\n", AID, AExt); + DecoderWriteByte(card, 0x07C, AExt & 0x1F); // Audio Stream Extension ID + card->reg08F = (card->reg08F & ~0x1F) | (AID & 0x1F); + DecoderWriteByte(card, 0x08F, card->reg08F); + //DecoderMaskByte(card,0x08F,0x1F,AID&0x1F); // Set Stream ID +} + +// AHeader: 0=No Headers, 1=first PTS/DTS header, 2=all headers, 3=All with PTS/DTS +// AType: 0=disable audio, 1=MPEG ID (MPEG 1), 2=Lin.PCM ID, 3=AC3 ID, 4=all MPEG (use only, if just one MPEG audio stream), 5=MPEG multichannel ID (MPEG 2) +// AID: -1=all MPEG, Audio Stream ID: 0..31 +// AExt: -1=unused, Audio Stream Extension ID: 0..31, only used if AType=5 +// IEC956: 0:MPEG/AC3 data on digital out 1:IEC956 data on digital S/PDIF out +void DecoderPrepareAudio(struct cvdv_cards *card) +{ + int AHeader = 2; + int AType = 3; + int AID = card->setup.audioID; + int AExt = card->setup.audioIDext; + int IEC956 = card->setup.SPDIFmode; + MDEBUG(1, ": -- PrepAudio %d %d %d %d %d\n", + AHeader, card->setup.audioselect, AID, AExt, IEC956); + switch (card->setup.audioselect) { + case audio_disable: + case audio_none: + case audio_SDDS: + AType = 0; + break; + case audio_MPEG: // MPEG Audio + AType = 1; + break; + case audio_MPEG_EXT: // MPEG Audio with extension stream + AType = 5; + break; + case audio_LPCM: // Linear Pulse Code Modulation LPCM + AType = 2; + break; + case audio_AC3: // AC-3 + AType = 3; + break; + case audio_DTS: // DTS + AType = 8; + break; + } + if (AType <= 0) { + card->reg08F = 0x00; // disable audio and discard all packets + DecoderWriteByte(card, 0x08F, card->reg08F); + //DecoderWriteByte(card,0x08F,0x00); // disable audio and discard all packets + //DecoderMaskByte(card,0x093,0xC3,0xC0); // write no headers + card->reg093 = (card->reg093 & ~0x03); // write no headers + DecoderWriteByte(card, 0x093, card->reg093); + } else { + AudioOpen(card); + DecoderMaskByte(card, 0x165, 0x1F, 0x00); // reset the register + if (AType == 8) { // DTS + card->reg090 |= 0x01; // DTS in Transport Private 1 Stream stored in AudioES channel buffer + DecoderWriteByte(card, 0x090, card->reg090); + //DecoderSetByte(card,0x090,0x01); // DTS in Transport Private 1 Stream stored in AudioES channel buffer + AudioSetMode(card, 0); + DecoderSetByte(card, 0x165, 0x01); + AudioStartFormat(card); + } else if (AType == 3) { // AC3 + card->reg090 |= 0x01; // AC3 in Transport Private 1 Stream stored in AudioES channel buffer + DecoderWriteByte(card, 0x090, card->reg090); + //DecoderSetByte(card,0x090,0x01); // AC3 in Transport Private 1 Stream stored in AudioES channel buffer + AudioSetMode(card, ((IEC956) ? 1 : 3)); + } else if (AType == 2) { // PCM + card->reg090 |= 0x01; // PCM in Transport Private 1 Stream stored in AudioES channel buffer + DecoderWriteByte(card, 0x090, card->reg090); + //DecoderSetByte(card,0x090,0x01); // PCM in Transport Private 1 Stream stored in AudioES channel buffer + AudioSetMode(card, 4); + } else { // MPEG + card->reg090 &= ~0x01; // MPEG Audio stored in AudioES channel buffer + DecoderWriteByte(card, 0x090, card->reg090); + //DecoderDelByte(card,0x090,0x01); // MPEG Audio stored in AudioES channel buffer + if (AID < 0) + AType = 4; + if (AExt >= 0) + AType = 5; + else + AExt = -1; + AudioSetMode(card, ((IEC956) ? 0 : 2)); + } + card->setup.audioID = AID; + card->setup.audioIDext = AExt; + DecoderSelectAudioID(card); + card->reg08F = (card->reg08F & ~0xE0) | ((AType & 0x07) << 5); // Set Stream Type + DecoderWriteByte(card, 0x08F, card->reg08F); + //DecoderMaskByte(card,0x08F,0xE0,(AType&0x07)<<5); // Set Stream Type + AudioSetVolume(card, 0xFF); // Set PCM scale to full volume + //DecoderMaskByte(card,0x093,0xC3,(AHeader&0x03)|0xC0); // write header select + card->reg093 = (card->reg093 & ~0x03) | (AHeader & 0x03); // write header select + DecoderWriteByte(card, 0x093, card->reg093); + // Mute the card and put it in play mode, then wait for the parameters to be parsed and un-mute if successful + //AudioMute(card,1); + if (AType > 0) { + AudioStartDecode(card); + //AudioSetPlayMode(card,MAUDIO_PLAY); + AudioSetPlayMode(card, MAUDIO_PAUSE); + } + //card->startingA=1; + } + card->lastaattr = 0; +} + +// VHeader: -1=disable Video, 0=No Headers, 1=first PTS/DTS header, 2=all headers, 3=All with PTS/DTS +// VID: -1=all MPEG, 0..15=Video Stream ID +void DecoderPrepareVideo(struct cvdv_cards *card) +{ + int VHeader = 3; + int VID = card->setup.videoID; + if (VHeader < 0) { + card->reg091 = 0x00; + DecoderWriteByte(card, 0x091, card->reg091); + //DecoderWriteByte(card,0x091,0x00); + } else { + if (VID < 0) { + card->reg091 = ((VHeader & 0x03) << 6) | (2 << 4); + DecoderWriteByte(card, 0x091, card->reg091); + //DecoderWriteByte(card,0x091,((VHeader&0x03)<<6)|(2<<4)); + } else { + card->reg091 = + ((VHeader & 0x03) << 6) | (1 << 4) | (VID & + 0x0F); + DecoderWriteByte(card, 0x091, card->reg091); + //DecoderWriteByte(card,0x091,((VHeader&0x03)<<6)|(1<<4)|(VID&0x0F)); + } + } +} + +// Prepare Decoder for Elementary Streams, Disable Preparser +int DecoderPrepareES(struct cvdv_cards *card) +{ + int i; + MDEBUG(1, ": -- PrepareES\n"); + //DecoderStopDecode(card); + +// DecoderWriteByte(card,0x05,0x00); + + DecoderMaskByte(card, 0x007, 0xCE, 0xC2 | (3 << 2)); // Stream Select: A/V Elementary Stream + MDEBUG(3, ": Int - A VideoES w/r addr: %08X %08X\n", + (DecoderReadByte(card,0x060)|(DecoderReadByte(card,0x061)<<8)| + (DecoderReadByte(card,0x062)<<16))<<2, + (DecoderReadByte(card,0x06C)|(DecoderReadByte(card,0x06D)<<8)| + (DecoderReadByte(card,0x06E)<<16))<<2); + // set the decoding buffers + card->reg093 = (card->reg093 & ~0xFC); // write no header + DecoderWriteByte(card, 0x093, card->reg093); + if ((i = DecoderSetChannelBuffers(card, 256000, 4096, 0, 0, 0, 0))) { + MDEBUG(0, ": SetDecoderBuffers failed for buffer at 0x%03X\n", i); + DecoderKillChannelBuffers(card); + return 1; + } + MDEBUG(3, ": Int - B VideoES w/r addr: %08X %08X\n", + (DecoderReadByte(card,0x060)|(DecoderReadByte(card,0x061)<<8)| + (DecoderReadByte(card,0x062)<<16))<<2, + (DecoderReadByte(card,0x06C)|(DecoderReadByte(card,0x06D)<<8)| + (DecoderReadByte(card,0x06E)<<16))<<2); + + MDEBUG(3, ": Int - C VideoES w/r addr: %08X %08X\n", + (DecoderReadByte(card,0x060)|(DecoderReadByte(card,0x061)<<8)| + (DecoderReadByte(card,0x062)<<16))<<2, + (DecoderReadByte(card,0x06C)|(DecoderReadByte(card,0x06D)<<8)| + (DecoderReadByte(card,0x06E)<<16))<<2); + +// DecoderStartChannel(card); +// DecoderStartDecode(card); + + MDEBUG(3, ": Int - D VideoES w/r addr: %08X %08X\n", + (DecoderReadByte(card,0x060)|(DecoderReadByte(card,0x061)<<8)| + (DecoderReadByte(card,0x062)<<16))<<2, + (DecoderReadByte(card,0x06C)|(DecoderReadByte(card,0x06D)<<8)| + (DecoderReadByte(card,0x06E)<<16))<<2); + + DecoderPrepare(card); + + return 0; +} + +// Prepare Decoder for Packetised Elementary Streams, set parameters of Preparser +int DecoderPreparePES(struct cvdv_cards *card) +{ + + // SPUID: -1=No SPU, 0..31=Display SPU of this ID + // DataDump: 0=disable DataDump, 1=process DataDump Substreams + // PackHeader: 0=write no headers, 1=write one header, 2=write all headers + // SysHeader: 0=write no headers, 1=write one header, 2=write all headers + // DSIHeader: 0=write no headers, 3=write PCI and DSI headers and packets + int i; + int SPUID = -1; + int DataDump = 0; + int PackHeader = 0; + int SysHeader = 0; + int DSIHeader = 0; + + MDEBUG(1, ": -- PreparePES\n"); + DecoderMaskByte(card, 0x007, 0xCE, 0xC2 | (0 << 2)); // Stream Select: A/V PES Packets + + if (SPUID < 0) + card->reg092 = 0; // Do we use SPU? + else + card->reg092 = 0x20 | (SPUID & 0x1F); + if (DataDump) + card->reg092 |= 0x40; // Do we use DataDump? + DecoderWriteByte(card, 0x092, card->reg092); + //DecoderMaskByte(card,0x093,0xFC,((DSIHeader&0x03)<<6)|((PackHeader&0x03)<<4)|((SysHeader&0x03)<<2)); + card->reg093 = + (card->reg093 & ~0xFC) | (((DSIHeader & 0x03) << 6) | + ((PackHeader & 0x03) << 4) | + ((SysHeader & 0x03) << 2)); + DecoderWriteByte(card, 0x093, card->reg093); + // set the decoding buffers + if ( + (i = + DecoderSetChannelBuffers(card, 256000, 4096, 512, 0, 512, + 0))) { + MDEBUG(0,": SetDecoderBuffers failed for buffer at 0x%03X\n", i); + DecoderKillChannelBuffers(card); + return 1; + } + + DecoderPrepare(card); + + return 0; +} + + +// Prepare Decoder for MPEG 1 Systems Streams or MPEG 2 Program Streams +// SPUID: -1:ignore, 0...15 SPU Substream ID +// DataDump: 0:disable data dump stream, 1:enable data dump stream +// PackHeader: 0:write no headers, 1:write one header, 2:write all headers, 3:always discard +// SysHeader: 0:always discard, 1:write one header, 2:write all headers, 3:always discard +// DSIHeader: 0:write no DSI or PCI headers, 3:write DSI and PCI headers + packets +// DVD: 0: normal MPEG-2 data, 1: DVD stream with navi pack data +int DecoderPreparePS(struct cvdv_cards *card, + int SPUID, int DataDump, + int PackHeader, int SysHeader, int DSIHeader, int DVD) +{ + int i=0; + MDEBUG(1, ": -- PreparePS %s\n", ((DVD) ? "DVD" : "")); + //DecoderStopDecode(card); + DecoderMaskByte(card, 0x007, 0xCE, 0xC2 | (1 << 2)); // Stream Select: MPEG1 System / MPEG2 Program Stream + + if (SPUID < 0) + card->reg092 = 0; // Do we use SPU? + else + card->reg092 = 0x20 | (SPUID & 0x1F); + if (DataDump) + card->reg092 |= 0x40; // Do we use DataDump? + DecoderWriteByte(card, 0x092, card->reg092); + //DecoderMaskByte(card,0x093,0xFC,((DSIHeader&0x03)<<6)|((PackHeader&0x03)<<4)|((SysHeader&0x03)<<2)); + card->reg093 = + (card->reg093 & ~0xFC) | (((DSIHeader & 0x03) << 6) | + ((PackHeader & 0x03) << 4) | + ((SysHeader & 0x03) << 2)); + DecoderWriteByte(card, 0x093, card->reg093); + // set the decoding buffers + if (DVD) { // do we need SPU-, navi- and datadump-buffers? + + // if(card->videomode == NTSC) + i = DecoderSetChannelBuffers(card, 340000, 32768, 32768, 0, + 512,4096) ; + //else + // i = DecoderSetChannelBuffers(card, 291878, 16384, 512, 0, + // 512,0) ; + + if (i) { + MDEBUG(0,": SetDecoderBuffers failed for buffer at 0x%03X\n", i); + DecoderKillChannelBuffers(card); + return 1; + } + + } else { // normal PS + if ( + (i = + DecoderSetChannelBuffers(card, 340000, 32768, 512, + 0, 512, 0))) { + MDEBUG(0,": SetDecoderBuffers failed for buffer at 0x%03X\n", i); + DecoderKillChannelBuffers(card); + return 1; + } + } + + DecoderPrepare(card); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/streams.h linux.20pre2-ac1/drivers/media/video/margi/streams.h --- linux.20pre2/drivers/media/video/margi/streams.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/streams.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,79 @@ +/* + streams.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CVDV_STREAMS_H +#define CVDV_STREAMS_H + +#include "cardbase.h" + +// Frees allocated channel buffers +int DecoderKillChannelBuffers(struct cvdv_cards *card); + +// Allocates channel buffers +// All sizes in bytes, preferably multiple of 256 (will be rounded up otherwise) +int DecoderSetChannelBuffers(struct cvdv_cards *card, int VideoES, // Video ES Channel Buffer size, e.g. 229376 byte for NTSC + int AudioES, // Audio ES Channel Buffer size, 4096 byte + int VideoPES, // Video PES Header / SPU Channel Buffer size, 512 byte + int DataDump, // Data Dump Channel Buffer size, e.g. 80896 byte + int AudioPES, // Audio PES Header / System Channel Buffer size, 512 byte + int NaviBank); // Navi Bank Channel Buffer size, 2048 byte + +//int DecoderReadFifo + +int DecoderUnPrepare(struct cvdv_cards *card); + +void DecoderPrepare(struct cvdv_cards *card); + +// Selects audio type MPEG and sets stream ID's +// AID: -1=all MPEG, Audio Stream ID: 0..31 +// AExt: -1=unused, Audio Stream Extension ID: 0..31, only used if AType=5 +void DecoderSelectAudioID(struct cvdv_cards *card); + +// AHeader: 0=No Headers, 1=first PTS/DTS header, 2=all headers, 3=All with PTS/DTS +// AType: 0=disable audio, 1=MPEG ID (MPEG 1), 2=Lin.PCM ID, 3=AC3 ID, 4=all MPEG (use only, if just one MPEG audio stream), 5=MPEG multichannel ID (MPEG 2) +// AID: -1=all MPEG, Audio Stream ID: 0..31 +// AExt: -1=unused, Audio Stream Extension ID: 0..31, only used if AType=5 +// IEC956: 0:MPEG/AC3 data on digital out 1:IEC956 data on digital S/PDIF out +void DecoderPrepareAudio(struct cvdv_cards *card); + +// VHeader: -1=disable Video, 0=No Headers, 1=first PTS/DTS header, 2=all headers, 3=All with PTS/DTS +// VID: -1=all MPEG, 0..15=Video Stream ID +void DecoderPrepareVideo(struct cvdv_cards *card); + +// Prepare Decoder for Elementary Streams, Disable Preparser +int DecoderPrepareES(struct cvdv_cards *card); + +// Prepare Decoder for Packetised Elementary Streams, set parameters of Preparser +int DecoderPreparePES(struct cvdv_cards *card); + + +// Prepare Decoder for MPEG 1 Systems Streams or MPEG 2 Program Streams +// SPUID: -1:ignore, 0...15 SPU Substream ID +// DataDump: 0:disable data dump stream, 1:enable data dump stream +// PackHeader: 0:write no headers, 1:write one header, 2:write all headers, 3:always discard +// SysHeaader: 0:always discard, 1:write one header, 2:write all headers, 3:always discard +// DSIHeader: 0:write no DSI or PCI headers, 3:write DSI and PCI headers + packets +// DVD: 0: normal MPEG-2 data, 1: DVD stream with navi pack data +int DecoderPreparePS(struct cvdv_cards *card, + int SPUID, int DataDump, + int PackHeader, int SysHeader, int DSIHeader, + int DVD); + +#endif /* CVDV_STREAMS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/video.c linux.20pre2-ac1/drivers/media/video/margi/video.c --- linux.20pre2/drivers/media/video/margi/video.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/video.c 2002-08-06 15:42:12.000000000 +0100 @@ -0,0 +1,525 @@ +/* + video.c + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +// +// Video Decoder +// +#define __NO_VERSION__ + +#include "video.h" +#include "l64021.h" +#include "dram.h" + +// Set the background of the OSD and SPU and it's color +// mode=0: Video on Black +// mode=1: Black +// mode=2: Selected Color +// mode=3: Video on Selected Color +void VideoSetBackground(struct cvdv_cards *card, int mode, u8 Y, u8 Cb, + u8 Cr) +{ + DecoderWriteByte(card, 0x10A, Y); + DecoderWriteByte(card, 0x10B, Cb); + DecoderWriteByte(card, 0x10C, Cr); + DecoderMaskByte(card, 0x109, 0xC0, mode << 6); +} + + +int DecoderStartDecode(struct cvdv_cards *card) +{ + DecoderSetByte(card, 0x0F6, 0x01); +#ifdef DVB + if (card->audiostate.AVSyncState) +#endif + card->videosync = 1; + return 0; +} + +int DecoderStopDecode(struct cvdv_cards *card) +{ + DecoderDelByte(card, 0x0F6, 0x01); + card->videosync = 0; + return 0; +} + +// Sets Display Override (Still Image Display) to Frame Buffer at specified addresses, +// addresses are 16 bit, in 64 byte resolution +// mode: 0=off, 1=Frame, 2=Field +// width: width of the still picture in 8 pixel units +int DecoderStillImageDisplay(struct cvdv_cards *card, int mode, int width, + u16 LumaAddr, u16 ChromaAddr) +{ + DecoderStopDecode(card); + DecoderWriteWord(card, 0x11D, LumaAddr); + DecoderWriteWord(card, 0x11F, ChromaAddr); + DecoderWriteByte(card, 0x11B, width & 0x7F); + DecoderMaskByte(card, 0x109, 0x30, (mode & 3) << 4); // Display Override Mode + return 0; +} + +// Frees allocated frame buffers +int DecoderKillFrameBuffers(struct cvdv_cards *card) +{ + MDEBUG(1, ": -- DecoderKillFrameBuffers\n"); + DecoderStopDecode(card); + DRAMFree(card, card->FrameStoreLuma1); + card->FrameStoreLuma1 = BLANK; + DRAMFree(card, card->FrameStoreChroma1); + card->FrameStoreChroma1 = BLANK; + DRAMFree(card, card->FrameStoreLuma2); + card->FrameStoreLuma2 = BLANK; + DRAMFree(card, card->FrameStoreChroma2); + card->FrameStoreChroma2 = BLANK; + DRAMFree(card, card->FrameStoreLumaB); + card->FrameStoreLumaB = BLANK; + DRAMFree(card, card->FrameStoreChromaB); + card->FrameStoreChromaB = BLANK; + card->FrameBuffersAllocated = 0; +// DecoderWriteWord( + return 0; +} + +int DecoderSetFrameBuffers(struct cvdv_cards *card, int lines, // number of lines of the decoded MPEG + int TwoFrames, // 1 if no B-Frames are present in the video stream, thus allowing only 2 framestores + int RMM) // 1 if RMM +{ +#define SEGMENTS 44 // 40..54 for PAL, 44 recommended +#define BUFFERSET(buf,adr,align) if (buf>0) {\ + if (buf&((1<buf=addr;\ + addr>>=align;\ + DecoderWriteByte(card,adr,addr&0xFF);\ + DecoderWriteByte(card,adr+1,(addr>>8)&(0x00FF));\ +} + u32 addr; + int pixel, byteperline; // visible pixel per video line, same for PAL and NTSC + int FrameStoreLuma1, FrameStoreChroma1, + FrameStoreLuma2, FrameStoreChroma2, + FrameStoreLumaB, FrameStoreChromaB; + MDEBUG(1, ": -- DecoderSetFrameBuffers\n"); + DecoderStopDecode(card); + //DecoderStopChannel(card); + //lines=((CCIR601Lines(card->videomode)==625)?576:480); + byteperline = (DecoderReadByte(card, 0x116) & 0x7F) * 8; // main 64-bit reads per line + pixel = byteperline * lines; + FrameStoreLuma1 = FrameStoreLuma2 = FrameStoreLumaB = pixel >> 1; // 8 bit luma per pixel in words + FrameStoreChroma1 = FrameStoreChroma2 = FrameStoreChromaB = + pixel >> 2; // 8+8 bit chroma every 2nd pixel every 2nd line + if (card->FrameBuffersAllocated) + DecoderKillFrameBuffers(card); + BUFFERSET(FrameStoreLuma1, 0x0E0, 5); // Anchor Frame Store 1 + BUFFERSET(FrameStoreChroma1, 0x0E2, 5); + BUFFERSET(FrameStoreLuma2, 0x0E4, 5); // Anchor Frame Store 2 + BUFFERSET(FrameStoreChroma2, 0x0E6, 5); + if (TwoFrames) { + DecoderDelByte(card, 0x0F8, 0x01); + } else { +// if (CCIR601Lines(card->videomode)==525) { // Normal Mode, NTSC + if (!RMM) { // Normal Mode, NTSC + BUFFERSET(FrameStoreLumaB, 0x0E8, 5); // B Frame Store + BUFFERSET(FrameStoreChromaB, 0x0EA, 5); + DecoderDelByte(card, 0x0F8, 0x01); + } else { // Reduced Memory Mode, PAL + // 44 segments with 8 lines each (8 bit luma + 4 bit chroma) + // only display modes 4-8, 10, and 11 are allowed + FrameStoreLumaB = + (8 * byteperline * SEGMENTS) >> 1; + FrameStoreChromaB = + (4 * byteperline * SEGMENTS) >> 1; + BUFFERSET(FrameStoreLumaB, 0x0E8, 5); // B Frame Store + BUFFERSET(FrameStoreChromaB, 0x0EA, 5); + DecoderWriteByte(card, 0x121, SEGMENTS << 1); // Number of segments + DecoderSetByte(card, 0x0F8, 0x01); + } + } + card->FrameBuffersAllocated = 1; +#undef SEGMENTS +#undef BUFFERSET + return 0; +} + +// returns size of the Video ES Buffer in bytes or 0=error +u32 DecoderGetVideoESSize(struct cvdv_cards * card) +{ + if (!card->ChannelBuffersAllocated) + return 0; // buffer not initialised + return (u32) ((DecoderReadWord(card, 0x04A) & 0x3FFF) - + (DecoderReadWord(card, 0x048) & 0x3FFF)) * 256; // bytes +} + +// returns level of fullness in bytes +u32 DecoderGetVideoESLevel(struct cvdv_cards * card) +{ + u32 items; + items = DecoderReadByte(card, 0x086); + items |= ((DecoderReadWord(card, 0x087) & 0x07FF) << 8); + items *= 8; // 64 bit per item + return items; +} + +// pics=0 --> items=bytes +// pics=1 --> items=pictures +void DecoderSetVideoPanic(struct cvdv_cards *card, int pics, int items) +{ + if (pics < 0) { + DecoderMaskByte(card, 0x045, 0x18, 0x00 << 3); // disable panic mode + } else { + if (pics) { + DecoderWriteMWord(card, 0x086, items & 0x0003FFFF); + DecoderMaskByte(card, 0x045, 0x18, 0x02 << 3); // set panic mode to "number of pictures" in VideoES + } else { + DecoderWriteMWord(card, 0x086, + (items / 8) & 0x0003FFFF); + DecoderMaskByte(card, 0x045, 0x18, 0x01 << 3); // set panic mode to "number of 8-byte-frames" in VideoES + } + } +} + +int DecoderClose(struct cvdv_cards *card) +{ + if (card->DecoderOpen) { + MDEBUG(1, ": -- DecoderClose\n"); + DecoderStopDecode(card); + DecoderKillFrameBuffers(card); + card->DecoderOpen = 0; + card->lastvattr = 0; + return 0; + } else + return 1; +} + +// returns 0 on success, 1 on "picture size too big", 2 on "out of DRAM memory" +int DecoderOpen(struct cvdv_cards *card, int x, int y, // size of the decoded MPEG picture + int aspect, // pixel or picture aspect ratio of the MPEG picture: 1=square pixel 2=3:4 3=9:16 4=1:2.21 + int Field, // 0:Frame (interlaced, MPEG-2) , 1:Field (non-interlaced, MPEG-1) structure + int Letterbox, // 0:PanScan (4:3), 1:letterbox (16:9, 8:3) picture ratio + int RMM) // 1:use ReducedMemoryMode +{ + int mode, // Display Mode + i, factor, // zoom factor + top, bottom, left, right, width, height, newwidth, newheight, // screen size + vaspx, vaspy, // output video pixel aspect ratio + paspx, paspy, // input picture pixel aspect ratio + SIF; // 0:Full (480/576 lines, MPEG-2), 1:SIF (half, 240/288 lines, MPEG-1) resolution + + MDEBUG(1, ": -- DecoderOpen x:%d y:%d asp:%d field:%d lt:%d rmm:%d\n", + x, y, aspect, Field, Letterbox, RMM); + if ((x <= 0) || (y <= 0)) + return 4; // picture too small +//if (card->DecoderOpen) return 3; + DecoderStopDecode(card); + DecoderClose(card); // closes only, if already open + vaspy = 11; + vaspx = ((CCIR601Lines(card->videomode) == 525) ? 10 : 12); // screen pixel aspect ratio + // note: this aspect ratio applies to 704 pixel width, but the card's default is 720, wich is not 3:4 picture aspect ratio anymore!? + i = ((x == 720) ? 704 : x); // 720 wide is overscan of 704 wide + switch (aspect) { // MPEG data pixel aspect ratio + case 1: + paspx = 1; + paspy = 1; + break; + default: + case 2: + paspx = 4 * y; + paspy = 3 * i; + break; + case 3: + paspx = 16 * y; + paspy = 9 * i; + break; + case 4: + paspx = 221 * y; + paspy = 100 * i; + break; + } + top = + DecoderReadByte(card, + 0x129) | ((DecoderReadByte(card, 0x12B) & 0x07) + << 8); // current Start- and End Column + bottom = + DecoderReadByte(card, + 0x12A) | ((DecoderReadByte(card, 0x12B) & 0x70) + << 4); + height = (bottom - top + 1) * 2; // screen (frame) height + left = + DecoderReadByte(card, + 0x12C) | ((DecoderReadByte(card, 0x12E) & 0x07) + << 8); // current Start- and End Row + right = + DecoderReadByte(card, + 0x12D) | ((DecoderReadByte(card, 0x12E) & 0x70) + << 4); + width = (right - left + 1) / 2; // screen width, 2 clocks = 1 pixel + + if (RMM) + DecoderSetByte(card, 0x0F8, 0x01); + else + DecoderDelByte(card, 0x0F8, 0x01); + + DecoderWriteByte(card, 0x0EF, 0x08); + + //if (x>width) { // Is the picture too wide for the screen? + // DecoderSetByte(card,0x112,0x40); // Horiz. 2:1 Filter enable + // x/=2; + //} else { + DecoderDelByte(card, 0x112, 0x40); // Horiz. 2:1 Filter disable + //} + + + + + if (1 /*Letterbox */ ) { // Fit to width, reduce height + newwidth = (x * vaspy * paspx / (paspy * vaspx)); // width in right aspect ratio + if (newwidth <= 360) { // less then about half the screen size? + SIF = 1; + newwidth *= 2; + } else { + SIF = 0; + } + if ((newwidth == 704) || (newwidth == 720)) + width = newwidth; // standard sizes? + newheight = + (y * vaspx * paspy / (paspx * vaspy)) * width / x; + factor = newheight * 100 / y; + printk(KERN_INFO LOGNAME + ": Decoder Open: Display size %d x %d, Picture size %d x %d, Demanded size: %d x %d, factor %d\n", + width, height, x, y, newwidth, newheight, factor); + // 16:9 Letterbox + if ((aspect == 3) + || ((aspect == 0) + && (((factor >= 65) && (factor <= 80)) + || ((factor >= 140) && (factor <= 160))))) { + if (SIF) { // height * 1.5, SIF Letterbox + if (RMM) + return 1; // not supported! + height = (y * 3) / 2 - 2; + mode = 3; + } else { // height * 0.75, 16:9 Letterbox + height = (y * 3) / 4 - 2; + mode = 8; + } + // 2.21:1 Letterbox + } else if ((aspect == 4) + || ((aspect == 0) + && (((factor >= 45) && (factor <= 60)) + || (SIF && ((factor >= 90) + && (factor <= 110)))))) { + if (SIF) { // height * 1 + height = y; + mode = 5; + } else { // height / 2 + height = y / 2; + mode = 11; + } + // 3:4 aspect ratio + } else { + if (SIF) { + height = y * 2; + mode = ((Field && ~RMM) ? 9 : 10); + } else if (newwidth > 720) { // picture too wide, scale down to 3/4 + height = (y * 3) / 4; + mode = 8; + } else { + height = y; + mode = ((Field) ? 7 : 5); +// mode=((Field)?5:7); + } + } + width = (x * vaspy * paspx / (paspy * vaspx)) * height / y; + if (x < width) { // does the picture needs a horizontal blow-up? + DecoderWriteByte(card, 0x115, + ((x * 256 + width - 1) / width) & 0xFF); // Horiz.Filter scale, x/width*256, rounded up + DecoderSetByte(card, 0x114, 0x02); // Horiz.Filter enable + } else if (x == width) { + DecoderWriteByte(card, 0x115, 0); // 1:1 scale + DecoderDelByte(card, 0x114, 0x02); // Horiz.Filter disable + } else if (x <= 720) { + width = x; + DecoderWriteByte(card, 0x115, 0); // 1:1 scale + DecoderDelByte(card, 0x114, 0x02); // Horiz.Filter disable + } else { // picture is more than twice the screen width. sigh. + return 1; + } + } else { // Pan-Scan, fit height to maximum + DecoderSetByte(card, 0x117, 0x40); // pan-scan from bitstream +//TODO + newwidth = (x * vaspy * paspx / (paspy * vaspx)); // width in right aspect ratio + newheight = y; + if (newheight <= 288) { // less then about half the screen size? + SIF = 1; + newheight *= 2; + } else { + SIF = 0; + } + if ((newwidth == 704) || (newwidth == 720)) + width = newwidth; // standard sizes? + //newheight=(y*vaspx*paspy/(paspx*vaspy))*width/x; + factor = newheight * 100 / y; + printk(KERN_INFO LOGNAME + ": Decoder Open: Display size %d x %d, Picture size %d x %d, Demanded size: %d x %d, factor %d\n", + width, height, x, y, newwidth, newheight, factor); + if (aspect == 3) { // 16:9 Letterbox + if (SIF) { // height * 1.5, SIF Letterbox + if (RMM) + return 1; // not supported! + height = (y * 3) / 2; + mode = 3; + } else { // height * 0.75, 16:9 Letterbox + height = (y * 3) / 4; + mode = 8; + } + } else if (aspect == 4) { // 2.21:1 Letterbox + if (SIF) { // height * 1 + height = y; + mode = 5; + } else { // height / 2 + height = y / 2; + mode = 11; + } + } else if (aspect == 2) { // 3:4 aspect ratio + if (SIF) { + height = y * 2; + mode = ((Field && ~RMM) ? 9 : 10); + } else if (newwidth > 720) { // picture too wide, scale down to 3/4 + height = (y * 3) / 4; + mode = 8; + } else { + height = y; + mode = ((Field) ? 7 : 5); +// mode=((Field)?5:7); + } + } + width = (x * vaspy * paspx / (paspy * vaspx)) * height / y; + if (x < width) { // does the picture needs a horizontal blow-up? + DecoderWriteByte(card, 0x115, + ((x * 256 + width - 1) / width) & 0xFF); // Horiz.Filter scale, x/width*256, rounded up + DecoderSetByte(card, 0x114, 0x02); // Horiz.Filter enable + } else if (x == width) { + DecoderWriteByte(card, 0x115, 0); // 1:1 scale + DecoderDelByte(card, 0x114, 0x02); // Horiz.Filter disable + } else if (x <= 720) { + width = x; + DecoderWriteByte(card, 0x115, 0); // 1:1 scale + DecoderDelByte(card, 0x114, 0x02); // Horiz.Filter disable + } else { // picture is more than twice the screen width. sigh. + return 1; + } + } + printk(KERN_INFO LOGNAME + ": Decoder Open: Display size %d x %d, Picture size %d x %d Mode: %d\n", + width, height, x, y, mode); + + // calculate new picture start- and end rows and columns + height /= 2; // convert back to field height + top += ((bottom - top + 1 - height) / 2); + if (top < 0) + top = 0; + bottom = top + height - 1; + width *= 2; // convert back to clocks + left += ((right - left + 1 - width) / 2); + if (left < 0) + left = 0; + right = left + width - 1; + DecoderWriteByte(card, 0x12C, left & 0xFF); // Start- and End Column + DecoderWriteByte(card, 0x12D, right & 0xFF); + DecoderWriteByte(card, 0x12E, + ((right >> 4) & 0x70) | ((left >> 8) & 0x07)); + DecoderWriteByte(card, 0x129, top & 0xFF); // Start- and End Row + DecoderWriteByte(card, 0x12A, bottom & 0xFF); + DecoderWriteByte(card, 0x12b, + ((bottom >> 4) & 0x70) | ((top >> 8) & 0x07)); + + DecoderWriteByte(card, 0x116, ((x + 7) / 8) & 0x7F); // Main Reads per Line + + // set the new mode + DecoderMaskByte(card, 0x114, 0x78, (mode & 0x0F) << 3); + + MDEBUG(3,": Decoder Open: top/bottom/width / left/right/height / main reads %d/%d/%d / %d/%d/%d / %d\n",top,bottom,width,left,right,height,((x+7)/8)&0x7F); + + // set the frame store buffers + if ((i = DecoderSetFrameBuffers(card, y, 0, RMM))) { + MDEBUG(0,": SetFrameBuffers failed for buffer at 0x%03X\n",i); + DecoderKillFrameBuffers(card); + return 2; + } + + card->lastvattr = 0; + card->DecoderOpen = 1; + return 0; +} + +// displays a still image, whose pixel data is in luma and chroma +int DecoderShowStill(struct cvdv_cards *card, int width, int height, + u8 * luma, u8 * chroma) +{ + u16 addr; + DecoderOpen(card, width, height, + (((width == 320) || (width == 640) || (width == 384) + || (width == 768)) ? 1 : 2), + ((height < 313) ? 1 : 0), 1, 0); + addr = + ((DecoderReadWord(card, 0x11D) == DecoderReadWord(card, 0x0E0)) + ? 0x0E4 : 0x0E0); // choose invisible frame + DRAMWriteByte(card, DecoderReadWord(card, addr) << 5, + width * height, luma, 1); + DRAMWriteByte(card, DecoderReadWord(card, addr + 2) << 5, + width * height / 2, chroma, 1); + DecoderStillImageDisplay(card, ((height < 313) ? 2 : 1), + DecoderReadByte(card, 0x116) & 0x7F, + DecoderReadWord(card, addr), + DecoderReadWord(card, addr + 2)); + VideoSetBackground(card, 0, 0, 0, 0); // video on black + return 0; +} + +// TODO: untested, probably won't work (have to use "main reads per line" instead of width on SIF) +int DecoderGetStill(struct cvdv_cards *card, int *width, int *height, + u8 * luma, u8 * chroma) +{ + int framebuffer; + if (card->DecoderOpen) { + //*width=((DecoderReadByte(card,0x12D)|((DecoderReadByte(card,0x12E)&0x70)<<4))-(DecoderReadByte(card,0x12C)|((DecoderReadByte(card,0x12E)&0x07)<<8))+1)/2; // screen width, 2 clocks = 1 pixel + *width = DecoderReadByte(card, 0x116) * 8; + *height = + ((DecoderReadByte + (card, + 0x12A) | ((DecoderReadByte(card, 0x12B) & 0x70) << + 4)) - + (DecoderReadByte(card, 0x129) | + ((DecoderReadByte(card, 0x12B) & 0x07) << 8)) + 1) * 2; // screen (frame) height + if ((luma != NULL) && (chroma != NULL)) { + framebuffer = + (((DecoderReadByte(card, 0x0EE) & 0x0C) == 1) ? + 0x0E4 : 0x0E0); + DRAMReadByte(card, + DecoderReadWord(card, + framebuffer) << 5, + (*width) * (*height), luma, 1); + DRAMReadByte(card, + DecoderReadWord(card, + framebuffer + 2) << 5, + (*width) * (*height) / 2, chroma, 1); + } + return 0; + } else + return 1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/margi/video.h linux.20pre2-ac1/drivers/media/video/margi/video.h --- linux.20pre2/drivers/media/video/margi/video.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/margi/video.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,85 @@ +/* + video.h + + Copyright (C) Christian Wolff for convergence integrated media. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef CVDV_VIDEO_H +#define CVDV_VIDEO_H + + // + // Video Decoder +// + +#include "cardbase.h" + +// Set the background of the OSD and SPU and it's color +// mode=0: Video on Black +// mode=1: Black +// mode=2: Selected Color +// mode=3: Video on Selected Color +void VideoSetBackground(struct cvdv_cards *card, int mode, u8 Y, u8 Cb, + u8 Cr); + + +int DecoderStartDecode(struct cvdv_cards *card); + +int DecoderStopDecode(struct cvdv_cards *card); + +// Sets Display Override (Still Image Display) to Frame Buffer at specified addresses, +// addresses are 16 bit, in 64 byte resolution +// mode: 0=off, 1=Frame, 2=Field +// width: width of the still picture in 8 pixel units +int DecoderStillImageDisplay(struct cvdv_cards *card, int mode, int width, + u16 LumaAddr, u16 ChromaAddr); + +// Frees allocated frame buffers +int DecoderKillFrameBuffers(struct cvdv_cards *card); + +int DecoderSetFrameBuffers(struct cvdv_cards *card, int lines, // number of lines of the decoded MPEG + int TwoFrames, // 1 if no B-Frames are present in the video stream, thus allowing only 2 framestores + int RMM); // 1 if RMM + +// returns size of the Video ES Buffer in bytes or 0=error +u32 DecoderGetVideoESSize(struct cvdv_cards *card); + +// returns level of fullness in bytes +u32 DecoderGetVideoESLevel(struct cvdv_cards *card); + +// pics=0 --> items=bytes +// pics=1 --> items=pictures +void DecoderSetVideoPanic(struct cvdv_cards *card, int pics, int items); + +int DecoderClose(struct cvdv_cards *card); + +// returns 0 on success, 1 on "picture size too big", 2 on "out of DRAM memory" +int DecoderOpen(struct cvdv_cards *card, int x, int y, // size of the decoded MPEG picture + int aspect, // pixel or picture aspect ratio of the MPEG picture: 1=square pixel 2=3:4 3=9:16 4=1:2.21 + int Field, // 0:Frame (interlaced, MPEG-2) , 1:Field (non-interlaced, MPEG-1) structure + int Letterbox, // 0:PanScan (4:3), 1:letterbox (16:9, 8:3) picture ratio // TODO, ignored for now + int RMM // 1:use ReducedMemoryMode + ); + +// displays a still image, whose pixel data is in luma and chroma +int DecoderShowStill(struct cvdv_cards *card, int width, int height, + u8 * luma, u8 * chroma); + +// TODO: untested, probably won't work (have to use "main reads per line" instead of width on SIF) +int DecoderGetStill(struct cvdv_cards *card, int *width, int *height, + u8 * luma, u8 * chroma); + +#endif /* CVDV_VIDEO_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/media/video/zr36067.c linux.20pre2-ac1/drivers/media/video/zr36067.c --- linux.20pre2/drivers/media/video/zr36067.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/media/video/zr36067.c 2002-08-06 15:42:12.000000000 +0100 @@ -1417,7 +1417,7 @@ zr36060_sleep(zr, 0); post_office_write(zr, 3, 0, 0); udelay(2); - default: + default:; } return 0; } @@ -4208,6 +4208,7 @@ /* sleep 1 second */ + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); /* Get status of video decoder */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/fusion/mptbase.c linux.20pre2-ac1/drivers/message/fusion/mptbase.c --- linux.20pre2/drivers/message/fusion/mptbase.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/fusion/mptbase.c 2002-08-09 11:07:47.000000000 +0100 @@ -49,7 +49,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.c,v 1.120 2002/06/27 13:53:27 pdelaney Exp $ + * $Id: mptbase.c,v 1.121 2002/07/23 18:56:59 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -437,8 +437,9 @@ pa = 0; /* No reply flush! */ } +#ifdef MPT_DEBUG_IRQ if ((int)ioc->chip_type > (int)FC929) { - /* Verify mf, mf are reasonable. + /* Verify mf, mr are reasonable. */ if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth)) || (mf < ioc->req_frames)) ) { @@ -464,6 +465,7 @@ freeme = 0; } } +#endif /* Check for (valid) IO callback! */ if (cb_idx) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/fusion/mptbase.h linux.20pre2-ac1/drivers/message/fusion/mptbase.h --- linux.20pre2/drivers/message/fusion/mptbase.h 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/fusion/mptbase.h 2002-08-14 14:41:30.000000000 +0100 @@ -13,7 +13,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.h,v 1.127 2002/07/09 13:30:36 pdelaney Exp $ + * $Id: mptbase.h,v 1.131 2002/07/31 18:55:11 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -80,8 +80,8 @@ #define COPYRIGHT "Copyright (c) 1999-2002 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "2.01.07" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.01.07" +#define MPT_LINUX_VERSION_COMMON "2.01.10" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.01.10" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -515,7 +515,7 @@ #define MPT_SCSICFG_NEGOTIATE 0x01 /* Negotiate on next IO */ #define MPT_SCSICFG_NEED_DV 0x02 /* Schedule DV */ #define MPT_SCSICFG_DV_PENDING 0x04 /* DV on this physical id pending */ -#define MPT_SCSICFG_DV_DONE 0x08 /* DV on this physical id complete */ +#define MPT_SCSICFG_DV_NOT_DONE 0x08 /* DV has not been performed */ #define MPT_SCSICFG_BLK_NEGO 0x10 /* WriteSDP1 with WDTR and SDTR disabled */ /* Args passed to writeSDP1: */ @@ -527,6 +527,7 @@ int *nvram; /* table of device NVRAM values */ IOCPage3_t *pIocPg3; /* table of physical disks */ u8 dvStatus[MPT_MAX_SCSI_DEVICES]; + u8 iocntr[MPT_MAX_SCSI_DEVICES]; int isRaid; /* bit field, 1 if RAID */ u8 minSyncFactor; /* 0xFF if async */ u8 maxSyncOffset; /* 0 if async */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/fusion/mptctl.c linux.20pre2-ac1/drivers/message/fusion/mptctl.c --- linux.20pre2/drivers/message/fusion/mptctl.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/fusion/mptctl.c 2002-08-09 11:07:47.000000000 +0100 @@ -34,7 +34,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptctl.c,v 1.55 2002/06/20 13:28:16 pdelaney Exp $ + * $Id: mptctl.c,v 1.58 2002/07/31 18:55:12 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -637,8 +637,8 @@ iocnumX = khdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - printk(KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnumX); + dtmprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnumX)); return -ENODEV; } @@ -708,9 +708,9 @@ } if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { - printk(KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n", - __FILE__, __LINE__, krinfo.hdr.iocnum); - return -ENXIO; /* (-6) No such device or address */ + dtmprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n", + __FILE__, __LINE__, krinfo.hdr.iocnum)); + return -ENODEV; /* (-6) No such device or address */ } if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) { @@ -816,9 +816,9 @@ dctlprintk((KERN_INFO "DbG: kfwdl.ioc = %04xh\n", ioc)); if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) { - printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n", - __FILE__, __LINE__, ioc); - return -ENXIO; /* (-6) No such device or address */ + dtmprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n", + __FILE__, __LINE__, ioc)); + return -ENODEV; /* (-6) No such device or address */ } /* Valid device. Get a message frame and construct the FW download message. @@ -1252,8 +1252,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1379,8 +1379,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1510,8 +1510,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1568,8 +1568,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1606,8 +1606,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1654,8 +1654,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1708,8 +1708,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1794,8 +1794,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1842,8 +1842,8 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } if (!ioc->ioctl) { @@ -1948,10 +1948,6 @@ if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; - else { - rc = -EPERM; - goto done_free_mem; - } /* Have the IOCTL driver set the direction based * on the dataOutSize (ordering issue with Sparc). @@ -2393,8 +2389,8 @@ if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnumX); + dtmprintk((KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnumX)); return -ENODEV; } @@ -2466,8 +2462,8 @@ if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -2567,8 +2563,8 @@ if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -2631,8 +2627,8 @@ if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -2687,8 +2683,8 @@ if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -2790,8 +2786,8 @@ iocnumX = karg.lc & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); + dtmprintk((KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -2920,12 +2916,12 @@ static struct file_operations mptctl_fops = { owner_THIS_MODULE - llseek: no_llseek, - read: mptctl_read, - write: mptctl_write, - ioctl: mptctl_ioctl, - open: mptctl_open, - release: mptctl_release, + .llseek = no_llseek, + .read = mptctl_read, + .write = mptctl_write, + .ioctl = mptctl_ioctl, + .open = mptctl_open, + .release = mptctl_release, }; static struct miscdevice mptctl_miscdev = { @@ -2975,8 +2971,8 @@ iocnumX = kfw32.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n", - __LINE__, iocnumX); + dtmprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n", + __LINE__, iocnumX)); return -ENODEV; } @@ -3015,8 +3011,8 @@ iocnumX = karg32.hdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", - __LINE__, iocnumX); + dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", + __LINE__, iocnumX)); return -ENODEV; } @@ -3072,8 +3068,8 @@ iocnumX = karg32.lc & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || (ioc == NULL)) { - printk(KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", - __LINE__, iocnumX); + dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", + __LINE__, iocnumX)); return -ENODEV; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/fusion/mptscsih.c linux.20pre2-ac1/drivers/message/fusion/mptscsih.c --- linux.20pre2/drivers/message/fusion/mptscsih.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/fusion/mptscsih.c 2002-08-09 11:07:47.000000000 +0100 @@ -26,7 +26,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.c,v 1.97 2002/07/03 13:11:01 pdelaney Exp $ + * $Id: mptscsih.c,v 1.100 2002/07/31 18:55:12 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -183,7 +183,7 @@ static VirtDevice *mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen); void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); -static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data); +static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags); static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id); static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags); @@ -226,11 +226,11 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28) static struct proc_dir_entry proc_mpt_scsihost = { - low_ino: PROC_SCSI_MPT, - namelen: 8, - name: "mptscsih", - mode: S_IFDIR | S_IRUGO | S_IXUGO, - nlink: 2, + .low_ino = PROC_SCSI_MPT, + .namelen = 8, + .name = "mptscsih", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + .nlink = 2, }; #endif @@ -323,8 +323,8 @@ return 1; } - dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p)\n", - ioc->name, mf, mr, sc)); + dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", + ioc->name, mf, mr, sc, req_idx)); atomic_dec(&queue_depth); @@ -332,6 +332,14 @@ pScsiReq = (SCSIIORequest_t *) mf; pScsiReply = (SCSIIOReply_t *) mr; +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION + if (hd->is_spi) { + u32 qtag = le32_to_cpu(pScsiReq->Control); + if (qtag & MPI_SCSIIO_CONTROL_UNTAGGED) + hd->ioc->spi_data.iocntr[sc->target]--; + } +#endif + if (pScsiReply == NULL) { /* special context reply handling */ @@ -351,9 +359,6 @@ } } clear_sense_flag(hd, pScsiReq); - - if (hd->is_spi) - mptscsih_set_dvflags(hd, pScsiReq, sc->buffer); } else { u32 xfer_cnt; u16 status; @@ -484,9 +489,6 @@ sc->buffer, xfer_cnt); } - - if (hd->is_spi) - mptscsih_set_dvflags(hd, pScsiReq, sc->buffer); break; case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ @@ -568,9 +570,6 @@ sc->buffer, xfer_cnt); } - - if (hd->is_spi) - mptscsih_set_dvflags(hd, pScsiReq, sc->buffer); break; case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ @@ -947,6 +946,12 @@ mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); } } +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION + /* Clear untagged counting array */ + for (ii= 0; ii < MPT_MAX_SCSI_DEVICES; ii++) + hd->ioc->spi_data.iocntr[ii] = 0; +#endif + return; } @@ -1435,7 +1440,11 @@ hd->ioc->spi_data.forceDv = 0; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) hd->ioc->spi_data.dvStatus[ii] = MPT_SCSICFG_NEGOTIATE; - + + if (hd->negoNvram == 0) { + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) + hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_NOT_DONE; + } ddvprintk((MYIOC_s_INFO_FMT "dv %x width %x factor %x \n", @@ -2041,17 +2050,25 @@ mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); issueCmd = 0; } + + if (qtag == MPI_SCSIIO_CONTROL_UNTAGGED) + hd->ioc->spi_data.iocntr[target]++; + + /* Set the DV flags. + */ + if (dvStatus & MPT_SCSICFG_DV_NOT_DONE) + mptscsih_set_dvflags(hd, pScsiReq); #endif } } if (issueCmd) { mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); - dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p)\n", - hd->ioc->name, SCpnt)); + dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", + hd->ioc->name, SCpnt, mf, my_idx)); } else { - ddvtprintk((MYIOC_s_INFO_FMT "Pending SCSI cmd (%p)\n", - hd->ioc->name, SCpnt)); + ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n", + hd->ioc->name, SCpnt, my_idx)); /* Place this command on the pendingQ if possible */ spin_lock_irqsave(&hd->freedoneQlock, flags); if (!Q_IS_EMPTY(&hd->freeQ)) { @@ -3683,10 +3700,25 @@ * 0 = _DIR_NONE changed to SCSI_DATA_NONE (3) * -1 = _DATA_IN changed to SCSI_DATA_READ (2) * If the direction is unknown, fall through to original code. + * + * Mid-layer bug fix(): sg interface generates the wrong data + * direction in some cases. Set the direction the hard way for + * the most common commands. */ static int mptscsih_io_direction(Scsi_Cmnd *cmd) { + switch (cmd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + return SCSI_DATA_WRITE; + break; + case READ_6: + case READ_10: + return SCSI_DATA_READ; + break; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (cmd->sc_data_direction != SCSI_DATA_UNKNOWN) return cmd->sc_data_direction; @@ -3898,7 +3930,7 @@ MPT_FRAME_HDR *mf = NULL; MPT_FRAME_HDR *cmdMfPtr = NULL; - ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ called...", hd->ioc->name)); + ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name)); cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); spin_lock_irqsave(&hd->freedoneQlock, flags); if (!Q_IS_EMPTY(&hd->pendingQ)) { @@ -3938,7 +3970,7 @@ /* Flush the pendingQ. */ - ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands called\n", hd->ioc->name)); + ddvtprintk((MYIOC_s_INFO_FMT ": post_pendingQ_commands\n", hd->ioc->name)); while (1) { spin_lock_irqsave(&hd->freedoneQlock, flags); if (Q_IS_EMPTY(&hd->pendingQ)) { @@ -3966,8 +3998,15 @@ } mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); - ddvtprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (mf=%p)\n", - hd->ioc->name, mf)); + +#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) + { + u16 req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + Scsi_Cmnd *sc = hd->ScsiLookup[req_idx]; + printk(MYIOC_s_INFO_FMT "Issued SCSI cmd (sc=%p) idx=%d (mf=%p)\n", + hd->ioc->name, sc, req_idx, mf); + } +#endif } return; @@ -4177,7 +4216,7 @@ while (numPDisk) { if (physDiskNum == pPDisk->PhysDiskNum) { - pSpi->dvStatus[pPDisk->PhysDiskID] = MPT_SCSICFG_NEED_DV; + pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE); pSpi->forceDv = MPT_SCSICFG_NEED_DV; ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID)); break; @@ -4612,6 +4651,20 @@ return 0; } + /* Prevent the system from continually writing to the log + * if a medium is not found: 02 3A 00 + * Changer issues: TUR, Read Capacity, Table of Contents continually + */ + if (sk==SK_NOT_READY && asc==0x3A) { + if (ioop->cdbPtr == NULL) { + return 0; + } else if ((ioop->cdbPtr[0] == CMD_TestUnitReady) || + (ioop->cdbPtr[0] == CMD_ReadCapacity) || + (ioop->cdbPtr[0] == 0x43)) { + return 0; + } + } + /* * Protect ourselves... */ @@ -4746,6 +4799,14 @@ mptscsih_setTargetNegoParms(hd, vdev, data[56]); else mptscsih_setTargetNegoParms(hd, vdev, 0); + + /* If LUN 0, tape and have not done DV, set the DV flag. + */ + if ((lun == 0) && ((data[0] & 0x1F) == 0x01)) { + ScsiCfgData *pSpi = &hd->ioc->spi_data; + if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE) + pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV; + } } /* Is LUN supported? If so, upper 3 bits will be 0 @@ -4915,43 +4976,39 @@ return; } -/* - * If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return. +/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return. * Else set the NEED_DV flag after Read Capacity Issued (disks) - * or Mode Sense (cdroms). Tapes, key off of Inquiry command. + * or Mode Sense (cdroms). + * + * Tapes, initTarget will set this flag on completion of Inquiry command. + * Called only if DV_NOT_DONE flag is set */ -static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq, char *data) +static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) { - u8 cmd = pReq->CDB[0]; + u8 cmd; - if (pReq->LUN[1] != 0) + if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0)) return; - if (hd->negoNvram != 0) - return; + cmd = pReq->CDB[0]; - if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE) || - ((cmd == INQUIRY) && ((data[0] & 0x1F) == 0x01))) { - u8 dvStatus = hd->ioc->spi_data.dvStatus[pReq->TargetID]; - if (!(dvStatus & MPT_SCSICFG_DV_DONE)) { - ScsiCfgData *pSpi = &hd->ioc->spi_data; - if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) { - /* Set NEED_DV for all hidden disks - */ - Ioc3PhysDisk_t *pPDisk = pSpi->pIocPg3->PhysDisk; - int numPDisk = pSpi->pIocPg3->NumPhysDisks; - - while (numPDisk) { - pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV; - ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID)); - pPDisk++; - numPDisk--; - } - } - pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV; - ddvtprintk(("NEED_DV set for visible disk id %d\n", - pReq->TargetID)); - }; + if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) { + ScsiCfgData *pSpi = &hd->ioc->spi_data; + if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) { + /* Set NEED_DV for all hidden disks + */ + Ioc3PhysDisk_t *pPDisk = pSpi->pIocPg3->PhysDisk; + int numPDisk = pSpi->pIocPg3->NumPhysDisks; + + while (numPDisk) { + pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV; + ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID)); + pPDisk++; + numPDisk--; + } + } + pSpi->dvStatus[pReq->TargetID] |= MPT_SCSICFG_NEED_DV; + ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID)); } } @@ -5052,6 +5109,7 @@ u8 offset; u8 bus = 0; u8 negoFlags; + u8 maxwidth, maxoffset, maxfactor; if (ioc->spi_data.sdp1length == 0) return 0; @@ -5065,48 +5123,53 @@ } for (; id <= maxid; id++) { + if (id == ioc->pfacts[portnum].PortSCSIID) continue; - if (flags & MPT_SCSICFG_USE_NVRAM) { - /* Use NVRAM, adapter maximums and target settings. - * Data over-riden by target structure information, if present - */ - width = ioc->spi_data.maxBusWidth; - offset = ioc->spi_data.maxSyncOffset; - factor = ioc->spi_data.minSyncFactor; - if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) { - nvram = ioc->spi_data.nvram[id]; - - if (width) - width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; - - if (offset > 0) { - factor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; - if (factor == 0) { - /* Key for async */ - factor = MPT_ASYNC; - offset = 0; - } else if (factor < ioc->spi_data.minSyncFactor) { - factor = ioc->spi_data.minSyncFactor; - } - } else - factor = MPT_ASYNC; - } + /* Use NVRAM to get adapter and target maximums + * Data over-riden by target structure information, if present + */ + maxwidth = ioc->spi_data.maxBusWidth; + maxoffset = ioc->spi_data.maxSyncOffset; + maxfactor = ioc->spi_data.minSyncFactor; + if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) { + nvram = ioc->spi_data.nvram[id]; + + if (maxwidth) + maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + + if (maxoffset > 0) { + maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; + if (maxfactor == 0) { + /* Key for async */ + maxfactor = MPT_ASYNC; + maxoffset = 0; + } else if (maxfactor < ioc->spi_data.minSyncFactor) { + maxfactor = ioc->spi_data.minSyncFactor; + } + } else + maxfactor = MPT_ASYNC; + } - /* Set the negotiation flags. - */ - negoFlags = ioc->spi_data.noQas; - if (!width) - negoFlags |= MPT_TARGET_NO_NEGO_WIDE; - - if (!offset) - negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + /* Set the negotiation flags. + */ + negoFlags = ioc->spi_data.noQas; + if (!maxwidth) + negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + + if (!maxoffset) + negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + + if (flags & MPT_SCSICFG_USE_NVRAM) { + width = maxwidth; + factor = maxfactor; + offset = maxoffset; } else { width = 0; factor = MPT_ASYNC; offset = 0; - negoFlags = 0; + //negoFlags = 0; //negoFlags = MPT_TARGET_NO_NEGO_SYNC; } @@ -5135,6 +5198,10 @@ return -EAGAIN; } + ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n", + hd->ioc->name, mf, id, requested, configuration)); + + /* Set the request and the data pointers. * Request takes: 36 bytes (32 bit SGE) * SCSI Device Page 1 requires 16 bytes @@ -5291,13 +5358,13 @@ pReq = (SCSIIORequest_t *) mf; if (mf != hd->cmdPtr) { - printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p)\n", - hd->ioc->name, (void *)mf, (void *) hd->cmdPtr); + printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n", + hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx); } hd->cmdPtr = NULL; - ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p)\n", - hd->ioc->name, mf, mr)); + ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", + hd->ioc->name, mf, mr, req_idx)); atomic_dec(&queue_depth); @@ -5965,7 +6032,6 @@ unsigned long flags; int id, maxid, dvStatus, did; int ii, isPhysDisk; - u8 oldQas; spin_lock_irqsave(&dvtaskQ_lock, flags); dvtaskQ_active = 1; @@ -6011,7 +6077,6 @@ maxid = MIN (ioc->sh->max_id, MPT_MAX_SCSI_DEVICES); for (id = 0; id < maxid; id++) { - oldQas = hd->ioc->spi_data.noQas; spin_lock_irqsave(&dvtaskQ_lock, flags); if (dvtaskQ_release) { dvtaskQ_active = 0; @@ -6022,8 +6087,25 @@ dvStatus = hd->ioc->spi_data.dvStatus[id]; if (dvStatus & MPT_SCSICFG_NEED_DV) { + VirtDevice *pTarget = hd->Targets[id]; + did++; + if (pTarget && ((pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) == 0)){ + if (hd->ioc->spi_data.iocntr[id] == 0) { + hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING; + } else { + /* Wait until not busy + */ + ddvtprintk((MYIOC_s_NOTE_FMT + " DV Wait: %d untagged and busy. cntr %d\n", + ioc->name, id, + hd->ioc->spi_data.iocntr[id])); + continue; + } + } else { + hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING; + } + - hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING; hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV; set_current_state(TASK_INTERRUPTIBLE); @@ -6043,9 +6125,8 @@ } mptscsih_doDv(hd, 0, id); - did++; - hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_DONE; - hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING; + + hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING); if (isPhysDisk) { for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { @@ -6060,7 +6141,7 @@ */ post_pendingQ_commands(hd); - if ((!oldQas) && (hd->ioc->spi_data.noQas)) + if (hd->ioc->spi_data.noQas) mptscsih_qas_check(hd); } } @@ -6099,27 +6180,25 @@ { VirtDevice *pTarget = NULL; int ii; - int change = 0; if (hd->Targets == NULL) return; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { - change = 0; + if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0) + continue; + pTarget = hd->Targets[ii]; if ((pTarget != NULL) && (!pTarget->raidVolume)) { if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) { - change = 1; pTarget->negoFlags |= hd->ioc->spi_data.noQas; + mptscsih_writeSDP1(hd, 0, ii, 0); } } else { if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) - change = 1; + mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM); } - - if ((change) && (hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_DONE)) - mptscsih_writeSDP1(hd, 0, ii, 0); } return; } @@ -6407,6 +6486,7 @@ cfg.physAddr = cfg0_dma_addr; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; cfg.dir = 0; + if (mpt_config(hd->ioc, &cfg) != 0) goto target_done; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/i2o/i2o_block.c linux.20pre2-ac1/drivers/message/i2o/i2o_block.c --- linux.20pre2/drivers/message/i2o/i2o_block.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/i2o/i2o_block.c 2002-08-06 15:42:18.000000000 +0100 @@ -1448,6 +1448,12 @@ * 1. If there was a TID reuse. * 2. There was more than one I2O controller. */ + + if(pci_set_dma_mask(c->pdev, 0xffffffff)) + { + printk(KERN_WARNING "i2o_block : No suitable DMA available for controller %d\n", i); + continue; + } if(!bios) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/i2o/i2o_config.c linux.20pre2-ac1/drivers/message/i2o/i2o_config.c --- linux.20pre2/drivers/message/i2o/i2o_config.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/i2o/i2o_config.c 2002-08-06 15:42:18.000000000 +0100 @@ -277,7 +277,14 @@ if(c) { foo[i] = 1; - i2o_unlock_controller(c); + if(pci_set_dma_mask(c->pdev, 0xffffffff)) + { + printk(KERN_WARNING "i2o_config : No suitable DMA available on controller %d\n", i); + i2o_unlock_controller(c); + continue; + } + + i2o_unlock_controller(c); } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/i2o/i2o_core.c linux.20pre2-ac1/drivers/message/i2o/i2o_core.c --- linux.20pre2/drivers/message/i2o/i2o_core.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/i2o/i2o_core.c 2002-08-06 15:42:18.000000000 +0100 @@ -3390,8 +3390,9 @@ { if(i2o_quiesce_controller(c)) { - printk(KERN_WARNING "i2o: Could not quiesce %s." " - Verify setup on next system power up.\n", c->name); + printk(KERN_WARNING "i2o: Could not quiesce %s.\n" + "Verify setup on next system power up.\n", + c->name); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/i2o/i2o_lan.c linux.20pre2-ac1/drivers/message/i2o/i2o_lan.c --- linux.20pre2/drivers/message/i2o/i2o_lan.c 2002-08-13 13:58:33.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/i2o/i2o_lan.c 2002-08-06 15:42:18.000000000 +0100 @@ -1474,6 +1474,12 @@ if (iop==NULL) continue; + if(pci_set_dma_mask(iop->pdev, 0xffffffff)) + { + printk(KERN_WARNING "i2o_lan : No suitable DMA available for controller %d\n", i); + continue; + } + for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) { if (i2o_dev->lct_data.class_id != I2O_CLASS_LAN) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/message/i2o/i2o_pci.c linux.20pre2-ac1/drivers/message/i2o/i2o_pci.c --- linux.20pre2/drivers/message/i2o/i2o_pci.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/message/i2o/i2o_pci.c 2002-08-13 14:26:26.000000000 +0100 @@ -335,6 +335,11 @@ continue; printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n", dev->bus->number, dev->devfn); + if(pci_set_dma_mask(dev, 0xffffffff)) + { + printk(KERN_WARNING "I2O controller on bus %d at %d : No suitable DMA available\n", dev->bus->number, dev->devfn); + continue; + } pci_set_master(dev); if(i2o_pci_install(dev)==0) count++; @@ -385,4 +390,3 @@ MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o"); module_init(i2o_pci_core_attach); module_exit(i2o_pci_core_detach); - \ No newline at end of file diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/3c59x.c linux.20pre2-ac1/drivers/net/3c59x.c --- linux.20pre2/drivers/net/3c59x.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/3c59x.c 2002-08-06 15:42:06.000000000 +0100 @@ -166,6 +166,11 @@ - Rename wait_for_completion() to issue_and_wait() to avoid completion.h clash. + LK1.1.18ac 01Jul02 akpm + - Fix for undocumented transceiver power-up bit on some 3c566B's + (Donald Becker, Rahul Karnik) + + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. - Also see Documentation/networking/vortex.txt */ @@ -181,8 +186,8 @@ #define DRV_NAME "3c59x" -#define DRV_VERSION "LK1.1.16" -#define DRV_RELDATE "19 July 2001" +#define DRV_VERSION "LK1.1.18-ac" +#define DRV_RELDATE "1 July 2002" @@ -400,7 +405,7 @@ EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ 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 }; + EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000 }; enum vortex_chips { CH_3C590 = 0, @@ -508,7 +513,7 @@ HAS_HWCKSM, 128, }, {"3c556B Laptop Hurricane", PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR| - HAS_HWCKSM, 128, }, + WNO_XCVR_PWR|HAS_HWCKSM, 128, }, {"3c575 [Megahertz] 10/100 LAN CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, @@ -1198,6 +1203,10 @@ if (vp->drv_flags & INVERT_MII_PWR) n |= 0x4000; outw(n, ioaddr + Wn2_ResetOptions); + if (vp->drv_flags & WNO_XCVR_PWR) { + EL3WINDOW(0); + outw(0x0800, ioaddr); + } } /* Extract our information from the EEPROM data. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/atarilance.c linux.20pre2-ac1/drivers/net/atarilance.c --- linux.20pre2/drivers/net/atarilance.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/atarilance.c 2002-08-06 16:14:39.000000000 +0100 @@ -546,11 +546,8 @@ if (lp->cardtype == PAM_CARD || memaddr == (unsigned short *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ - if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO, - "PAM/Riebl-ST Ethernet", dev)) { - printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 ); - return( 0 ); - } + request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO, + "PAM/Riebl-ST Ethernet", dev); dev->irq = (unsigned short)IRQ_AUTO_5; } else { @@ -563,11 +560,8 @@ printk( "Lance: request for VME interrupt failed\n" ); return( 0 ); } - if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, - "Riebl-VME Ethernet", dev)) { - printk( "Lance: request for irq %d failed\n", irq ); - return( 0 ); - } + request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, + "Riebl-VME Ethernet", dev); dev->irq = irq; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/Config.in linux.20pre2-ac1/drivers/net/Config.in --- linux.20pre2/drivers/net/Config.in 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/Config.in 2002-08-11 21:22:33.000000000 +0100 @@ -149,9 +149,9 @@ tristate ' IBM LAN Adapter/A support' CONFIG_IBMLANA fi if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then - bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI + bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI else - define_bool CONFIG_NET_PCI n + define_bool CONFIG_NET_PCI n fi if [ "$CONFIG_NET_PCI" = "y" ]; then dep_tristate ' AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI @@ -241,7 +241,7 @@ dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI dep_tristate 'Intel(R) PRO/1000 Gigabit Ethernet support' CONFIG_E1000 $CONFIG_PCI dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS -dep_tristate 'National Semiconduct DP83820 support' CONFIG_NS83820 $CONFIG_PCI +dep_tristate 'National Semiconductor DP83820 support' CONFIG_NS83820 $CONFIG_PCI dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/cs89x0.h linux.20pre2-ac1/drivers/net/cs89x0.h --- linux.20pre2/drivers/net/cs89x0.h 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/cs89x0.h 2002-08-06 15:42:06.000000000 +0100 @@ -385,11 +385,11 @@ #define A_CNF_10B_T 0x0001 #define A_CNF_AUI 0x0002 #define A_CNF_10B_2 0x0004 -#define A_CNF_MEDIA_TYPE 0x0060 -#define A_CNF_MEDIA_AUTO 0x0000 +#define A_CNF_MEDIA_TYPE 0x0070 +#define A_CNF_MEDIA_AUTO 0x0070 #define A_CNF_MEDIA_10B_T 0x0020 #define A_CNF_MEDIA_AUI 0x0040 -#define A_CNF_MEDIA_10B_2 0x0060 +#define A_CNF_MEDIA_10B_2 0x0010 #define A_CNF_DC_DC_POLARITY 0x0080 #define A_CNF_NO_AUTO_POLARITY 0x2000 #define A_CNF_LOW_RX_SQUELCH 0x4000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/depca.c linux.20pre2-ac1/drivers/net/depca.c --- linux.20pre2/drivers/net/depca.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/depca.c 2002-08-12 15:25:42.000000000 +0100 @@ -1347,8 +1347,7 @@ ** If the MCA configuration says the card should be here, ** it really should be here. */ - printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not -responding.\n", dev->name, iobase); + printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not responding.\n", dev->name, iobase); } if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) { @@ -1970,7 +1969,7 @@ case DEPCA_SET_MCA: /* Set a multicast address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (ioc->len >= HASH_TABLE_LEN || ioc->len < 0) + if (ioc->len >= HASH_TABLE_LEN) return -EINVAL; if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) return -EFAULT; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/eepro.c linux.20pre2-ac1/drivers/net/eepro.c --- linux.20pre2/drivers/net/eepro.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/eepro.c 2002-08-13 17:04:28.000000000 +0100 @@ -732,27 +732,27 @@ goto exit; } - /* We seem to have the 82595 signature, let's - play with its counter (last 2 bits of - register 2 of bank 0) to be sure. */ + /* We seem to have the 82595 signature, let's + play with its counter (last 2 bits of + register 2 of bank 0) to be sure. */ - counter = (id & R_ROBIN_BITS); + counter = (id & R_ROBIN_BITS); if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS)!=(counter + 0x40)) { retval = -ENODEV; goto exit; } - /* Initialize the device structure */ - dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL); + /* Initialize the device structure */ + dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL); if (!dev->priv) { retval = -ENOMEM; goto exit; } - memset(dev->priv, 0, sizeof(struct eepro_local)); + memset(dev->priv, 0, sizeof(struct eepro_local)); - lp = (struct eepro_local *)dev->priv; + lp = (struct eepro_local *)dev->priv; /* default values */ lp->eepro = 0; @@ -761,37 +761,37 @@ lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; lp->eeprom_reg = EEPROM_REG_PRO; - /* Now, get the ethernet hardware address from - the EEPROM */ - station_addr[0] = read_eeprom(ioaddr, 2, dev); - - /* FIXME - find another way to know that we've found - * an Etherexpress 10 - */ - if (station_addr[0] == 0x0000 || - station_addr[0] == 0xffff) { - lp->eepro = LAN595FX_10ISA; + /* Now, get the ethernet hardware address from + the EEPROM */ + station_addr[0] = read_eeprom(ioaddr, 2, dev); + + /* FIXME - find another way to know that we've found + * an Etherexpress 10 + */ + if (station_addr[0] == 0x0000 || + station_addr[0] == 0xffff) { + lp->eepro = LAN595FX_10ISA; lp->eeprom_reg = EEPROM_REG_10; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; lp->xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; lp->xmt_bar = XMT_BAR_10; station_addr[0] = read_eeprom(ioaddr, 2, dev); - } - station_addr[1] = read_eeprom(ioaddr, 3, dev); - station_addr[2] = read_eeprom(ioaddr, 4, dev); + } + station_addr[1] = read_eeprom(ioaddr, 3, dev); + station_addr[2] = read_eeprom(ioaddr, 4, dev); if (!lp->eepro) { if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) lp->eepro = 2; else if (station_addr[2] == SA_ADDR1) lp->eepro = 1; - } + } - /* Fill in the 'dev' fields. */ - dev->base_addr = ioaddr; + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; for (i=0; i < 6; i++) - dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; + dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; /* RX buffer must be more than 3K and less than 29K */ if (dev->mem_end < 3072 || dev->mem_end > 29696) @@ -800,59 +800,58 @@ /* calculate {xmt,rcv}_{lower,upper}_limit */ eepro_recalc(dev); - - if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) - dev->if_port = BNC; + if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) + dev->if_port = BNC; else dev->if_port = TPE; if ((dev->irq < 2) && (lp->eepro!=0)) { - i = read_eeprom(ioaddr, 1, dev); - irqMask = read_eeprom(ioaddr, 7, dev); - i &= 0x07; /* Mask off INT number */ - - for (j=0; ((j<16) && (i>=0)); j++) { - if ((irqMask & (1<irq = j; - break; /* found bit corresponding to irq */ - } - i--; /* count bits set in irqMask */ - } + i = read_eeprom(ioaddr, 1, dev); + irqMask = read_eeprom(ioaddr, 7, dev); + i &= 0x07; /* Mask off INT number */ + + for (j=0; ((j<16) && (i>=0)); j++) { + if ((irqMask & (1<irq = j; + break; /* found bit corresponding to irq */ } - if (dev->irq < 2) { + i--; /* count bits set in irqMask */ + } + } + if (dev->irq < 2) { printk(KERN_ERR " Duh! illegal interrupt vector stored in EEPROM.\n"); - kfree(dev->priv); + kfree(dev->priv); retval = -ENODEV; goto freeall; - } else - if (dev->irq==2) dev->irq = 9; - } - - /* Grab the region so we can find another board if autoIRQ fails. */ - if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { - printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr); - goto freeall; - } - ((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED; + } + else if (dev->irq==2) dev->irq = 9; + } - dev->open = eepro_open; - dev->stop = eepro_close; - dev->hard_start_xmit = eepro_send_packet; - dev->get_stats = eepro_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->tx_timeout = eepro_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Fill in the fields of the device structure with - ethernet generic values */ - ether_setup(dev); + /* Grab the region so we can find another board if autoIRQ fails. */ + if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { + printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n", ioaddr); + goto freeall; + } + ((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED; + + dev->open = eepro_open; + dev->stop = eepro_close; + dev->hard_start_xmit = eepro_send_packet; + dev->get_stats = eepro_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->tx_timeout = eepro_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + /* Fill in the fields of the device structure with + ethernet generic values */ + ether_setup(dev); /* print boot time info */ eepro_print_info(dev); /* reset 82595 */ - eepro_reset(ioaddr); + eepro_reset(ioaddr); exit: return retval; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/irda/irda-usb.c linux.20pre2-ac1/drivers/net/irda/irda-usb.c --- linux.20pre2/drivers/net/irda/irda-usb.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/irda/irda-usb.c 2002-08-13 14:29:57.000000000 +0100 @@ -158,12 +158,12 @@ (!force) && (self->speed != -1)) { /* No speed and xbofs change here * (we'll do it later in the write callback) */ - IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n"); + IRDA_DEBUG(2, "%s(), not changing speed yet\n", __FUNCTION__); *header = 0; return; } - IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed); + IRDA_DEBUG(2, "%s(), changing speed to %d\n", __FUNCTION__, self->new_speed); self->speed = self->new_speed; self->new_speed = -1; @@ -204,7 +204,7 @@ /* Set the negotiated additional XBOFS */ if (self->new_xbofs != -1) { - IRDA_DEBUG(2, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs); + IRDA_DEBUG(2, "%s(), changing xbofs to %d\n", __FUNCTION__, self->new_xbofs); self->xbofs = self->new_xbofs; self->new_xbofs = -1; @@ -248,16 +248,16 @@ { unsigned long flags; __u8 *frame; - struct urb *urb; + struct urb *purb; int ret; - IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n", - self->new_speed, self->new_xbofs); + IRDA_DEBUG(2, "%s(), speed=%d, xbofs=%d\n", + __FUNCTION__, self->new_speed, self->new_xbofs); /* Grab the speed URB */ purb = &self->speed_urb; if (purb->status != USB_ST_NOERROR) { - WARNING(__FUNCTION__ "(), URB still in use!\n"); + WARNING("%s(), URB still in use!\n", __FUNCTION__); return; } @@ -279,7 +279,7 @@ purb->timeout = MSECS_TO_JIFFIES(100); if ((ret = usb_submit_urb(purb))) { - WARNING(__FUNCTION__ "(), failed Speed URB\n"); + WARNING("%s(), failed Speed URB\n", __FUNCTION__); } spin_unlock_irqrestore(&self->lock, flags); } @@ -292,18 +292,18 @@ { struct irda_usb_cb *self = purb->context; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); /* We should always have a context */ if (self == NULL) { - WARNING(__FUNCTION__ "(), Bug : self == NULL\n"); + WARNING("%s(), Bug : self == NULL\n", __FUNCTION__); return; } /* Check for timeout and other USB nasties */ if(purb->status != USB_ST_NOERROR) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, purb->status, purb->transfer_flags); /* Don't do anything here, that might confuse the USB layer. * Instead, we will wait for irda_usb_net_timeout(), the @@ -337,7 +337,7 @@ /* Check if the device is still there */ if ((!self) || (!self->present)) { - IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n"); + IRDA_DEBUG(0, "%s(), Device is gone...\n", __FUNCTION__); return 1; /* Failed */ } @@ -373,7 +373,7 @@ } if (purb->status != USB_ST_NOERROR) { - WARNING(__FUNCTION__ "(), URB still in use!\n"); + WARNING("%s(), URB still in use!\n", __FUNCTION__); dev_kfree_skb(skb); return 0; } @@ -383,9 +383,9 @@ * Also, we don't use directly skb_cow(), because it require * headroom >= 16, which force unnecessary copies - Jean II */ if (skb_headroom(skb) < USB_IRDA_HEADER) { - IRDA_DEBUG(0, __FUNCTION__ "(), Insuficient skb headroom.\n"); + IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__); if (skb_cow(skb, USB_IRDA_HEADER)) { - WARNING(__FUNCTION__ "(), failed skb_cow() !!!\n"); + WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__); dev_kfree_skb(skb); return 0; } @@ -459,7 +459,7 @@ /* Ask USB to send the packet */ if ((res = usb_submit_urb(purb))) { - WARNING(__FUNCTION__ "(), failed Tx URB\n"); + WARNING("%s(), failed Tx URB\n", __FUNCTION__); self->stats.tx_errors++; /* Let USB recover : We will catch that in the watchdog */ /*netif_start_queue(netdev);*/ @@ -484,11 +484,11 @@ struct sk_buff *skb = purb->context; struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); /* We should always have a context */ if (self == NULL) { - WARNING(__FUNCTION__ "(), Bug : self == NULL\n"); + WARNING("%s(), Bug : self == NULL\n", __FUNCTION__); return; } @@ -499,7 +499,7 @@ /* Check for timeout and other USB nasties */ if(purb->status != USB_ST_NOERROR) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, "%s(), URB complete status %d, transfer_flags 0x%04X\n", __FUNCTION__, purb->status, purb->transfer_flags); /* Don't do anything here, that might confuse the USB layer, * and we could go in recursion and blow the kernel stack... @@ -515,13 +515,13 @@ /* If the network is closed, stop everything */ if ((!self->netopen) || (!self->present)) { - IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n"); + IRDA_DEBUG(0, "%s(), Network is gone...\n", __FUNCTION__); return; } /* If we need to change the speed or xbofs, do it now */ if ((self->new_speed != -1) || (self->new_xbofs != -1)) { - IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed now...\n"); + IRDA_DEBUG(1, "%s(), Changing speed now...\n", __FUNCTION__); irda_usb_change_speed_xbofs(self); } else { /* Otherwise, allow the stack to send more packets */ @@ -544,10 +544,10 @@ struct urb *purb; int done = 0; /* If we have made any progress */ - IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n"); + IRDA_DEBUG(0, "%s(), Network layer thinks we timed out!\n", __FUNCTION__); if ((!self) || (!self->present)) { - WARNING(__FUNCTION__ "(), device not present!\n"); + WARNING("%s(), device not present!\n", __FUNCTION__); netif_stop_queue(netdev); return; } @@ -697,11 +697,11 @@ struct irda_skb_cb *cb; int ret; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); /* Check that we have an urb */ if (!purb) { - WARNING(__FUNCTION__ "(), Bug : purb == NULL\n"); + WARNING("%s(), Bug : purb == NULL\n", __FUNCTION__); return; } @@ -711,7 +711,7 @@ if (!skb) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ - WARNING(__FUNCTION__ "(), Failed to allocate Rx skb\n"); + WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__); return; } } else { @@ -741,7 +741,7 @@ if (ret) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ - WARNING(__FUNCTION__ "(), Failed to submit Rx URB %d\n", ret); + WARNING("%s(), Failed to submit Rx URB %d\n", __FUNCTION__, ret); } } @@ -759,7 +759,7 @@ struct irda_skb_cb *cb; struct sk_buff *new; - IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length); + IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, purb->actual_length); /* Find ourselves */ cb = (struct irda_skb_cb *) skb->cb; @@ -769,7 +769,7 @@ /* If the network is closed or the device gone, stop everything */ if ((!self->netopen) || (!self->present)) { - IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n"); + IRDA_DEBUG(0, "%s(), Network is gone!\n", __FUNCTION__); /* Don't re-submit the URB : will stall the Rx path */ return; } @@ -782,13 +782,13 @@ self->stats.rx_crc_errors++; break; case -ECONNRESET: /* -104 */ - IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags); + IRDA_DEBUG(0, "%s(), Connection Reset (-104), transfer_flags 0x%04X \n", __FUNCTION__, purb->transfer_flags); /* uhci_cleanup_unlink() is going to kill the Rx * URB just after we return. No problem, at this * point the URB will be idle ;-) - Jean II */ break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, "%s(), RX status %d,transfer_flags 0x%04X \n", __FUNCTION__, purb->status, purb->transfer_flags); break; } goto done; @@ -796,7 +796,7 @@ /* Check for empty frames */ if (purb->actual_length <= USB_IRDA_HEADER) { - WARNING(__FUNCTION__ "(), empty frame!\n"); + WARNING("%s(), empty frame!\n", __FUNCTION__); goto done; } @@ -900,7 +900,7 @@ */ static int irda_usb_net_init(struct net_device *dev) { - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); /* Set up to be a normal IrDA network device driver */ irda_device_setup(dev); @@ -924,7 +924,7 @@ char hwname[16]; int i; - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; @@ -932,7 +932,7 @@ /* Can only open the device if it's there */ if(!self->present) { - WARNING(__FUNCTION__ "(), device not present!\n"); + WARNING("%s(), device not present!\n", __FUNCTION__); return -1; } @@ -988,7 +988,7 @@ struct irda_usb_cb *self; int i; - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; @@ -1041,7 +1041,7 @@ self = dev->priv; ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); /* Check if the device is still there */ if(!self->present) @@ -1096,7 +1096,7 @@ { struct irda_class_desc *desc; - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); desc = self->irda_desc; @@ -1109,7 +1109,8 @@ self->qos.window_size.bits = desc->bmWindowSize; self->qos.data_size.bits = desc->bmDataSize; - IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits); + IRDA_DEBUG(0, "%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", + __FUNCTION__, self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits); /* Don't always trust what the dongle tell us */ if(self->capability & IUC_SIR_ONLY) @@ -1153,7 +1154,7 @@ struct net_device *netdev; int err; - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); spin_lock_init(&self->lock); @@ -1173,7 +1174,7 @@ /* Create a network device for us */ if (!(netdev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return -1; } self->netdev = netdev; @@ -1193,7 +1194,7 @@ err = register_netdevice(netdev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return -1; } MESSAGE("IrDA: Registered device %s\n", netdev->name); @@ -1208,7 +1209,7 @@ */ static inline int irda_usb_close(struct irda_usb_cb *self) { - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); @@ -1290,12 +1291,13 @@ /* This is our interrupt endpoint */ self->bulk_int_ep = ep; } else { - ERROR(__FUNCTION__ "(), Unrecognised endpoint %02X.\n", ep); + ERROR("%s(), Unrecognised endpoint %02X.\n", __FUNCTION__, ep); } } } - IRDA_DEBUG(0, __FUNCTION__ "(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep); + IRDA_DEBUG(0, "%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", + __FUNCTION__, self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep); /* Should be 8, 16, 32 or 64 bytes */ ASSERT(self->bulk_out_mtu == 64, ;); @@ -1357,7 +1359,7 @@ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500)); - IRDA_DEBUG(1, __FUNCTION__ "(), ret=%d\n", ret); + IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret); if (ret < sizeof(*desc)) { WARNING("usb-irda: class_descriptor read %s (%d)\n", (ret<0) ? "failed" : "too short", ret); @@ -1417,7 +1419,7 @@ if((irda->usbdev != NULL) && (irda->present == 0) && (irda->netopen == 0)) { - IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n"); + IRDA_DEBUG(0, "%s(), found a zombie instance !!!\n", __FUNCTION__); irda_usb_disconnect(irda->usbdev, (void *) irda); } } @@ -1457,10 +1459,10 @@ break; case USB_ST_STALL: /* -EPIPE = -32 */ usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); - IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" ); + IRDA_DEBUG(0, "%s(), Clearing stall on control interface\n", __FUNCTION__); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret); + IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret); return NULL; break; } @@ -1469,7 +1471,7 @@ interface = &dev->actconfig->interface[ifnum].altsetting[0]; if(!irda_usb_parse_endpoints(self, interface->endpoint, interface->bNumEndpoints)) { - ERROR(__FUNCTION__ "(), Bogus endpoints...\n"); + ERROR("%s(), Bogus endpoints...\n", __FUNCTION__); return NULL; } @@ -1500,7 +1502,7 @@ struct irda_usb_cb *self = (struct irda_usb_cb *) ptr; int i; - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); /* Oups ! We are not there any more */ self->present = 0; @@ -1517,7 +1519,7 @@ usb_unlink_urb(&(self->tx_urb)); usb_unlink_urb(&(self->speed_urb)); - IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n"); + IRDA_DEBUG(0, "%s(), postponing disconnect, network is still active...\n", __FUNCTION__); /* better not do anything just yet, usb_irda_cleanup() * will do whats needed */ return; @@ -1527,7 +1529,7 @@ irda_usb_close(self); /* No longer attached to USB bus */ self->usbdev = NULL; - IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n"); + IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __FUNCTION__); } /*------------------------------------------------------------------*/ @@ -1575,7 +1577,7 @@ irda = &irda_instance[i]; /* If the Device is zombie */ if((irda->usbdev != NULL) && (irda->present == 0)) { - IRDA_DEBUG(0, __FUNCTION__ "(), disconnect zombie now !\n"); + IRDA_DEBUG(0, "%s(), disconnect zombie now !\n", __FUNCTION__); irda_usb_disconnect(irda->usbdev, (void *) irda); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/irda/irport.c linux.20pre2-ac1/drivers/net/irda/irport.c --- linux.20pre2/drivers/net/irda/irport.c 2002-08-13 13:58:24.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/irda/irport.c 2002-08-06 15:42:06.000000000 +0100 @@ -126,7 +126,7 @@ { int i; - IRDA_DEBUG( 4, __FUNCTION__ "()\n"); + IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); for (i=0; i < 4; i++) { if (dev_self[i]) @@ -143,15 +143,15 @@ void *ret; int err; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); /* * Allocate new instance of the driver */ self = kmalloc(sizeof(struct irport_cb), GFP_KERNEL); if (!self) { - ERROR(__FUNCTION__ "(), can't allocate memory for " - "control block!\n"); + ERROR("%s(), can't allocate memory for " + "control block!\n", __FUNCTION__); return NULL; } memset(self, 0, sizeof(struct irport_cb)); @@ -171,8 +171,8 @@ /* Lock the port that we need */ ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name); if (!ret) { - IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.sir_base); + IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n", + __FUNCTION__, self->io.sir_base); return NULL; } @@ -215,7 +215,7 @@ self->mode = IRDA_IRLAP; if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return NULL; } self->netdev = dev; @@ -243,7 +243,7 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return NULL; } MESSAGE("IrDA: Registered device %s\n", dev->name); @@ -268,8 +268,8 @@ } /* Release the IO-port that this driver is using */ - IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", - self->io.sir_base); + IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", + __FUNCTION__, self->io.sir_base); release_region(self->io.sir_base, self->io.sir_ext); if (self->tx_buff.head) @@ -332,7 +332,7 @@ */ int irport_probe(int iobase) { - IRDA_DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase); + IRDA_DEBUG(4, "%s(), iobase=%#x\n", __FUNCTION__, iobase); return 0; } @@ -352,7 +352,8 @@ int lcr; /* Line control reg */ int divisor; - IRDA_DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed); + IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", + __FUNCTION__, speed); ASSERT(self != NULL, return;); @@ -407,7 +408,7 @@ __u32 speed = (__u32) task->param; int ret = 0; - IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); + IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); self = (struct irport_cb *) task->instance; @@ -449,8 +450,7 @@ irda_task_next_state(task, IRDA_TASK_CHILD_DONE); break; case IRDA_TASK_CHILD_WAIT: - WARNING(__FUNCTION__ - "(), changing speed of dongle timed out!\n"); + WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__); ret = -1; break; case IRDA_TASK_CHILD_DONE: @@ -460,7 +460,7 @@ irda_task_next_state(task, IRDA_TASK_DONE); break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); ret = -1; break; @@ -483,7 +483,7 @@ ASSERT(self != NULL, return;); - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); iobase = self->io.sir_base; @@ -501,7 +501,7 @@ * if we need to change the speed of the hardware */ if (self->new_speed) { - IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n"); + IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__); irda_task_execute(self, __irport_change_speed, irport_change_speed_complete, NULL, (void *) self->new_speed); @@ -541,7 +541,7 @@ /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n"); + IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __FUNCTION__); return 0; } @@ -566,7 +566,7 @@ { struct irport_cb *self; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); self = (struct irport_cb *) task->instance; @@ -617,7 +617,7 @@ int iobase; s32 speed; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return 0;); @@ -688,7 +688,7 @@ /* Make sure we don't stay here to long */ if (boguscount++ > 32) { - IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n"); + IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__); break; } } while (inb(iobase+UART_LSR) & UART_LSR_DR); @@ -708,7 +708,7 @@ int iir, lsr; if (!dev) { - WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq); + WARNING("%s() irq %d for unknown device.\n", __FUNCTION__, irq); return; } self = (struct irport_cb *) dev->priv; @@ -722,13 +722,12 @@ /* Clear interrupt */ lsr = inb(iobase+UART_LSR); - IRDA_DEBUG(4, __FUNCTION__ - "(), iir=%02x, lsr=%02x, iobase=%#x\n", - iir, lsr, iobase); + IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", + __FUNCTION__, iir, lsr, iobase); switch (iir) { case UART_IIR_RLSI: - IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n"); + IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__); break; case UART_IIR_RDI: /* Receive interrupt */ @@ -740,7 +739,7 @@ irport_write_wakeup(self); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir); + IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir); break; } @@ -775,7 +774,7 @@ int iobase; char hwname[16]; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); self = (struct irport_cb *) dev->priv; @@ -784,8 +783,8 @@ if (request_irq(self->io.irq, self->interrupt, 0, dev->name, (void *) dev)) { - IRDA_DEBUG(0, __FUNCTION__ "(), unable to allocate irq=%d\n", - self->io.irq); + IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", + __FUNCTION__, self->io.irq); return -EAGAIN; } @@ -822,7 +821,7 @@ struct irport_cb *self; int iobase; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); self = (struct irport_cb *) dev->priv; @@ -863,7 +862,7 @@ /* Wait until Tx FIFO is empty */ while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG(2, __FUNCTION__ "(), waiting!\n"); + IRDA_DEBUG(2, "%s(), waiting!\n", __FUNCTION__); current->state = TASK_INTERRUPTIBLE; schedule_timeout(MSECS_TO_JIFFIES(60)); } @@ -918,7 +917,7 @@ /* Tx FIFO should be empty! */ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n"); + IRDA_DEBUG( 0, "%s(), failed, fifo not empty!\n", __FUNCTION__); return -1; } @@ -952,7 +951,7 @@ ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); /* Disable interrupts & save flags */ save_flags(flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/irda/irtty.c linux.20pre2-ac1/drivers/net/irda/irtty.c --- linux.20pre2/drivers/net/irda/irtty.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/irda/irtty.c 2002-08-13 14:30:24.000000000 +0100 @@ -121,9 +121,8 @@ /* Unregister tty line-discipline */ if ((ret = tty_register_ldisc(N_IRDA, NULL))) { - ERROR(__FUNCTION__ - "(), can't unregister line discipline (err = %d)\n", - ret); + ERROR("%s(), can't unregister line discipline (err = %d)\n", + __FUNCTION__, ret); } /* @@ -230,7 +229,7 @@ self->rx_buff.data = self->rx_buff.head; if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return -ENOMEM; } @@ -249,7 +248,7 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return -1; } @@ -352,7 +351,7 @@ cflag &= ~CBAUD; - IRDA_DEBUG(2, __FUNCTION__ "(), Setting speed to %d\n", speed); + IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed); switch (speed) { case 1200: @@ -400,14 +399,14 @@ __u32 speed = (__u32) task->param; int ret = 0; - IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); + IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); self = (struct irtty_cb *) task->instance; ASSERT(self != NULL, return -1;); /* Check if busy */ if (self->task && self->task != task) { - IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n"); + IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__); return MSECS_TO_JIFFIES(10); } else self->task = task; @@ -455,8 +454,7 @@ irda_task_next_state(task, IRDA_TASK_CHILD_DONE); break; case IRDA_TASK_CHILD_WAIT: - WARNING(__FUNCTION__ - "(), changing speed of dongle timed out!\n"); + WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__); ret = -1; break; case IRDA_TASK_CHILD_DONE: @@ -467,7 +465,7 @@ self->task = NULL; break; default: - ERROR(__FUNCTION__ "(), unknown state %d\n", task->state); + ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state); irda_task_next_state(task, IRDA_TASK_DONE); self->task = NULL; ret = -1; @@ -559,7 +557,7 @@ struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; if (!self || !self->netdev) { - IRDA_DEBUG(0, __FUNCTION__ "(), not ready yet!\n"); + IRDA_DEBUG(0, "%s(), not ready yet!\n", __FUNCTION__); return; } @@ -605,7 +603,7 @@ { struct irtty_cb *self; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); self = (struct irtty_cb *) task->instance; @@ -684,7 +682,7 @@ */ static int irtty_receive_room(struct tty_struct *tty) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); return 65536; /* We can handle an infinite amount of data. :-) */ } @@ -719,14 +717,14 @@ * Now serial buffer is almost free & we can start * transmission of another packet */ - IRDA_DEBUG(5, __FUNCTION__ "(), finished with frame!\n"); + IRDA_DEBUG(5, "%s(), finished with frame!\n", __FUNCTION__); self->stats.tx_packets++; tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); if (self->new_speed) { - IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n"); + IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__); irda_task_execute(self, irtty_change_speed, irtty_change_speed_complete, NULL, (void *) self->new_speed); @@ -760,14 +758,11 @@ struct irtty_cb *self; struct tty_struct *tty; mm_segment_t fs; - int arg = 0; + int arg = TIOCM_MODEM_BITS; self = (struct irtty_cb *) dev->priv; tty = self->tty; -#ifdef TIOCM_OUT2 /* Not defined for ARM */ - arg = TIOCM_OUT2; -#endif if (rts) arg |= TIOCM_RTS; if (dtr) @@ -785,7 +780,7 @@ set_fs(get_ds()); if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { - IRDA_DEBUG(2, __FUNCTION__ "(), error doing ioctl!\n"); + IRDA_DEBUG(2, "%s(), error doing ioctl!\n", __FUNCTION__); } set_fs(fs); @@ -808,7 +803,7 @@ ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, __FUNCTION__ "(), mode=%s\n", infrared_mode[mode]); + IRDA_DEBUG(2, "%s(), mode=%s\n", __FUNCTION__, infrared_mode[mode]); /* save status for driver */ self->mode = mode; @@ -901,7 +896,7 @@ ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRTTY_MAGIC, return -1;); - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); /* Ready to play! */ netif_start_queue(dev); @@ -969,7 +964,7 @@ ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRTTY_MAGIC, return -1;); - IRDA_DEBUG(3, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); /* Disable interrupts & save flags */ save_flags(flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/irda/nsc-ircc.c linux.20pre2-ac1/drivers/net/irda/nsc-ircc.c --- linux.20pre2/drivers/net/irda/nsc-ircc.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/irda/nsc-ircc.c 2002-08-13 14:30:33.000000000 +0100 @@ -165,8 +165,8 @@ /* Probe for all the NSC chipsets we know about */ for (chip=chips; chip->name ; chip++) { - IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", - chip->name); + IRDA_DEBUG(2, "%s(), Probing for %s ...\n", + __FUNCTION__, chip->name); /* Try all config registers for this chip */ for (cfg=0; cfg<3; cfg++) { @@ -183,8 +183,8 @@ /* Read index register */ reg = inb(cfg_base); if (reg == 0xff) { - IRDA_DEBUG(2, __FUNCTION__ - "() no chip at 0x%03x\n", cfg_base); + IRDA_DEBUG(2, "%s() no chip at 0x%03x\n", + __FUNCTION__, cfg_base); continue; } @@ -192,9 +192,8 @@ outb(chip->cid_index, cfg_base); id = inb(cfg_base+1); if ((id & chip->cid_mask) == chip->cid_value) { - IRDA_DEBUG(2, __FUNCTION__ - "() Found %s chip, revision=%d\n", - chip->name, id & ~chip->cid_mask); + IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n", + __FUNCTION__, chip->name, id & ~chip->cid_mask); /* * If the user supplies the base address, then * we init the chip, if not we probe the values @@ -209,8 +208,7 @@ ret = 0; i++; } else { - IRDA_DEBUG(2, __FUNCTION__ - "(), Wrong chip id=0x%02x\n", id); + IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id); } } @@ -253,7 +251,7 @@ void *ret; int err; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, info->cfg_base); @@ -266,8 +264,8 @@ /* Allocate new instance of the driver */ self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL); if (self == NULL) { - ERROR(__FUNCTION__ "(), can't allocate memory for " - "control block!\n"); + ERROR("%s(), can't allocate memory for " + "control block!\n", __FUNCTION__); return -ENOMEM; } memset(self, 0, sizeof(struct nsc_ircc_cb)); @@ -288,8 +286,8 @@ /* Reserve the ioports that we need */ ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name); if (!ret) { - WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", - self->io.fir_base); + WARNING("%s(), can't get iobase of 0x%03x\n", + __FUNCTION__, self->io.fir_base); dev_self[i] = NULL; kfree(self); return -ENODEV; @@ -339,7 +337,7 @@ self->tx_fifo.tail = self->tx_buff.head; if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__); return -ENOMEM; } @@ -358,7 +356,7 @@ err = register_netdevice(dev); rtnl_unlock(); if (err) { - ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); return -1; } MESSAGE("IrDA: Registered device %s\n", dev->name); @@ -395,7 +393,7 @@ { int iobase; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); @@ -409,8 +407,8 @@ } /* Release the PORT that this driver is using */ - IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", - self->io.fir_base); + IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", + __FUNCTION__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) @@ -447,7 +445,7 @@ case 0x2e8: outb(0x15, cfg_base+1); break; case 0x3f8: outb(0x16, cfg_base+1); break; case 0x2f8: outb(0x17, cfg_base+1); break; - default: ERROR(__FUNCTION__ "(), invalid base_address"); + default: ERROR("%s(), invalid base_address", __FUNCTION__); } /* Control Signal Routing Register (CSRT) */ @@ -459,7 +457,7 @@ case 9: temp = 0x05; break; case 11: temp = 0x06; break; case 15: temp = 0x07; break; - default: ERROR(__FUNCTION__ "(), invalid irq"); + default: ERROR("%s(), invalid irq", __FUNCTION__); } outb(1, cfg_base); @@ -467,7 +465,7 @@ case 0: outb(0x08+temp, cfg_base+1); break; case 1: outb(0x10+temp, cfg_base+1); break; case 3: outb(0x18+temp, cfg_base+1); break; - default: ERROR(__FUNCTION__ "(), invalid dma"); + default: ERROR("%s(), invalid dma", __FUNCTION__); } outb(2, cfg_base); /* Mode Control Register (MCTL) */ @@ -506,8 +504,8 @@ break; } info->sir_base = info->fir_base; - IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", - info->fir_base); + IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", + __FUNCTION__, info->fir_base); /* Read control signals routing register (CSRT) */ outb(CFG_CSRT, cfg_base); @@ -539,7 +537,7 @@ info->irq = 15; break; } - IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq); + IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq); /* Currently we only read Rx DMA but it will also be used for Tx */ switch ((reg >> 3) & 0x03) { @@ -556,7 +554,7 @@ info->dma = 3; break; } - IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma); + IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma); /* Read mode control register (MCTL) */ outb(CFG_MCTL, cfg_base); @@ -805,39 +803,39 @@ switch (dongle_id) { case 0x00: /* same as */ case 0x01: /* Differential serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x02: /* same as */ case 0x03: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x04: /* Sharp RY5HD01 */ break; case 0x05: /* Reserved, but this is what the Thinkpad reports */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x06: /* Single-ended serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x07: /* Consumer-IR only */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ outb(0x28, iobase+7); /* Set irsl[0-2] as output */ break; case 0x0A: /* same as */ case 0x0B: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x0C: /* same as */ case 0x0D: /* HP HSDL-1100/HSDL-2100 */ @@ -851,15 +849,15 @@ outb(0x28, iobase+7); /* Set irsl[0-2] as output */ break; case 0x0F: /* No dongle connected */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s\n", + __FUNCTION__, dongle_types[dongle_id]); switch_bank(iobase, BANK0); outb(0x62, iobase+MCR); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", - dongle_id); + IRDA_DEBUG(0, "%s(), invalid dongle_id %#x", + __FUNCTION__, dongle_id); } /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ @@ -891,31 +889,31 @@ switch (dongle_id) { case 0x00: /* same as */ case 0x01: /* Differential serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x02: /* same as */ case 0x03: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x04: /* Sharp RY5HD01 */ break; case 0x05: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x06: /* Single-ended serial interface */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x07: /* Consumer-IR only */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s\n", + __FUNCTION__, dongle_types[dongle_id]); outb(0x00, iobase+4); if (speed > 115200) outb(0x01, iobase+4); @@ -934,8 +932,8 @@ break; case 0x0A: /* same as */ case 0x0B: /* Reserved */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n", + __FUNCTION__, dongle_types[dongle_id]); break; case 0x0C: /* same as */ case 0x0D: /* HP HSDL-1100/HSDL-2100 */ @@ -943,14 +941,14 @@ case 0x0E: /* Supports SIR Mode only */ break; case 0x0F: /* No dongle connected */ - IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n", - dongle_types[dongle_id]); + IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n", + __FUNCTION__, dongle_types[dongle_id]); switch_bank(iobase, BANK0); outb(0x62, iobase+MCR); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n"); + IRDA_DEBUG(0, "%s(), invalid data_rate\n", __FUNCTION__); } /* Restore bank register */ outb(bank, iobase+BSR); @@ -969,7 +967,7 @@ int iobase; __u8 bank; - IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed); + IRDA_DEBUG(2, "%s(), speed=%d\n", __FUNCTION__, speed); ASSERT(self != NULL, return;); @@ -1002,20 +1000,20 @@ outb(inb(iobase+4) | 0x04, iobase+4); mcr = MCR_MIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n"); + IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__); break; case 1152000: mcr = MCR_MIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n"); + IRDA_DEBUG(0, "%s(), handling baud of 1152000\n", __FUNCTION__); break; case 4000000: mcr = MCR_FIR; - IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); + IRDA_DEBUG(0, "%s(), handling baud of 4000000\n", __FUNCTION__); break; default: mcr = MCR_FIR; - IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", - speed); + IRDA_DEBUG(0, "%s(), unknown baud rate of %d\n", + __FUNCTION__, speed); break; } @@ -1278,15 +1276,14 @@ int actual = 0; __u8 bank; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); /* Save current bank */ bank = inb(iobase+BSR); switch_bank(iobase, BANK0); if (!(inb_p(iobase+LSR) & LSR_TXEMP)) { - IRDA_DEBUG(4, __FUNCTION__ - "(), warning, FIFO not empty yet!\n"); + IRDA_DEBUG(4, "%s(), warning, FIFO not empty yet!\n", __FUNCTION__); /* FIFO may still be filled to the Tx interrupt threshold */ fifo_size -= 17; @@ -1298,8 +1295,8 @@ outb(buf[actual++], iobase+TXD); } - IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", - fifo_size, actual, len); + IRDA_DEBUG(4, "%s(), fifo_size %d ; %d sent of %d\n", + __FUNCTION__, fifo_size, actual, len); /* Restore bank */ outb(bank, iobase+BSR); @@ -1320,7 +1317,7 @@ __u8 bank; int ret = TRUE; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); iobase = self->io.fir_base; @@ -1456,7 +1453,7 @@ len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); if (st_fifo->tail >= MAX_RX_WINDOW) { - IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n"); + IRDA_DEBUG(0, "%s(), window is full!\n", __FUNCTION__); continue; } @@ -1546,8 +1543,8 @@ skb = dev_alloc_skb(len+1); if (skb == NULL) { - WARNING(__FUNCTION__ "(), memory squeeze, " - "dropping frame.\n"); + WARNING("%s(), memory squeeze, " + "dropping frame.\n", __FUNCTION__); self->stats.rx_dropped++; /* Restore bank register */ @@ -1643,7 +1640,7 @@ if (eir & EIR_TXEMP_EV) { /* Check if we need to change the speed? */ if (self->new_speed) { - IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n"); + IRDA_DEBUG(2, "%s(), Changing speed!\n", __FUNCTION__); nsc_ircc_change_speed(self, self->new_speed); self->new_speed = 0; @@ -1822,7 +1819,7 @@ */ static int nsc_ircc_net_init(struct net_device *dev) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); /* Setup to be a normal IrDA network device driver */ irda_device_setup(dev); @@ -1845,7 +1842,7 @@ char hwname[32]; __u8 bank; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); self = (struct nsc_ircc_cb *) dev->priv; @@ -1909,7 +1906,7 @@ int iobase; __u8 bank; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(dev != NULL, return -1;); @@ -1965,7 +1962,7 @@ ASSERT(self != NULL, return -1;); - IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); /* Disable interrupts & save flags */ save_flags(flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/pcnet32.c linux.20pre2-ac1/drivers/net/pcnet32.c --- linux.20pre2/drivers/net/pcnet32.c 2002-08-13 13:58:24.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/pcnet32.c 2002-08-06 15:42:06.000000000 +0100 @@ -1,5 +1,5 @@ -/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */ -/* +/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. + * * Copyright 1996-1999 Thomas Bogendoerfer * * Derived from the lance driver written 1993,1994,1995 by Donald Becker. @@ -543,7 +543,7 @@ /* initialize variables */ fdx = mii = fset = dxsuflo = ltint = 0; chip_version = (chip_version >> 12) & 0xffff; - + switch (chip_version) { case 0x2420: chipname = "PCnet/PCI 79C970"; /* PCI */ @@ -1175,19 +1175,12 @@ if (err_status & 0x04000000) lp->stats.tx_aborted_errors++; if (err_status & 0x08000000) lp->stats.tx_carrier_errors++; if (err_status & 0x10000000) lp->stats.tx_window_errors++; -#ifndef DO_DXSUFLO if (err_status & 0x40000000) { lp->stats.tx_fifo_errors++; - /* Ackk! On FIFO errors the Tx unit is turned off! */ - /* Remove this verbosity later! */ - printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n", - dev->name, csr0); - must_restart = 1; - } -#else - if (err_status & 0x40000000) { - lp->stats.tx_fifo_errors++; - if (! lp->dxsuflo) { /* If controller doesn't recover ... */ +#ifdef DO_DXSUFLO + if (! lp->dxsuflo) +#endif + { /* If controller doesn't recover ... */ /* Ackk! On FIFO errors the Tx unit is turned off! */ /* Remove this verbosity later! */ printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n", @@ -1195,7 +1188,6 @@ must_restart = 1; } } -#endif } else { if (status & 0x1800) lp->stats.collisions++; @@ -1722,12 +1714,13 @@ } } + module_init(pcnet32_init_module); module_exit(pcnet32_cleanup_module); /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c" + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include/linux -Wall -Wstrict-prototypes -O2 -m486 -c pcnet32.c" * c-indent-level: 4 * tab-width: 8 * End: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/slip.c linux.20pre2-ac1/drivers/net/slip.c --- linux.20pre2/drivers/net/slip.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/slip.c 2002-08-06 15:42:06.000000000 +0100 @@ -1393,10 +1393,8 @@ /* First of all: check for active disciplines and hangup them. */ do { - if (busy) { - current->counter = 0; - schedule(); - } + if (busy) + sys_sched_yield(); busy = 0; local_bh_disable(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/tulip/eeprom.c linux.20pre2-ac1/drivers/net/tulip/eeprom.c --- linux.20pre2/drivers/net/tulip/eeprom.c 2002-08-13 13:58:24.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/tulip/eeprom.c 2002-08-06 15:42:06.000000000 +0100 @@ -136,6 +136,48 @@ subsequent_board: if (ee_data[27] == 0) { /* No valid media table. */ +#ifdef __hppa__ + /* + * HSC-PCI cards don't have a standard srom, + * but we need to setup a fake mediatable + * for a correct csr12 setup and mii handling + */ + if (ee_data[0] == 0x3c && ee_data[1] == 0x10 && /* sub vendor id */ + ee_data[2] == 0x63 && ee_data[3] == 0x10) { /* sub device id */ + static unsigned char leafdata[] = + { 0x01, /* phy number */ + 0x02, /* gpr setup sequence length */ + 0x02, 0x00, /* gpr setup sequence */ + 0x02, /* phy reset sequence length */ + 0x01, 0x00, /* phy reset sequence */ + 0x00, 0x78, /* media capabilities */ + 0x00, 0xe0, /* nway advertisment */ + 0x00, 0x05, /* fdx bit map */ + 0x00, 0x06 /* ttm bit map */ + }; + struct mediatable *mtable; + + mtable = (struct mediatable *) + kmalloc(sizeof(struct mediatable) + sizeof(struct medialeaf), + GFP_KERNEL); + if (mtable == NULL) + return; /* Horrible, impossible failure. */ + + tp->mtable = mtable; + mtable->defaultmedia = 0x800; + mtable->leafcount = 1; + mtable->csr12dir = 0x3f; /* inputs on bit7 for hsc-pci, bit6 for pci-fx */ + mtable->has_nonmii = 0; + mtable->has_reset = 0; + mtable->has_mii = 1; + mtable->csr15dir = mtable->csr15val = 0; + mtable->mleaf[0].type = 1; + mtable->mleaf[0].media = 11; + mtable->mleaf[0].leafdata = &leafdata[0]; + tp->flags |= HAS_PHY_IRQ; + tp->csr12_shadow = -1; + } +#endif } else if (tp->chip_id == DC21041) { unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; int media = get_u16(p); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/tulip/interrupt.c linux.20pre2-ac1/drivers/net/tulip/interrupt.c --- linux.20pre2/drivers/net/tulip/interrupt.c 2002-08-13 13:58:24.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/tulip/interrupt.c 2002-08-06 15:42:06.000000000 +0100 @@ -291,6 +291,23 @@ #endif } +static inline void phy_interrupt (struct net_device *dev, struct tulip_private *tp, long ioaddr) +{ + int csr12; + + csr12 = inl(ioaddr + CSR12) & 0xff; + if (csr12 != tp->csr12_shadow) { + /* ack interrupt */ + outl(csr12 | 0x02, ioaddr + CSR12); + tp->csr12_shadow = csr12; + /* do link change stuff */ + spin_lock(&tp->lock); + tulip_check_duplex(dev); + spin_unlock(&tp->lock); + /* clear irq ack bit */ + outl(csr12 & ~0x02, ioaddr + CSR12); + } +} /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -313,6 +330,10 @@ /* Let's see whether the interrupt really is for us */ csr5 = inl(ioaddr + CSR5); + + if (tp->flags & HAS_PHY_IRQ) + phy_interrupt (dev, tp, ioaddr); + if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/tulip/media.c linux.20pre2-ac1/drivers/net/tulip/media.c --- linux.20pre2/drivers/net/tulip/media.c 2002-08-13 13:58:24.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/tulip/media.c 2002-08-06 15:42:06.000000000 +0100 @@ -284,6 +284,10 @@ for (i = 0; i < init_length; i++) outl(init_sequence[i], ioaddr + CSR12); } + + inl(ioaddr + CSR6); /* flush posted writes */ + udelay(500); + tmp_info = get_u16(&misc_info[1]); if (tmp_info) tp->advertising[phy_num] = tmp_info | 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/tulip/tulip.h linux.20pre2-ac1/drivers/net/tulip/tulip.h --- linux.20pre2/drivers/net/tulip/tulip.h 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/tulip/tulip.h 2002-08-14 14:41:30.000000000 +0100 @@ -63,6 +63,7 @@ HAS_8023X = 0x0400, COMET_MAC_ADDR = 0x0800, HAS_PCI_MWI = 0x1000, + HAS_PHY_IRQ = 0x2000, }; @@ -388,7 +389,8 @@ int susp_rx; unsigned long nir; unsigned long base_addr; - int pad0, pad1; /* Used for 8-byte alignment */ + int csr12_shadow; + int pad1; /* Used for 8-byte alignment */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/via-rhine.c linux.20pre2-ac1/drivers/net/via-rhine.c --- linux.20pre2/drivers/net/via-rhine.c 2002-08-13 13:58:24.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/via-rhine.c 2002-08-06 15:42:06.000000000 +0100 @@ -93,6 +93,10 @@ - transmit frame queue message is off by one - fixed - adds IntrNormalSummary to "Something Wicked" exclusion list so normal interrupts will not trigger the message (src: Donald Becker) + (Roger Luethi) + - show confused chip where to continue after Tx error + - location of collision counter is chip specific + - allow selecting backoff algorithm (module parameter) */ @@ -111,6 +115,9 @@ Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; +/* Select a backoff algorithm (Ethernet capture effect) */ +static int backoff; + /* Used to pass the media type, etc. Both 'options[]' and 'full_duplex[]' should exist for driver interoperability. @@ -213,11 +220,13 @@ MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(backoff, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm"); MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex"); MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)"); @@ -234,7 +243,8 @@ Boards with this chip are functional only in a bus-master PCI slot. Many operational settings are loaded from the EEPROM to the Config word at -offset 0x78. This driver assumes that they are correct. +offset 0x78. For most of these settings, this driver assumes that they are +correct. If this driver is compiled to use PCI memory space operations the EEPROM must be configured to enable memory ops. @@ -386,9 +396,10 @@ StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC, }; -/* Bits in ConfigD (select backoff algorithm (Ethernet capture effect)) */ +/* Bits in ConfigD */ enum backoff_bits { - BackOpt=0x01, BackAMD=0x02, BackDEC=0x04, BackRandom=0x08 + BackOptional=0x01, BackModify=0x02, + BackCaptureEffect=0x04, BackRandom=0x08 }; #ifdef USE_MEM @@ -402,7 +413,7 @@ /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, - IntrTxDone=0x0002, IntrTxAbort=0x0008, IntrTxUnderrun=0x0010, + IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0010, IntrPCIErr=0x0040, IntrStatsMax=0x0080, IntrRxEarly=0x0100, IntrMIIChange=0x0200, IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, @@ -428,24 +439,27 @@ /* The Rx and Tx buffer descriptors. */ struct rx_desc { s32 rx_status; - u32 desc_length; + u32 desc_length; /* Chain flag, Buffer/frame length */ u32 addr; u32 next_desc; }; struct tx_desc { s32 tx_status; - u32 desc_length; + u32 desc_length; /* Chain flag, Tx Config, Frame length */ u32 addr; u32 next_desc; }; +/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */ +#define TXDESC 0x00e08000 + enum rx_status_bits { RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F }; -/* Bits in *_desc.status */ +/* Bits in *_desc.*_status */ enum desc_status_bits { - DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000, + DescOwn=0x80000000 }; /* Bits in ChipCmd. */ @@ -517,6 +531,7 @@ static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int via_rhine_close(struct net_device *dev); static inline void clear_tally_counters(long ioaddr); +static inline void via_restart_tx(struct net_device *dev); static void wait_for_reset(struct net_device *dev, int chip_id, char *name) { @@ -703,6 +718,11 @@ writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); } + /* Select backoff algorithm */ + if (backoff) + writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff), + ioaddr + ConfigD); + dev->irq = pdev->irq; np = dev->priv; @@ -937,7 +957,7 @@ for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].desc_length = cpu_to_le32(TXDESC); next += sizeof(struct tx_desc); np->tx_ring[i].next_desc = cpu_to_le32(next); np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ]; @@ -953,7 +973,7 @@ for (i = 0; i < TX_RING_SIZE; i++) { np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].desc_length = cpu_to_le32(TXDESC); np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (np->tx_skbuff[i]) { if (np->tx_skbuff_dma[i]) { @@ -978,7 +998,7 @@ writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers. */ - writew(0x0006, ioaddr + PCIBusConfig); /* Store & forward */ + writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ /* Configure initial FIFO thresholds. */ writeb(0x20, ioaddr + TxConfig); np->tx_thresh = 0x20; @@ -993,8 +1013,9 @@ via_rhine_set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ - writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| - IntrTxDone | IntrTxAbort | IntrTxUnderrun | + writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | + IntrRxDropped | IntrRxNoBuf | IntrTxAborted | + IntrTxDone | IntrTxError | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange, ioaddr + IntrEnable); @@ -1237,7 +1258,7 @@ } np->tx_ring[entry].desc_length = - cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); /* lock eth irq */ spin_lock_irq (&np->lock); @@ -1289,13 +1310,14 @@ IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) via_rhine_rx(dev); - if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun | + if (intr_status & (IntrTxDone | IntrTxError | IntrTxUnderrun | IntrTxAborted)) via_rhine_tx(dev); /* Abnormal error summary/uncommon events handlers. */ if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange | - IntrStatsMax | IntrTxAbort | IntrTxUnderrun)) + IntrStatsMax | IntrTxError | IntrTxAborted | + IntrTxUnderrun)) via_rhine_error(dev, intr_status); if (--boguscnt < 0) { @@ -1307,7 +1329,7 @@ } if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + printk(KERN_DEBUG "%s: exiting interrupt, status=%4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); } @@ -1323,11 +1345,11 @@ /* find and cleanup dirty tx descriptors */ while (np->dirty_tx != np->cur_tx) { txstatus = le32_to_cpu(np->tx_ring[entry].tx_status); - if (txstatus & DescOwn) - break; if (debug > 6) printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n", entry, txstatus); + if (txstatus & DescOwn) + break; if (txstatus & 0x8000) { if (debug > 1) printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", @@ -1337,10 +1359,22 @@ if (txstatus & 0x0200) np->stats.tx_window_errors++; if (txstatus & 0x0100) np->stats.tx_aborted_errors++; if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++; - if (txstatus & 0x0002) np->stats.tx_fifo_errors++; + if (((np->chip_id == VT86C100A) && txstatus & 0x0002) || + (txstatus & 0x0800) || (txstatus & 0x1000)) { + np->stats.tx_fifo_errors++; + np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); + break; /* Keep the skb - we try again */ + } /* Transmitter restarted in 'abnormal' handler. */ } else { - np->stats.collisions += (txstatus >> 3) & 15; + if (np->chip_id == VT86C100A) + np->stats.collisions += (txstatus >> 3) & 0x0F; + else + np->stats.collisions += txstatus & 0x0F; + if (debug > 6) + printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n", + (txstatus >> 3) & 0xF, + txstatus & 0xF); np->stats.tx_bytes += np->tx_skbuff[entry]->len; np->stats.tx_packets++; } @@ -1476,6 +1510,17 @@ writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd); } +static inline void via_restart_tx(struct net_device *dev) { + struct netdev_private *np = dev->priv; + int entry = np->dirty_tx % TX_RING_SIZE; + + /* We know better than the chip where it should continue */ + writel(np->tx_ring_dma + entry * sizeof(struct tx_desc), + dev->base_addr + TxRingPtr); + + writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); +} + static void via_rhine_error(struct net_device *dev, int intr_status) { struct netdev_private *np = dev->priv; @@ -1501,19 +1546,23 @@ np->stats.rx_missed_errors += readw(ioaddr + RxMissed); clear_tally_counters(ioaddr); } - if (intr_status & IntrTxAbort) { - /* Stats counted in Tx-done handler, just restart Tx. */ - writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); + if (intr_status & IntrTxError) { + if (debug > 1) + printk(KERN_INFO "%s: Abort %4.4x, frame dropped.\n", + dev->name, intr_status); + via_restart_tx(dev); } if (intr_status & IntrTxUnderrun) { if (np->tx_thresh < 0xE0) writeb(np->tx_thresh += 0x20, ioaddr + TxConfig); if (debug > 1) - printk(KERN_INFO "%s: Transmitter underrun, increasing Tx " - "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); + printk(KERN_INFO "%s: Transmitter underrun, Tx " + "threshold now %2.2x.\n", + dev->name, np->tx_thresh); + via_restart_tx(dev); } if (intr_status & ~( IntrLinkChange | IntrStatsMax | - IntrTxAbort | IntrTxAborted | IntrNormalSummary)) { + IntrTxError | IntrTxAborted | IntrNormalSummary)) { if (debug > 1) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/wan/8253x/sab8253xds.txt linux.20pre2-ac1/drivers/net/wan/8253x/sab8253xds.txt --- linux.20pre2/drivers/net/wan/8253x/sab8253xds.txt 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/wan/8253x/sab8253xds.txt 2002-08-06 15:42:06.000000000 +0100 @@ -92,7 +92,7 @@ -*ln ^Ös /home/martillo/kernel/linux-2.4.3/include/asm-i386 +*ln –s /home/martillo/kernel/linux-2.4.3/include/asm-i386 /home/martillo/kernel/linux-2.4.3/include/asm* * * @@ -101,12 +101,12 @@ * * -*ln ^Ös /home/martillo/kernel/linux-2.4.6/include/asm-i386 +*ln –s /home/martillo/kernel/linux-2.4.6/include/asm-i386 /home/martillo/kernel/linux-2.4.6/include/asm* * * -*ln ^Ös / /frolix * +*ln –s / /frolix * @@ -173,7 +173,7 @@ From a shell window: -*xemacs ^Öe shell&* +*xemacs –e shell&* @@ -854,7 +854,7 @@ -patch ^Öp1 < /{directory-patch}//8253x.patch +patch –p1 < /{directory-patch}//8253x.patch @@ -1051,7 +1051,7 @@ - The ASLX driver is designed to be a ^Óplug-and-play^Ô driver as far as + The ASLX driver is designed to be a “plug-and-play” driver as far as possible. If it is built as a dynamically loadable module, the user (or relevant system configuration file) invokes /insmod /to load the ASLX.o file. @@ -1169,7 +1169,7 @@ -cu ^Öl /dev/ttyS{n} ^Ös 9600 +cu –l /dev/ttyS{n} –s 9600 @@ -1281,7 +1281,7 @@ -cu ^Öl /dev/sttyS{n} ^Ös 9600 +cu –l /dev/sttyS{n} –s 9600 @@ -1289,7 +1289,7 @@ -8253xcfg /dev/sttyS? ^Ön 64 152 0 4 0 140 15 +8253xcfg /dev/sttyS? –n 64 152 0 4 0 140 15 @@ -1658,7 +1658,7 @@ The 8253xcfg command provides access to images of the channel control, mode and baud rate generator registers of the serial port that is specified by the minor device number (port number = minor device number -^Ö minor_start) of the TTY device (either synchronous, asynchronous or +– minor_start) of the TTY device (either synchronous, asynchronous or callout) specified on the command line by which 8253xcfg is invoked. The next time the port is initialized (usually on the first open after every process that currently has the port open has closed it) these @@ -2691,37 +2691,37 @@ -1. SAB_BOARD structure ^Ö driver specific +1. SAB_BOARD structure – driver specific -2. SAB_CHIP structure ^Ö driver specific +2. SAB_CHIP structure – driver specific -3. SAB_PORT structure ^Ö driver specific +3. SAB_PORT structure – driver specific -4. AURA_CIM structure ^Ö driver specific (actually specific to the +4. AURA_CIM structure – driver specific (actually specific to the multichannel server) -5. RING_DESCRIPTOR ^Ö used by all the driver functionalities in the +5. RING_DESCRIPTOR – used by all the driver functionalities in the transmission of data. -6. DCONTROL2 ^Ö used by all the driver functionalities in managing +6. DCONTROL2 – used by all the driver functionalities in managing the transmission of data. -7. struct sk_buff_head ^Ö two buffer lists are associated with the +7. struct sk_buff_head – two buffer lists are associated with the SAB_PORT structure are used to track all the sk_buffs that are currently in use at each port. -8. struct tty_struct ^Ö one per port, standard structure by which +8. struct tty_struct – one per port, standard structure by which the TTY driver access low level routines for either asynchronous TTY, synchronous TTY and callout functionality. The SAB_PORT serves as the private data structure associated with each 8253x TTY, which on a given open can instantiate itself as a synchronous TTY, an asynchronous TTY or as a call out device. -9. struct net_device ^Ö one per port, standard network device +9. struct net_device – one per port, standard network device structure. The SAB_PORT serves as the private data structure associated with each 8253x network interface. -10. struct file_operations ^Ö one per port, standard character device +10. struct file_operations – one per port, standard character device structure. The SAB_PORT serves as the private data structure associated with each 8253x character interface. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/net/wan/8253x/sab8253xfs.txt linux.20pre2-ac1/drivers/net/wan/8253x/sab8253xfs.txt --- linux.20pre2/drivers/net/wan/8253x/sab8253xfs.txt 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/drivers/net/wan/8253x/sab8253xfs.txt 2002-08-06 15:42:06.000000000 +0100 @@ -44,7 +44,7 @@ to the driver. The ASLX driver will automatically correct incorrectly programmed adapter card or Multichannel server serial EEPROMs. Moreover, in addition to the primary serial communications interface, -the ASLX driver provides a ^Ómaintenance^Ô interface to the serial EEPROMs +the ASLX driver provides a “maintenance” interface to the serial EEPROMs so that user intervention can correct an incorrectly programmed EEPROM. @@ -336,7 +336,7 @@ -Synchronous TTYs act just like asynchronous TTYs (e.g., getty^Òs may be +Synchronous TTYs act just like asynchronous TTYs (e.g., getty’s may be associated with them, and a user may invoke cu on them) in so far as possible (to wit, break processing is not possible on a synchronous TTY). @@ -536,7 +536,7 @@ In a sense, the synchronous character device implements an emulation of -Solaris putmsg/getmsg functionality for Aurora^Òs synchronous serial +Solaris putmsg/getmsg functionality for Aurora’s synchronous serial device. The availability of such emulation should help the portation of applications from Solaris to a Linux platform that uses Aurora hardware and software. @@ -586,7 +586,7 @@ Linux is not capable of registering an interrupt handler for each port -separately (when there are many ports ^Ö the specialty of Aurora +separately (when there are many ports – the specialty of Aurora hardware), and such an approach would have lower performance than having a single interrupt handler that polled the ports. In any case, interrupt status registers associated with the Aurora hardware often diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/pci/pci.c linux.20pre2-ac1/drivers/pci/pci.c --- linux.20pre2/drivers/pci/pci.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/pci/pci.c 2002-08-09 11:05:02.000000000 +0100 @@ -358,25 +358,41 @@ } /** - * pci_enable_device - Initialize device before it's used by a driver. + * pci_enable_device_bars - Initialize some of a device for use * @dev: PCI device to be initialized + * @bars: bitmask of BAR's that must be configured * * Initialize device before it's used by a driver. Ask low-level code - * to enable I/O and memory. Wake up the device if it was suspended. - * Beware, this function can fail. + * to enable selected I/O and memory resources. Wake up the device if it + * was suspended. Beware, this function can fail. */ + int -pci_enable_device(struct pci_dev *dev) +pci_enable_device_bars(struct pci_dev *dev, int bars) { int err; pci_set_power_state(dev, 0); - if ((err = pcibios_enable_device(dev)) < 0) + if ((err = pcibios_enable_device(dev, bars)) < 0) return err; return 0; } /** + * pci_enable_device - Initialize device before it's used by a driver. + * @dev: PCI device to be initialized + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O and memory. Wake up the device if it was suspended. + * Beware, this function can fail. + */ +int +pci_enable_device(struct pci_dev *dev) +{ + return pci_enable_device_bars(dev, 0x3F); +} + +/** * pci_disable_device - Disable PCI device after use * @dev: PCI device to be disabled * @@ -1629,7 +1645,7 @@ return error; } -static int pci_pm_suspend(u32 state) +int pci_pm_suspend(u32 state) { struct list_head *list; struct pci_bus *bus; @@ -1642,7 +1658,7 @@ return 0; } -static int pci_pm_resume(void) +int pci_pm_resume(void) { struct list_head *list; struct pci_bus *bus; @@ -2066,6 +2082,7 @@ EXPORT_SYMBOL(pci_write_config_dword); EXPORT_SYMBOL(pci_devices); EXPORT_SYMBOL(pci_root_buses); +EXPORT_SYMBOL(pci_enable_device_bars); EXPORT_SYMBOL(pci_enable_device); EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_find_capability); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/pci/pci.ids linux.20pre2-ac1/drivers/pci/pci.ids --- linux.20pre2/drivers/pci/pci.ids 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/pci/pci.ids 2002-08-06 17:04:21.000000000 +0100 @@ -2946,11 +2946,17 @@ 0009 CNB20LE Host Bridge 0010 CIOB30 0011 CMIC-HE + 0017 GCNB-LE Host Bridge 0200 OSB4 South Bridge 0201 CSB5 South Bridge + 0203 CSB6 South Bridge 0211 OSB4 IDE Controller 0212 CSB5 IDE Controller - 0220 OSB4/CSB5 USB Controller + 0213 CSB6 RAID/IDE Controller + 0220 OSB4/CSB5 OHCI USB Controller + 0221 CSB6 OHCI USB Controller + 0225 GCLE Host Bridge + 0227 GCLE-2 Host Bridge 1167 Mutoh Industries Inc 1168 Thine Electronics Inc 1169 Centre for Development of Advanced Computing diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/pnp/Config.in linux.20pre2-ac1/drivers/pnp/Config.in --- linux.20pre2/drivers/pnp/Config.in 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/pnp/Config.in 2002-08-06 15:42:11.000000000 +0100 @@ -8,4 +8,8 @@ dep_tristate ' ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_bool ' PNPBIOS support (EXPERIMENTAL)' CONFIG_PNPBIOS $CONFIG_PNP +fi + endmenu diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/pnp/isapnp.c linux.20pre2-ac1/drivers/pnp/isapnp.c --- linux.20pre2/drivers/pnp/isapnp.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/pnp/isapnp.c 2002-08-06 15:42:11.000000000 +0100 @@ -28,6 +28,8 @@ * 2001-11-07 Added isapnp_{,un}register_driver calls along the lines * of the pci driver interface * Kai Germaschewski + * 2002-06-06 Made the use of dma channel 0 configurable + * Gerald Teschl */ #include @@ -59,6 +61,7 @@ int isapnp_disable; /* Disable ISA PnP */ int isapnp_rdp; /* Read Data Port */ int isapnp_reset = 1; /* reset all PnP cards (deactivate) */ +int isapnp_allow_dma0 = -1; /* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */ int isapnp_skip_pci_scan; /* skip PCI resource scanning */ int isapnp_verbose = 1; /* verbose mode */ int isapnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */ @@ -74,6 +77,8 @@ MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port"); MODULE_PARM(isapnp_reset, "i"); MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards"); +MODULE_PARM(isapnp_allow_dma0, "i"); +MODULE_PARM_DESC(isapnp_allow_dma0, "Allow dma value 0 during auto activation"); MODULE_PARM(isapnp_skip_pci_scan, "i"); MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning"); MODULE_PARM(isapnp_verbose, "i"); @@ -1750,13 +1755,14 @@ static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx) { - int i; + int i, mindma =1; struct pci_dev *dev; /* Some machines allow DMA 0, but others don't. In fact on some boxes DMA 0 is the memory refresh. Play safe */ - - if (dma < 1 || dma == 4 || dma > 7) + if (isapnp_allow_dma0 == 1) + mindma = 0; + if (dma < mindma || dma == 4 || dma > 7) return 1; for (i = 0; i < 8; i++) { if (isapnp_reserve_dma[i] == dma) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/pnp/isapnp_proc.c linux.20pre2-ac1/drivers/pnp/isapnp_proc.c --- linux.20pre2/drivers/pnp/isapnp_proc.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/pnp/isapnp_proc.c 2002-08-06 15:42:11.000000000 +0100 @@ -944,6 +944,22 @@ res->start = res->end = dma; res->flags = IORESOURCE_DMA; } + +extern int isapnp_allow_dma0; +static int isapnp_set_allow_dma0(char *line) +{ + int i; + char value[32]; + + isapnp_get_str(value, line, sizeof(value)); + i = simple_strtoul(value, NULL, 0); + if (i < 0 || i > 1) { + printk("isapnp: wrong value %i for allow_dma0\n", i); + return 1; + } + isapnp_allow_dma0 = i; + return 0; +} static int isapnp_set_dma(char *line) { @@ -1030,6 +1046,8 @@ char cmd[32]; line = isapnp_get_str(cmd, line, sizeof(cmd)); + if (!strcmp(cmd, "allow_dma0")) + return isapnp_set_allow_dma0(line); if (!strcmp(cmd, "card")) return isapnp_set_card(line); if (!strcmp(cmd, "csn")) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/pnp/Makefile linux.20pre2-ac1/drivers/pnp/Makefile --- linux.20pre2/drivers/pnp/Makefile 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/pnp/Makefile 2002-08-06 15:42:11.000000000 +0100 @@ -10,15 +10,22 @@ O_TARGET := pnp.o -export-objs := isapnp.o -list-multi := isa-pnp.o +export-objs := isapnp.o pnpbios_core.o +multi-objs := isa-pnp.o pnpbios.o -proc-$(CONFIG_PROC_FS) = isapnp_proc.o -isa-pnp-objs := isapnp.o quirks.o $(proc-y) +isa-pnp-proc-$(CONFIG_PROC_FS) = isapnp_proc.o +pnpbios-proc-$(CONFIG_PROC_FS) = pnpbios_proc.o + +isa-pnp-objs := isapnp.o quirks.o $(isa-pnp-proc-y) +pnpbios-objs := pnpbios_core.o $(pnpbios-proc-y) obj-$(CONFIG_ISAPNP) += isa-pnp.o +obj-$(CONFIG_PNPBIOS) += pnpbios.o include $(TOPDIR)/Rules.make isa-pnp.o: $(isa-pnp-objs) $(LD) $(LD_RFLAG) -r -o $@ $(isa-pnp-objs) + +pnpbios.o: $(pnpbios-objs) + $(LD) $(LD_RFLAG) -r -o $@ $(pnpbios-objs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/pnp/pnpbios_core.c linux.20pre2-ac1/drivers/pnp/pnpbios_core.c --- linux.20pre2/drivers/pnp/pnpbios_core.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/pnp/pnpbios_core.c 2002-08-06 15:42:11.000000000 +0100 @@ -0,0 +1,1352 @@ +/* + * PnP BIOS services + * + * Originally (C) 1998 Christian Schmidt + * Modifications (c) 1998 Tom Lees + * Minor reorganizations by David Hinds + * Modifications (c) 2001,2002 by Thomas Hood + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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 + * + * References: + * Compaq Computer Corporation, Phoenix Technologies Ltd., Intel Corporation + * Plug and Play BIOS Specification, Version 1.0A, May 5, 1994 + * Plug and Play BIOS Clarification Paper, October 6, 1994 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * + * PnP BIOS INTERFACE + * + */ + +/* PnP BIOS signature: "$PnP" */ +#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24)) + +#pragma pack(1) +union pnp_bios_expansion_header { + struct { + u32 signature; /* "$PnP" */ + u8 version; /* in BCD */ + u8 length; /* length in bytes, currently 21h */ + u16 control; /* system capabilities */ + u8 checksum; /* all bytes must add up to 0 */ + + u32 eventflag; /* phys. address of the event flag */ + u16 rmoffset; /* real mode entry point */ + u16 rmcseg; + u16 pm16offset; /* 16 bit protected mode entry */ + u32 pm16cseg; + u32 deviceID; /* EISA encoded system ID or 0 */ + u16 rmdseg; /* real mode data segment */ + u32 pm16dseg; /* 16 bit pm data segment base */ + } fields; + char chars[0x21]; /* To calculate the checksum */ +}; +#pragma pack() + +static struct { + u16 offset; + u16 segment; +} pnp_bios_callpoint; + +static union pnp_bios_expansion_header * pnp_bios_hdr = NULL; + +/* The PnP BIOS entries in the GDT */ +#define PNP_GDT (0x0060) +#define PNP_CS32 (PNP_GDT+0x00) /* segment for calling fn */ +#define PNP_CS16 (PNP_GDT+0x08) /* code segment for BIOS */ +#define PNP_DS (PNP_GDT+0x10) /* data segment for BIOS */ +#define PNP_TS1 (PNP_GDT+0x18) /* transfer data segment */ +#define PNP_TS2 (PNP_GDT+0x20) /* another data segment */ + +/* + * These are some opcodes for a "static asmlinkage" + * As this code is *not* executed inside the linux kernel segment, but in a + * alias at offset 0, we need a far return that can not be compiled by + * default (please, prove me wrong! this is *really* ugly!) + * This is the only way to get the bios to return into the kernel code, + * because the bios code runs in 16 bit protected mode and therefore can only + * return to the caller if the call is within the first 64kB, and the linux + * kernel begins at offset 3GB... + */ + +asmlinkage void pnp_bios_callfunc(void); + +__asm__( + ".text \n" + __ALIGN_STR "\n" + SYMBOL_NAME_STR(pnp_bios_callfunc) ":\n" + " pushl %edx \n" + " pushl %ecx \n" + " pushl %ebx \n" + " pushl %eax \n" + " lcallw " SYMBOL_NAME_STR(pnp_bios_callpoint) "\n" + " addl $16, %esp \n" + " lret \n" + ".previous \n" +); + +#define Q_SET_SEL(selname, address, size) \ +set_base (gdt [(selname) >> 3], __va((u32)(address))); \ +set_limit (gdt [(selname) >> 3], size) + +#define Q2_SET_SEL(selname, address, size) \ +set_base (gdt [(selname) >> 3], (u32)(address)); \ +set_limit (gdt [(selname) >> 3], size) + +/* + * At some point we want to use this stack frame pointer to unwind + * after PnP BIOS oopses. + */ + +u32 pnp_bios_fault_esp; +u32 pnp_bios_fault_eip; +u32 pnp_bios_is_utter_crap = 0; + +static spinlock_t pnp_bios_lock; + +static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, + u16 arg4, u16 arg5, u16 arg6, u16 arg7, + void *ts1_base, u32 ts1_size, + void *ts2_base, u32 ts2_size) +{ + unsigned long flags; + u16 status; + + /* + * PnP BIOSes are generally not terribly re-entrant. + * Also, don't rely on them to save everything correctly. + */ + if(pnp_bios_is_utter_crap) + return PNP_FUNCTION_NOT_SUPPORTED; + + /* On some boxes IRQ's during PnP BIOS calls are deadly. */ + spin_lock_irqsave(&pnp_bios_lock, flags); + + if (ts1_size) + Q2_SET_SEL(PNP_TS1, ts1_base, ts1_size); + if (ts2_size) + Q2_SET_SEL(PNP_TS2, ts2_base, ts2_size); + + __asm__ __volatile__( + "pushl %%ebp\n\t" + "pushl %%edi\n\t" + "pushl %%esi\n\t" + "pushl %%ds\n\t" + "pushl %%es\n\t" + "pushl %%fs\n\t" + "pushl %%gs\n\t" + "pushfl\n\t" + "movl %%esp, pnp_bios_fault_esp\n\t" + "movl $1f, pnp_bios_fault_eip\n\t" + "lcall %5,%6\n\t" + "1:popfl\n\t" + "popl %%gs\n\t" + "popl %%fs\n\t" + "popl %%es\n\t" + "popl %%ds\n\t" + "popl %%esi\n\t" + "popl %%edi\n\t" + "popl %%ebp\n\t" + : "=a" (status) + : "0" ((func) | (((u32)arg1) << 16)), + "b" ((arg2) | (((u32)arg3) << 16)), + "c" ((arg4) | (((u32)arg5) << 16)), + "d" ((arg6) | (((u32)arg7) << 16)), + "i" (PNP_CS32), + "i" (0) + : "memory" + ); + spin_unlock_irqrestore(&pnp_bios_lock, flags); + + /* If we get here and this is set then the PnP BIOS faulted on us. */ + if(pnp_bios_is_utter_crap) + { + printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n"); + printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably.\n"); + printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS.\n"); + } + + return status; +} + + +/* + * + * UTILITY FUNCTIONS + * + */ + +static void pnpbios_warn_unexpected_status(const char * module, u16 status) +{ + printk(KERN_ERR "PnPBIOS: %s: Unexpected status 0x%x\n", module, status); +} + +void *pnpbios_kmalloc(size_t size, int f) +{ + void *p = kmalloc( size, f ); + if ( p == NULL ) + printk(KERN_ERR "PnPBIOS: kmalloc() failed\n"); + return p; +} + +/* + * Call this only after init time + */ +static inline int pnp_bios_present(void) +{ + return (pnp_bios_hdr != NULL); +} + +/* Forward declaration */ +static void update_devlist( u8 nodenum, struct pnp_bios_node *data ); + + +/* + * + * PnP BIOS ACCESS FUNCTIONS + * + */ + +#define PNP_GET_NUM_SYS_DEV_NODES 0x00 +#define PNP_GET_SYS_DEV_NODE 0x01 +#define PNP_SET_SYS_DEV_NODE 0x02 +#define PNP_GET_EVENT 0x03 +#define PNP_SEND_MESSAGE 0x04 +#define PNP_GET_DOCKING_STATION_INFORMATION 0x05 +#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09 +#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a +#define PNP_GET_APM_ID_TABLE 0x0b +#define PNP_GET_PNP_ISA_CONFIG_STRUC 0x40 +#define PNP_GET_ESCD_INFO 0x41 +#define PNP_READ_ESCD 0x42 +#define PNP_WRITE_ESCD 0x43 + +/* + * Call PnP BIOS with function 0x00, "get number of system device nodes" + */ +static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0, + data, sizeof(struct pnp_dev_node_info), 0, 0); + data->no_nodes &= 0xff; + return status; +} + +int pnp_bios_dev_node_info(struct pnp_dev_node_info *data) +{ + int status = __pnp_bios_dev_node_info( data ); + if ( status ) + pnpbios_warn_unexpected_status( "dev_node_info", status ); + return status; +} + +/* + * Note that some PnP BIOSes (e.g., on Sony Vaio laptops) die a horrible + * death if they are asked to access the "current" configuration. + * Therefore, if it's a matter of indifference, it's better to call + * get_dev_node() and set_dev_node() with boot=1 rather than with boot=0. + */ + +/* + * Call PnP BIOS with function 0x01, "get system device node" + * Input: *nodenum = desired node, + * boot = whether to get nonvolatile boot (!=0) + * or volatile current (0) config + * Output: *nodenum=next node or 0xff if no more nodes + */ +static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + if ( !boot & pnpbios_dont_use_current_config ) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0, + nodenum, sizeof(char), data, 65536); + return status; +} + +int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data) +{ + int status; + status = __pnp_bios_get_dev_node( nodenum, boot, data ); + if ( status ) + pnpbios_warn_unexpected_status( "get_dev_node", status ); + return status; +} + + +/* + * Call PnP BIOS with function 0x02, "set system device node" + * Input: *nodenum = desired node, + * boot = whether to set nonvolatile boot (!=0) + * or volatile current (0) config + */ +static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + if ( !boot & pnpbios_dont_use_current_config ) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0, + data, 65536, 0, 0); + return status; +} + +int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data) +{ + int status; + status = __pnp_bios_set_dev_node( nodenum, boot, data ); + if ( status ) { + pnpbios_warn_unexpected_status( "set_dev_node", status ); + return status; + } + if ( !boot ) { /* Update devlist */ + u8 thisnodenum = nodenum; + status = pnp_bios_get_dev_node( &nodenum, boot, data ); + if ( status ) + return status; + update_devlist( thisnodenum, data ); + } + return status; +} + +#if needed +/* + * Call PnP BIOS with function 0x03, "get event" + */ +static int pnp_bios_get_event(u16 *event) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0, + event, sizeof(u16), 0, 0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS with function 0x04, "send message" + */ +static int pnp_bios_send_message(u16 message) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0, 0, 0, 0, 0); + return status; +} +#endif + +#ifdef CONFIG_HOTPLUG +/* + * Call PnP BIOS with function 0x05, "get docking station information" + */ +static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, + data, sizeof(struct pnp_docking_station_info), 0, 0); + return status; +} +#endif + +#if needed +/* + * Call PnP BIOS with function 0x09, "set statically allocated resource + * information" + */ +static int pnp_bios_set_stat_res(char *info) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, + info, *((u16 *) info), 0, 0); + return status; +} +#endif + +/* + * Call PnP BIOS with function 0x0a, "get statically allocated resource + * information" + */ +static int __pnp_bios_get_stat_res(char *info) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, + info, 65536, 0, 0); + return status; +} + +int pnp_bios_get_stat_res(char *info) +{ + int status; + status = __pnp_bios_get_stat_res( info ); + if ( status ) + pnpbios_warn_unexpected_status( "get_stat_res", status ); + return status; +} + +#if needed +/* + * Call PnP BIOS with function 0x0b, "get APM id table" + */ +static int pnp_bios_apm_id_table(char *table, u16 *size) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0, + table, *size, size, sizeof(u16)); + return status; +} +#endif + +/* + * Call PnP BIOS with function 0x40, "get isa pnp configuration structure" + */ +static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) +{ + u16 status; + if (!pnp_bios_present()) + return PNP_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, + data, sizeof(struct pnp_isa_config_struc), 0, 0); + return status; +} + +int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data) +{ + int status; + status = __pnp_bios_isapnp_config( data ); + if ( status ) + pnpbios_warn_unexpected_status( "isapnp_config", status ); + return status; +} + +/* + * Call PnP BIOS with function 0x41, "get ESCD info" + */ +static int __pnp_bios_escd_info(struct escd_info_struc *data) +{ + u16 status; + if (!pnp_bios_present()) + return ESCD_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS, + data, sizeof(struct escd_info_struc), 0, 0); + return status; +} + +int pnp_bios_escd_info(struct escd_info_struc *data) +{ + int status; + status = __pnp_bios_escd_info( data ); + if ( status ) + pnpbios_warn_unexpected_status( "escd_info", status ); + return status; +} + +/* + * Call PnP BIOS function 0x42, "read ESCD" + * nvram_base is determined by calling escd_info + */ +static int __pnp_bios_read_escd(char *data, u32 nvram_base) +{ + u16 status; + if (!pnp_bios_present()) + return ESCD_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0, + data, 65536, (void *)nvram_base, 65536); + return status; +} + +int pnp_bios_read_escd(char *data, u32 nvram_base) +{ + int status; + status = __pnp_bios_read_escd( data, nvram_base ); + if ( status ) + pnpbios_warn_unexpected_status( "read_escd", status ); + return status; +} + +#if needed +/* + * Call PnP BIOS function 0x43, "write ESCD" + */ +static int pnp_bios_write_escd(char *data, u32 nvram_base) +{ + u16 status; + if (!pnp_bios_present()) + return ESCD_FUNCTION_NOT_SUPPORTED; + status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0, + data, 65536, nvram_base, 65536); + return status; +} +#endif + + +/* + * + * DOCKING FUNCTIONS + * + */ + +#ifdef CONFIG_HOTPLUG + +static int unloading = 0; +static struct completion unload_sem; + +/* + * (Much of this belongs in a shared routine somewhere) + */ + +static int pnp_dock_event(int dock, struct pnp_docking_station_info *info) +{ + char *argv [3], **envp, *buf, *scratch; + int i = 0, value; + + if (!hotplug_path [0]) + return -ENOENT; + if (!current->fs->root) { + return -EAGAIN; + } + if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) { + return -ENOMEM; + } + if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) { + kfree (envp); + return -ENOMEM; + } + + /* only one standardized param to hotplug command: type */ + argv [0] = hotplug_path; + argv [1] = "dock"; + argv [2] = 0; + + /* minimal command environment */ + envp [i++] = "HOME=/"; + envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + +#ifdef DEBUG + /* hint that policy agent should enter no-stdout debug mode */ + envp [i++] = "DEBUG=kernel"; +#endif + /* extensible set of named bus-specific parameters, + * supporting multiple driver selection algorithms. + */ + scratch = buf; + + /* action: add, remove */ + envp [i++] = scratch; + scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1; + + /* Report the ident for the dock */ + envp [i++] = scratch; + scratch += sprintf (scratch, "DOCK=%x/%x/%x", + info->location_id, info->serial, info->capabilities); + envp[i] = 0; + + value = call_usermodehelper (argv [0], argv, envp); + kfree (buf); + kfree (envp); + return 0; +} + +/* + * Poll the PnP docking at regular intervals + */ +static int pnp_dock_thread(void * unused) +{ + static struct pnp_docking_station_info now; + int docked = -1, d = 0; + daemonize(); + reparent_to_init(); + strcpy(current->comm, "kpnpbiosd"); + while(!unloading && !signal_pending(current)) + { + int status; + + /* + * Poll every 2 seconds + */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ*2); + if(signal_pending(current)) + break; + + status = pnp_bios_dock_station_info(&now); + + switch(status) + { + /* + * No dock to manage + */ + case PNP_FUNCTION_NOT_SUPPORTED: + complete_and_exit(&unload_sem, 0); + case PNP_SYSTEM_NOT_DOCKED: + d = 0; + break; + case PNP_SUCCESS: + d = 1; + break; + default: + pnpbios_warn_unexpected_status( "pnp_dock_thread", status ); + continue; + } + if(d != docked) + { + if(pnp_dock_event(d, &now)==0) + { + docked = d; +#if 0 + printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de"); +#endif + } + } + } + complete_and_exit(&unload_sem, 0); +} + +#endif /* CONFIG_HOTPLUG */ + + +/* + * + * NODE DATA PARSING FUNCTIONS + * + */ + +static void add_irqresource(struct pci_dev *dev, int irq) +{ + int i = 0; + while (!(dev->irq_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_IRQ) i++; + if (i < DEVICE_COUNT_IRQ) { + dev->irq_resource[i].start = (unsigned long) irq; + dev->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag + } +} + +static void add_dmaresource(struct pci_dev *dev, int dma) +{ + int i = 0; + while (!(dev->dma_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_DMA) i++; + if (i < DEVICE_COUNT_DMA) { + dev->dma_resource[i].start = (unsigned long) dma; + dev->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag + } +} + +static void add_ioresource(struct pci_dev *dev, int io, int len) +{ + int i = 0; + while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++; + if (i < DEVICE_COUNT_RESOURCE) { + dev->resource[i].start = (unsigned long) io; + dev->resource[i].end = (unsigned long)(io + len - 1); + dev->resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag + } +} + +static void add_memresource(struct pci_dev *dev, int mem, int len) +{ + int i = 0; + while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++; + if (i < DEVICE_COUNT_RESOURCE) { + dev->resource[i].start = (unsigned long) mem; + dev->resource[i].end = (unsigned long)(mem + len - 1); + dev->resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag + } +} + +static void node_resource_data_to_dev(struct pnp_bios_node *node, struct pci_dev *dev) +{ + unsigned char *p = node->data, *lastp=NULL; + int i; + + /* + * First, set resource info to default values + */ + for (i=0;iresource[i].start = 0; // "disabled" + dev->resource[i].flags = IORESOURCE_UNSET; + } + for (i=0;iirq_resource[i].start = (unsigned long)-1; // "disabled" + dev->irq_resource[i].flags = IORESOURCE_UNSET; + } + for (i=0;idma_resource[i].start = (unsigned long)-1; // "disabled" + dev->dma_resource[i].flags = IORESOURCE_UNSET; + } + + /* + * Fill in dev resource info + */ + while ( (char *)p < ((char *)node->data + node->size )) { + if(p==lastp) break; + + if( p[0] & 0x80 ) {// large item + switch (p[0] & 0x7f) { + case 0x01: // memory + { + int io = *(short *) &p[4]; + int len = *(short *) &p[10]; + add_memresource(dev, io, len); + break; + } + case 0x02: // device name + { + int len = *(short *) &p[1]; + memcpy(dev->name, p + 3, len >= 80 ? 79 : len); + break; + } + case 0x05: // 32-bit memory + { + int io = *(int *) &p[4]; + int len = *(int *) &p[16]; + add_memresource(dev, io, len); + break; + } + case 0x06: // fixed location 32-bit memory + { + int io = *(int *) &p[4]; + int len = *(int *) &p[8]; + add_memresource(dev, io, len); + break; + } + } /* switch */ + lastp = p+3; + p = p + p[1] + p[2]*256 + 3; + continue; + } + if ((p[0]>>3) == 0x0f) // end tag + break; + switch (p[0]>>3) { + case 0x04: // irq + { + int i, mask, irq = -1; + mask= p[1] + p[2]*256; + for (i=0;i<16;i++, mask=mask>>1) + if(mask & 0x01) irq=i; + add_irqresource(dev, irq); + break; + } + case 0x05: // dma + { + int i, mask, dma = -1; + mask = p[1]; + for (i=0;i<8;i++, mask = mask>>1) + if(mask & 0x01) dma=i; + add_dmaresource(dev, dma); + break; + } + case 0x08: // io + { + int io= p[2] + p[3] *256; + int len = p[7]; + add_ioresource(dev, io, len); + break; + } + case 0x09: // fixed location io + { + int io = p[1] + p[2] * 256; + int len = p[3]; + add_ioresource(dev, io, len); + break; + } + } /* switch */ + lastp=p+1; + p = p + (p[0] & 0x07) + 1; + + } /* while */ + + return; +} + + +/* + * + * DEVICE LIST MANAGEMENT FUNCTIONS + * + * + * Some of these are exported to give public access + * + * Question: Why maintain a device list when the PnP BIOS can + * list devices for us? Answer: Some PnP BIOSes can't report + * the current configuration, only the boot configuration. + * The boot configuration can be changed, so we need to keep + * a record of what the configuration was when we booted; + * presumably it continues to describe the current config. + * For those BIOSes that can change the current config, we + * keep the information in the devlist up to date. + * + * Note that it is currently assumed that the list does not + * grow or shrink in size after init time, and slot_name + * never changes. The list is protected by a spinlock. + */ + +static LIST_HEAD(pnpbios_devices); + +static spinlock_t pnpbios_devices_lock; + +static int inline insert_device(struct pci_dev *dev) +{ + + /* + * FIXME: Check for re-add of existing node; + * return -1 if node already present + */ + + /* We don't lock because we only do this at init time */ + list_add_tail(&dev->global_list, &pnpbios_devices); + + return 0; +} + +#define HEX(id,a) hex[((id)>>a) & 15] +#define CHAR(id,a) (0x40 + (((id)>>a) & 31)) +// +static void inline pnpid32_to_pnpid(u32 id, char *str) +{ + const char *hex = "0123456789abcdef"; + + id = be32_to_cpu(id); + str[0] = CHAR(id, 26); + str[1] = CHAR(id, 21); + str[2] = CHAR(id,16); + str[3] = HEX(id, 12); + str[4] = HEX(id, 8); + str[5] = HEX(id, 4); + str[6] = HEX(id, 0); + str[7] = '\0'; + + return; +} +// +#undef CHAR +#undef HEX + +/* + * Build a linked list of pci_devs in order of ascending node number + * Called only at init time. + */ +static void __init build_devlist(void) +{ + u8 nodenum; + unsigned int nodes_got = 0; + unsigned int devs = 0; + struct pnp_bios_node *node; + struct pnp_dev_node_info node_info; + struct pci_dev *dev; + + if (!pnp_bios_present()) + return; + + if (pnp_bios_dev_node_info(&node_info) != 0) + return; + + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) + return; + + for(nodenum=0; nodenum<0xff; ) { + u8 thisnodenum = nodenum; + /* We build the list from the "boot" config because + * asking for the "current" config causes some + * BIOSes to crash. + */ + if (pnp_bios_get_dev_node(&nodenum, (char )1 , node)) + break; + nodes_got++; + dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL); + if (!dev) + break; + memset(dev,0,sizeof(struct pci_dev)); + dev->devfn = thisnodenum; + memcpy(dev->name,"PNPBIOS",8); + pnpid32_to_pnpid(node->eisa_id,dev->slot_name); + node_resource_data_to_dev(node,dev); + if(insert_device(dev)<0) + kfree(dev); + else + devs++; + if (nodenum <= thisnodenum) { + printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum); + break; + } + } + kfree(node); + + printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n", + nodes_got, nodes_got != 1 ? "s" : "", devs); +} + +static struct pci_dev *find_device_by_nodenum( u8 nodenum ) +{ + struct pci_dev *dev; + + pnpbios_for_each_dev(dev) { + if(dev->devfn == nodenum) + return dev; + } + + return NULL; +} + +static void update_devlist( u8 nodenum, struct pnp_bios_node *data ) +{ + unsigned long flags; + struct pci_dev *dev; + + spin_lock_irqsave(&pnpbios_devices_lock, flags); + dev = find_device_by_nodenum( nodenum ); + if ( dev ) { + node_resource_data_to_dev(data,dev); + } + spin_unlock_irqrestore(&pnpbios_devices_lock, flags); + + return; +} + + +/* + * + * DRIVER REGISTRATION FUNCTIONS + * + * + * Exported to give public access + * + */ + +static LIST_HEAD(pnpbios_drivers); + +static const struct pnpbios_device_id * +match_device(const struct pnpbios_device_id *ids, const struct pci_dev *dev) +{ + while (*ids->id) + { + if(memcmp(ids->id, dev->slot_name, 7)==0) + return ids; + ids++; + } + return NULL; +} + +static int announce_device(struct pnpbios_driver *drv, struct pci_dev *dev) +{ + const struct pnpbios_device_id *id; + struct pci_dev tmpdev; + int ret; + + if (drv->id_table) { + id = match_device(drv->id_table, dev); + if (!id) + return 0; + } else + id = NULL; + + memcpy( &tmpdev, dev, sizeof(struct pci_dev)); + tmpdev.global_list.prev = NULL; + tmpdev.global_list.next = NULL; + + dev_probe_lock(); + /* Obviously, probe() should not call any pnpbios functions */ + ret = drv->probe(&tmpdev, id); + dev_probe_unlock(); + if (ret < 1) + return 0; + + dev->driver = (void *)drv; + + return 1; +} + +/** + * pnpbios_register_driver - register a new pci driver + * @drv: the driver structure to register + * + * Adds the driver structure to the list of registered drivers + * + * For each device in the pnpbios device list that matches one of + * the ids in drv->id_table, calls the driver's "probe" function with + * arguments (1) a pointer to a *temporary* struct pci_dev containing + * resource info for the device, and (2) a pointer to the id string + * of the device. Expects the probe function to return 1 if the + * driver claims the device (otherwise 0) in which case, marks the + * device as having this driver. + * + * Returns the number of pci devices which were claimed by the driver + * during registration. The driver remains registered even if the + * return value is zero. + */ +int pnpbios_register_driver(struct pnpbios_driver *drv) +{ + struct pci_dev *dev; + unsigned long flags; + int count = 0; + + list_add_tail(&drv->node, &pnpbios_drivers); + spin_lock_irqsave(&pnpbios_devices_lock, flags); + pnpbios_for_each_dev(dev) { + if (!pnpbios_dev_driver(dev)) + count += announce_device(drv, dev); + } + spin_unlock_irqrestore(&pnpbios_devices_lock, flags); + return count; +} + +EXPORT_SYMBOL(pnpbios_register_driver); + +/** + * pnpbios_unregister_driver - unregister a pci driver + * @drv: the driver structure to unregister + * + * Deletes the driver structure from the list of registered PnPBIOS + * drivers, gives it a chance to clean up by calling its "remove" + * function for each device it was responsible for, and marks those + * devices as driverless. + */ +void pnpbios_unregister_driver(struct pnpbios_driver *drv) +{ + unsigned long flags; + struct pci_dev *dev; + + list_del(&drv->node); + spin_lock_irqsave(&pnpbios_devices_lock, flags); + pnpbios_for_each_dev(dev) { + if (dev->driver == (void *)drv) { + if (drv->remove) + drv->remove(dev); + dev->driver = NULL; + } + } + spin_unlock_irqrestore(&pnpbios_devices_lock, flags); +} + +EXPORT_SYMBOL(pnpbios_unregister_driver); + + +/* + * + * RESOURCE RESERVATION FUNCTIONS + * + * + * Used only at init time + * + */ + +static void __init reserve_ioport_range(char *pnpid, int start, int end) +{ + struct resource *res; + char *regionid; + +#if 0 + /* + * TEMPORARY hack to work around the fact that the + * floppy driver inappropriately reserves ioports 0x3f0 and 0x3f1 + * Remove this once the floppy driver is fixed. + */ + if ( + (0x3f0 >= start && 0x3f0 <= end) + || (0x3f1 >= start && 0x3f1 <= end) + ) { + printk(KERN_INFO + "PnPBIOS: %s: ioport range 0x%x-0x%x NOT reserved\n", + pnpid, start, end + ); + return; + } +#endif + + regionid = pnpbios_kmalloc(16, GFP_KERNEL); + if ( regionid == NULL ) + return; + snprintf(regionid, 16, "PnPBIOS %s", pnpid); + res = request_region(start,end-start+1,regionid); + if ( res == NULL ) + kfree( regionid ); + else + res->flags &= ~IORESOURCE_BUSY; + /* + * Failures at this point are usually harmless. pci quirks for + * example do reserve stuff they know about too, so we may well + * have double reservations. + */ + printk(KERN_INFO + "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved\n", + pnpid, start, end, + NULL != res ? "has been" : "could not be" + ); + + return; +} + +static void __init reserve_resources_of_dev( struct pci_dev *dev ) +{ + int i; + + for (i=0;iresource[i].flags & IORESOURCE_UNSET ) + /* end of resources */ + break; + if (dev->resource[i].flags & IORESOURCE_IO) { + /* ioport */ + if ( dev->resource[i].start == 0 ) + /* disabled */ + /* Do nothing */ + continue; + if ( dev->resource[i].start < 0x100 ) + /* + * Below 0x100 is only standard PC hardware + * (pics, kbd, timer, dma, ...) + * We should not get resource conflicts there, + * and the kernel reserves these anyway + * (see arch/i386/kernel/setup.c). + * So, do nothing + */ + continue; + if ( dev->resource[i].end < dev->resource[i].start ) + /* invalid endpoint */ + /* Do nothing */ + continue; + reserve_ioport_range( + dev->slot_name, + dev->resource[i].start, + dev->resource[i].end + ); + } else if (dev->resource[i].flags & IORESOURCE_MEM) { + /* iomem */ + /* For now do nothing */ + continue; + } else { + /* Neither ioport nor iomem */ + /* Do nothing */ + continue; + } + } + + return; +} + +static void __init reserve_resources( void ) +{ + struct pci_dev *dev; + + pnpbios_for_each_dev(dev) { + if ( + 0 != strcmp(dev->slot_name,"PNP0c01") && /* memory controller */ + 0 != strcmp(dev->slot_name,"PNP0c02") /* system peripheral: other */ + ) { + continue; + } + reserve_resources_of_dev(dev); + } + + return; +} + + +/* + * + * INIT AND EXIT + * + */ + +extern int is_sony_vaio_laptop; + +static int pnpbios_disabled; /* = 0 */ +static int dont_reserve_resources; /* = 0 */ +int pnpbios_dont_use_current_config; /* = 0 */ + +#ifndef MODULE +static int __init pnpbios_setup(char *str) +{ + int invert; + + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "off", 3) == 0) + pnpbios_disabled=1; + if (strncmp(str, "on", 2) == 0) + pnpbios_disabled=0; + invert = (strncmp(str, "no-", 3) == 0); + if (invert) + str += 3; + if (strncmp(str, "curr", 4) == 0) + pnpbios_dont_use_current_config = invert; + if (strncmp(str, "res", 3) == 0) + dont_reserve_resources = invert; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } + + return 1; +} + +__setup("pnpbios=", pnpbios_setup); +#endif + +int __init pnpbios_init(void) +{ + union pnp_bios_expansion_header *check; + u8 sum; + int i, length, r; + + spin_lock_init(&pnp_bios_lock); + spin_lock_init(&pnpbios_devices_lock); + + if(pnpbios_disabled) { + printk(KERN_INFO "PnPBIOS: Disabled\n"); + return -ENODEV; + } + + if ( is_sony_vaio_laptop ) + pnpbios_dont_use_current_config = 1; + + /* + * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS + * structure and, if one is found, sets up the selectors and + * entry points + */ + for (check = (union pnp_bios_expansion_header *) __va(0xf0000); + check < (union pnp_bios_expansion_header *) __va(0xffff0); + ((void *) (check)) += 16) { + if (check->fields.signature != PNP_SIGNATURE) + continue; + length = check->fields.length; + if (!length) + continue; + for (sum = 0, i = 0; i < length; i++) + sum += check->chars[i]; + if (sum) + continue; + if (check->fields.version < 0x10) { + printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n", + check->fields.version >> 4, + check->fields.version & 15); + continue; + } + printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check); + printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n", + check->fields.version >> 4, check->fields.version & 15, + check->fields.pm16cseg, check->fields.pm16offset, + check->fields.pm16dseg); + Q2_SET_SEL(PNP_CS32, &pnp_bios_callfunc, 64 * 1024); + Q_SET_SEL(PNP_CS16, check->fields.pm16cseg, 64 * 1024); + Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024); + pnp_bios_callpoint.offset = check->fields.pm16offset; + pnp_bios_callpoint.segment = PNP_CS16; + pnp_bios_hdr = check; + break; + } + if (!pnp_bios_present()) + return -ENODEV; + build_devlist(); + if ( ! dont_reserve_resources ) + reserve_resources(); +#ifdef CONFIG_PROC_FS + r = pnpbios_proc_init(); + if (r) + return r; +#endif + return 0; +} + +static int pnpbios_thread_init(void) +{ +#ifdef CONFIG_HOTPLUG + init_completion(&unload_sem); + if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0) + unloading = 0; +#endif + return 0; +} + +#ifndef MODULE + +/* init/main.c calls pnpbios_init early */ + +/* Start the kernel thread later: */ +module_init(pnpbios_thread_init); + +#else + +/* + * N.B.: Building pnpbios as a module hasn't been fully implemented + */ + +MODULE_LICENSE("GPL"); + +static int pnpbios_init_all(void) +{ + int r; + r = pnpbios_init(); + if (r) + return r; + r = pnpbios_thread_init(); + if (r) + return r; + return 0; +} + +static void __exit pnpbios_exit(void) +{ +#ifdef CONFIG_HOTPLUG + unloading = 1; + wait_for_completion(&unload_sem); +#endif + pnpbios_proc_exit(); + /* We ought to free resources here */ + return; +} + +module_init(pnpbios_init_all); +module_exit(pnpbios_exit); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/pnp/pnpbios_proc.c linux.20pre2-ac1/drivers/pnp/pnpbios_proc.c --- linux.20pre2/drivers/pnp/pnpbios_proc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/pnp/pnpbios_proc.c 2002-08-11 21:28:12.000000000 +0100 @@ -0,0 +1,278 @@ +/* + * /proc/bus/pnp interface for Plug and Play devices + * + * Written by David Hinds, dahinds@users.sourceforge.net + * Modified by Thomas Hood, jdthood@mail.com + * + * The .../devices and .../ and .../boot/ files are + * utilized by the lspnp and setpnp utilities, supplied with the + * pcmcia-cs package. + * http://pcmcia-cs.sourceforge.net + * + * The .../escd file is utilized by the lsescd utility written by + * Gunther Mayer. + * http://home.t-online.de/home/gunther.mayer/lsescd + * + * The .../legacy_device_resources file is not used yet. + * + * The other files are human-readable. + */ + +//#include +#define __NO_VERSION__ +//#include + +#include +#include +#include +#include +#include +#include + +static struct proc_dir_entry *proc_pnp = NULL; +static struct proc_dir_entry *proc_pnp_boot = NULL; +static struct pnp_dev_node_info node_info; + +static int proc_read_pnpconfig(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct pnp_isa_config_struc pnps; + + if (pnp_bios_isapnp_config(&pnps)) + return -EIO; + return snprintf(buf, count, + "structure_revision %d\n" + "number_of_CSNs %d\n" + "ISA_read_data_port 0x%x\n", + pnps.revision, + pnps.no_csns, + pnps.isa_rd_data_port + ); +} + +static int proc_read_escdinfo(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct escd_info_struc escd; + + if (pnp_bios_escd_info(&escd)) + return -EIO; + return snprintf(buf, count, + "min_ESCD_write_size %d\n" + "ESCD_size %d\n" + "NVRAM_base 0x%x\n", + escd.min_escd_write_size, + escd.escd_size, + escd.nv_storage_base + ); +} + +#define MAX_SANE_ESCD_SIZE (32*1024) +static int proc_read_escd(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct escd_info_struc escd; + char *tmpbuf; + int escd_size, escd_left_to_read, n; + + if (pnp_bios_escd_info(&escd)) + return -EIO; + + /* sanity check */ + if (escd.escd_size > MAX_SANE_ESCD_SIZE) { + printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n"); + return -EFBIG; + } + + tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL); + if (!tmpbuf) return -ENOMEM; + + if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) + return -EIO; + + escd_size = (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1])*256; + + /* sanity check */ + if (escd_size > MAX_SANE_ESCD_SIZE) { + printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n"); + return -EFBIG; + } + + escd_left_to_read = escd_size - pos; + if (escd_left_to_read < 0) escd_left_to_read = 0; + if (escd_left_to_read == 0) *eof = 1; + n = min(count,escd_left_to_read); + memcpy(buf, tmpbuf + pos, n); + kfree(tmpbuf); + *start = buf; + return n; +} + +static int proc_read_legacyres(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + /* Assume that the following won't overflow the buffer */ + if (pnp_bios_get_stat_res(buf)) + return -EIO; + + return count; // FIXME: Return actual length +} + +static int proc_read_devices(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct pnp_bios_node *node; + u8 nodenum; + char *p = buf; + + if (pos >= 0xff) + return 0; + + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + + for (nodenum=pos; nodenum<0xff; ) { + u8 thisnodenum = nodenum; + /* 26 = the number of characters per line sprintf'ed */ + if ((p - buf + 26) > count) + break; + if (pnp_bios_get_dev_node(&nodenum, 1, node)) + break; + p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", + node->handle, node->eisa_id, + node->type_code[0], node->type_code[1], + node->type_code[2], node->flags); + if (nodenum <= thisnodenum) { + printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum); + *eof = 1; + break; + } + } + kfree(node); + if (nodenum == 0xff) + *eof = 1; + *start = (char *)((off_t)nodenum - pos); + return p - buf; +} + +static int proc_read_node(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct pnp_bios_node *node; + int boot = (long)data >> 8; + u8 nodenum = (long)data; + int len; + + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + if (pnp_bios_get_dev_node(&nodenum, boot, node)) + return -EIO; + len = node->size - sizeof(struct pnp_bios_node); + memcpy(buf, node->data, len); + kfree(node); + return len; +} + +static int proc_write_node(struct file *file, const char *buf, + unsigned long count, void *data) +{ + struct pnp_bios_node *node; + int boot = (long)data >> 8; + u8 nodenum = (long)data; + + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) return -ENOMEM; + if ( pnp_bios_get_dev_node(&nodenum, boot, node) ) + return -EIO; + if (count != node->size - sizeof(struct pnp_bios_node)) + return -EINVAL; + memcpy(node->data, buf, count); + if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) + return -EINVAL; + kfree(node); + return count; +} + +/* + * When this is called, pnpbios functions are assumed to + * work and the pnpbios_dont_use_current_config flag + * should already have been set to the appropriate value + */ +int __init pnpbios_proc_init( void ) +{ + struct pnp_bios_node *node; + struct proc_dir_entry *ent; + char name[3]; + u8 nodenum; + + if (pnp_bios_dev_node_info(&node_info)) + return -EIO; + + proc_pnp = proc_mkdir("pnp", proc_bus); + if (!proc_pnp) + return -EIO; + proc_pnp_boot = proc_mkdir("boot", proc_pnp); + if (!proc_pnp_boot) + return -EIO; + create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL); + create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL); + create_proc_read_entry("escd_info", S_IRUSR, proc_pnp, proc_read_escdinfo, NULL); + create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL); + create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL); + + node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); + if (!node) + return -ENOMEM; + + for (nodenum=0; nodenum<0xff; ) { + u8 thisnodenum = nodenum; + if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0) + break; + sprintf(name, "%02x", node->handle); + if ( !pnpbios_dont_use_current_config ) { + ent = create_proc_entry(name, 0, proc_pnp); + if (ent) { + ent->read_proc = proc_read_node; + ent->write_proc = proc_write_node; + ent->data = (void *)(long)(node->handle); + } + } + ent = create_proc_entry(name, 0, proc_pnp_boot); + if (ent) { + ent->read_proc = proc_read_node; + ent->write_proc = proc_write_node; + ent->data = (void *)(long)(node->handle+0x100); + } + if (nodenum <= thisnodenum) { + printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_init:", (unsigned int)nodenum, (unsigned int)thisnodenum); + break; + } + } + kfree(node); + + return 0; +} + +void __exit pnpbios_proc_exit(void) +{ + int i; + char name[3]; + + if (!proc_pnp) return; + + for (i=0; i<0xff; i++) { + sprintf(name, "%02x", i); + if ( !pnpbios_dont_use_current_config ) + remove_proc_entry(name, proc_pnp); + remove_proc_entry(name, proc_pnp_boot); + } + remove_proc_entry("legacy_device_resources", proc_pnp); + remove_proc_entry("escd", proc_pnp); + remove_proc_entry("escd_info", proc_pnp); + remove_proc_entry("configuration_info", proc_pnp); + remove_proc_entry("devices", proc_pnp); + remove_proc_entry("boot", proc_pnp); + remove_proc_entry("pnp", proc_bus); + + return; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/sbus/char/aurora.c linux.20pre2-ac1/drivers/sbus/char/aurora.c --- linux.20pre2/drivers/sbus/char/aurora.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/sbus/char/aurora.c 2002-08-06 15:42:11.000000000 +0100 @@ -136,25 +136,25 @@ */ /* Get board number from pointer */ -extern inline int board_No (struct Aurora_board const * bp) +static inline int board_No (struct Aurora_board const * bp) { return bp - aurora_board; } /* Get port number from pointer */ -extern inline int port_No (struct Aurora_port const * port) +static inline int port_No (struct Aurora_port const * port) { return AURORA_PORT(port - aurora_port); } /* Get pointer to board from pointer to port */ -extern inline struct Aurora_board * port_Board(struct Aurora_port const * port) +static inline struct Aurora_board * port_Board(struct Aurora_port const * port) { return &aurora_board[AURORA_BOARD(port - aurora_port)]; } /* Wait for Channel Command Register ready */ -extern inline void aurora_wait_CCR(struct aurora_reg128 * r) +static inline void aurora_wait_CCR(struct aurora_reg128 * r) { unsigned long delay; @@ -173,7 +173,7 @@ */ /* Must be called with enabled interrupts */ -extern inline void aurora_long_delay(unsigned long delay) +static inline void aurora_long_delay(unsigned long delay) { unsigned long i; @@ -432,7 +432,7 @@ sbus_iounmap((unsigned long)bp->r3, 4); } -extern inline void aurora_mark_event(struct Aurora_port * port, int event) +static inline void aurora_mark_event(struct Aurora_port * port, int event) { #ifdef AURORA_DEBUG printk("aurora_mark_event: start\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/sbus/dvma.c linux.20pre2-ac1/drivers/sbus/dvma.c --- linux.20pre2/drivers/sbus/dvma.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/sbus/dvma.c 2002-08-06 15:42:11.000000000 +0100 @@ -18,7 +18,7 @@ struct sbus_dma *dma_chain; /* Print out the current values in the DMA control registers */ -extern __inline__ void dump_dma_regs(unsigned long dregs) +static inline void dump_dma_regs(unsigned long dregs) { printk("DMA CONTROL<%08x> ADDR<%08x> CNT<%08x> TEST<%08x>\n", sbus_readl(dregs + DMA_CSR), sbus_readl(dregs + DMA_ADDR), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/ChangeLog.ips linux.20pre2-ac1/drivers/scsi/ChangeLog.ips --- linux.20pre2/drivers/scsi/ChangeLog.ips 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/ChangeLog.ips 2002-08-13 17:08:02.000000000 +0100 @@ -116,4 +116,3 @@ - Fixed read/write errors when the adapter is using an 8K stripe size. - \ No newline at end of file diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/Config.in linux.20pre2-ac1/drivers/scsi/Config.in --- linux.20pre2/drivers/scsi/Config.in 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/Config.in 2002-08-06 15:42:07.000000000 +0100 @@ -150,7 +150,10 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_SYM53C8XX_2" != "y" ]; then dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI - if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then + if [ "$CONFIG_PARISC" = "y" ]; then + dep_tristate 'Zalon SCSI support' CONFIG_SCSI_ZALON $CONFIG_GSC $CONFIG_SCSI + fi + if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -o "$CONFIG_SCSI_ZALON" = "y" -o "$CONFIG_SCSI_ZALON" = "m" -o "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/cpqfcTSinit.c linux.20pre2-ac1/drivers/scsi/cpqfcTSinit.c --- linux.20pre2/drivers/scsi/cpqfcTSinit.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/cpqfcTSinit.c 2002-08-06 15:42:07.000000000 +0100 @@ -261,10 +261,22 @@ /* "Entry" point to discover if any supported PCI bus adapter can be found */ -// We're supporting: -// Compaq 64-bit, 66MHz HBA with Tachyon TS -// Agilent XL2 -#define HBA_TYPES 2 +/* We're supporting: + * Compaq 64-bit, 66MHz HBA with Tachyon TS + * Agilent XL2 + * HP Tachyon + */ +#define HBA_TYPES 3 + +#ifndef PCI_DEVICE_ID_COMPAQ_ +#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc +#endif + +static struct SupportedPCIcards cpqfc_boards[] __initdata = { + {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON}, +}; int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate) @@ -274,35 +286,28 @@ struct Scsi_Host *HostAdapter = NULL; CPQFCHBA *cpqfcHBAdata = NULL; struct timer_list *cpqfcTStimer = NULL; - SupportedPCIcards PCIids[HBA_TYPES]; int i; - + ENTER("cpqfcTS_detect"); - + #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS; #else ScsiHostTemplate->proc_name = "cpqfcTS"; #endif - + if( pci_present() == 0) // no PCI busses? { printk( " no PCI bus?@#!\n"); return NumberOfAdapters; } - // what HBA adapters are we supporting? - PCIids[0].vendor_id = PCI_VENDOR_ID_COMPAQ; - PCIids[0].device_id = CPQ_DEVICE_ID; - PCIids[1].vendor_id = PCI_VENDOR_ID_HP; // i.e. 103Ch (Agilent == HP for now) - PCIids[1].device_id = AGILENT_XL2_ID; // i.e. 1029h - for( i=0; i < HBA_TYPES; i++) { // look for all HBAs of each type - while( (PciDev = - pci_find_device( PCIids[i].vendor_id, PCIids[i].device_id, PciDev) )) + while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id, + cpqfc_boards[i].device_id, PciDev))) { if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/cpqfcTSstructs.h linux.20pre2-ac1/drivers/scsi/cpqfcTSstructs.h --- linux.20pre2/drivers/scsi/cpqfcTSstructs.h 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/cpqfcTSstructs.h 2002-08-14 14:41:30.000000000 +0100 @@ -95,14 +95,11 @@ #define DEV_NAME "cpqfcTS" -#define CPQ_DEVICE_ID 0xA0FC -#define AGILENT_XL2_ID 0x1029 - -typedef struct +struct SupportedPCIcards { __u16 vendor_id; __u16 device_id; -} SupportedPCIcards; +}; // nn:nn denotes bit field // TachyonHeader struct def. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/cpqfcTSworker.c linux.20pre2-ac1/drivers/scsi/cpqfcTSworker.c --- linux.20pre2/drivers/scsi/cpqfcTSworker.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/cpqfcTSworker.c 2002-08-12 15:31:48.000000000 +0100 @@ -2911,7 +2911,7 @@ } } -Done: +Done: ; } static void @@ -3028,7 +3028,7 @@ -Done: +Done: ; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/dpt_i2o.c linux.20pre2-ac1/drivers/scsi/dpt_i2o.c --- linux.20pre2/drivers/scsi/dpt_i2o.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/dpt_i2o.c 2002-08-12 15:30:10.000000000 +0100 @@ -110,10 +110,6 @@ static adpt_hba* hba_chain = NULL; static int hba_count = 0; -// Debug flags to be put into the HBA flags field when initialized -// Make sure to enable DEBUG_PRINT for these flags to work -static unsigned long DebugFlags = HBA_FLAGS_DBG_SCAN_B | HBA_FLAGS_DBG_FLAGS_MASK; - static struct file_operations adpt_fops = { ioctl: adpt_ioctl, open: adpt_open, @@ -1141,7 +1137,8 @@ // to support async LCT get wait_data->next = adpt_post_wait_queue; adpt_post_wait_queue = wait_data; - adpt_post_wait_id = (++adpt_post_wait_id & 0x7fff); + adpt_post_wait_id++; + adpt_post_wait_id = (adpt_post_wait_id & 0x7fff); wait_data->id = adpt_post_wait_id; spin_unlock_irqrestore(&adpt_post_wait_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/esp.c linux.20pre2-ac1/drivers/scsi/esp.c --- linux.20pre2/drivers/scsi/esp.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/esp.c 2002-08-06 15:42:07.000000000 +0100 @@ -378,7 +378,7 @@ #endif #ifdef DEBUG_ESP_CMDS -extern inline void esp_cmd(struct esp *esp, u8 cmd) +static inline void esp_cmd(struct esp *esp, u8 cmd) { esp->espcmdlog[esp->espcmdent] = cmd; esp->espcmdent = (esp->espcmdent + 1) & 31; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/hosts.c linux.20pre2-ac1/drivers/scsi/hosts.c --- linux.20pre2/drivers/scsi/hosts.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/hosts.c 2002-08-13 14:34:11.000000000 +0100 @@ -81,8 +81,8 @@ struct Scsi_Host * scsi_hostlist; struct Scsi_Device_Template * scsi_devicelist; -int max_scsi_hosts; -int next_scsi_host; +int max_scsi_hosts; /* host_no for next new host */ +int next_scsi_host; /* count of registered scsi hosts */ void scsi_unregister(struct Scsi_Host * sh){ @@ -107,21 +107,8 @@ if (shn) shn->host_registered = 0; /* else {} : This should not happen, we should panic here... */ - /* If we are removing the last host registered, it is safe to reuse - * its host number (this avoids "holes" at boot time) (DB) - * It is also safe to reuse those of numbers directly below which have - * been released earlier (to avoid some holes in numbering). - */ - if(sh->host_no == max_scsi_hosts - 1) { - while(--max_scsi_hosts >= next_scsi_host) { - shpnt = scsi_hostlist; - while(shpnt && shpnt->host_no != max_scsi_hosts - 1) - shpnt = shpnt->next; - if(shpnt) - break; - } - } next_scsi_host--; + kfree((char *) sh); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/hosts.h linux.20pre2-ac1/drivers/scsi/hosts.h --- linux.20pre2/drivers/scsi/hosts.h 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/hosts.h 2002-08-14 14:41:30.000000000 +0100 @@ -291,9 +291,17 @@ */ unsigned emulated:1; + /* + * True for drivers that can do I/O from highmem + */ unsigned highmem_io:1; /* + * True for drivers which can handle variable length IO + */ + unsigned can_do_varyio:1; + + /* * Name of proc directory */ char *proc_name; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/ide-scsi.c linux.20pre2-ac1/drivers/scsi/ide-scsi.c --- linux.20pre2/drivers/scsi/ide-scsi.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/ide-scsi.c 2002-08-13 15:20:32.000000000 +0100 @@ -27,6 +27,7 @@ * detection of devices with CONFIG_SCSI_MULTI_LUN * Ver 0.8 Feb 05 99 Optical media need translation too. Reverse 0.7. * Ver 0.9 Jul 04 99 Fix a bug in SG_SET_TRANSFORM. + * Ver 0.91 Jun 10 02 Fix "off by one" error in transforms */ #define IDESCSI_VERSION "0.9" @@ -53,76 +54,77 @@ #include "ide-scsi.h" #include -#define IDESCSI_DEBUG_LOG 0 +#define IDESCSI_DEBUG_LOG 0 typedef struct idescsi_pc_s { - u8 c[12]; /* Actual packet bytes */ - int request_transfer; /* Bytes to transfer */ - int actually_transferred; /* Bytes actually transferred */ - int buffer_size; /* Size of our data buffer */ - struct request *rq; /* The corresponding request */ - byte *buffer; /* Data buffer */ - byte *current_position; /* Pointer into the above buffer */ - struct scatterlist *sg; /* Scatter gather table */ - int b_count; /* Bytes transferred from current entry */ - Scsi_Cmnd *scsi_cmd; /* SCSI command */ - void (*done)(Scsi_Cmnd *); /* Scsi completion routine */ - unsigned long flags; /* Status/Action flags */ - unsigned long timeout; /* Command timeout */ + u8 c[12]; /* Actual packet bytes */ + int request_transfer; /* Bytes to transfer */ + int actually_transferred; /* Bytes actually transferred */ + int buffer_size; /* Size of our data buffer */ + struct request *rq; /* The corresponding request */ + byte *buffer; /* Data buffer */ + byte *current_position; /* Pointer into the above buffer */ + struct scatterlist *sg; /* Scatter gather table */ + int b_count; /* Bytes transferred from current entry */ + Scsi_Cmnd *scsi_cmd; /* SCSI command */ + void (*done)(Scsi_Cmnd *); /* Scsi completion routine */ + unsigned long flags; /* Status/Action flags */ + unsigned long timeout; /* Command timeout */ } idescsi_pc_t; /* * Packet command status bits. */ -#define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */ -#define PC_WRITING 1 /* Data direction */ -#define PC_TRANSFORM 2 /* transform SCSI commands */ +#define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */ +#define PC_WRITING 1 /* Data direction */ +#define PC_TRANSFORM 2 /* transform SCSI commands */ /* * SCSI command transformation layer */ -#define IDESCSI_TRANSFORM 0 /* Enable/Disable transformation */ -#define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */ +#define IDESCSI_TRANSFORM 0 /* Enable/Disable transformation */ +#define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */ /* * Log flags */ -#define IDESCSI_LOG_CMD 0 /* Log SCSI commands */ +#define IDESCSI_LOG_CMD 0 /* Log SCSI commands */ typedef struct { ide_drive_t *drive; - idescsi_pc_t *pc; /* Current packet command */ - unsigned long flags; /* Status/Action flags */ - unsigned long transform; /* SCSI cmd translation layer */ - unsigned long log; /* log flags */ + idescsi_pc_t *pc; /* Current packet command */ + unsigned long flags; /* Status/Action flags */ + unsigned long transform; /* SCSI cmd translation layer */ + unsigned long log; /* log flags */ + devfs_handle_t de; /* pointer to IDE device */ } idescsi_scsi_t; /* * Per ATAPI device status bits. */ -#define IDESCSI_DRQ_INTERRUPT 0 /* DRQ interrupt device */ +#define IDESCSI_DRQ_INTERRUPT 0 /* DRQ interrupt device */ /* * ide-scsi requests. */ -#define IDESCSI_PC_RQ 90 +#define IDESCSI_PC_RQ 90 /* * Bits of the interrupt reason register. */ -#define IDESCSI_IREASON_COD 0x1 /* Information transferred is command */ -#define IDESCSI_IREASON_IO 0x2 /* The device requests us to read */ +#define IDESCSI_IREASON_COD 0x1 /* Information transferred is command */ +#define IDESCSI_IREASON_IO 0x2 /* The device requests us to read */ static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount) { while (bcount--) - IN_BYTE (IDE_DATA_REG); + IN_BYTE(IDE_DATA_REG); } static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount) { while (bcount--) - OUT_BYTE (0, IDE_DATA_REG); + OUT_BYTE(0, IDE_DATA_REG); } /* @@ -181,26 +183,38 @@ return; if (drive->media == ide_cdrom || drive->media == ide_optical) { if (c[0] == READ_6 || c[0] == WRITE_6) { - c[8] = c[4]; c[5] = c[3]; c[4] = c[2]; - c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0; + c[8] = c[4]; + c[5] = c[3]; + c[4] = c[2]; + c[3] = c[1] & 0x1f; + c[2] = 0; + c[1] &= 0xe0; c[0] += (READ_10 - READ_6); } if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) { + unsigned short new_len; if (!scsi_buf) return; if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL) return; memset(atapi_buf, 0, pc->buffer_size + 4); memset (c, 0, 12); - c[0] = sc[0] | 0x40; c[1] = sc[1]; c[2] = sc[2]; - c[8] = sc[4] + 4; c[9] = sc[5]; - if (sc[4] + 4 > 255) - c[7] = sc[4] + 4 - 255; + c[0] = sc[0] | 0x40; + c[1] = sc[1]; + c[2] = sc[2]; + new_len = sc[4] + 4; + c[8] = new_len; + c[9] = sc[5]; + c[7] = new_len >> 8; if (c[0] == MODE_SELECT_10) { - atapi_buf[1] = scsi_buf[0]; /* Mode data length */ - atapi_buf[2] = scsi_buf[1]; /* Medium type */ - atapi_buf[3] = scsi_buf[2]; /* Device specific parameter */ - atapi_buf[7] = scsi_buf[3]; /* Block descriptor length */ + /* Mode data length */ + atapi_buf[1] = scsi_buf[0]; + /* Medium type */ + atapi_buf[2] = scsi_buf[1]; + /* Device specific parameter */ + atapi_buf[3] = scsi_buf[2]; + /* Block descriptor length */ + atapi_buf[7] = scsi_buf[3]; memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4); } pc->buffer = atapi_buf; @@ -220,15 +234,21 @@ return; if (drive->media == ide_cdrom || drive->media == ide_optical) { if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) { - scsi_buf[0] = atapi_buf[1]; /* Mode data length */ - scsi_buf[1] = atapi_buf[2]; /* Medium type */ - scsi_buf[2] = atapi_buf[3]; /* Device specific parameter */ - scsi_buf[3] = atapi_buf[7]; /* Block descriptor length */ + /* Mode data length */ + scsi_buf[0] = atapi_buf[1]; + /* Medium type */ + scsi_buf[1] = atapi_buf[2]; + /* Device specific parameter */ + scsi_buf[2] = atapi_buf[3]; + /* Block descriptor length */ + scsi_buf[3] = atapi_buf[7]; memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8); } if (pc->c[0] == INQUIRY) { - scsi_buf[2] |= 2; /* ansi_revision */ - scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */ + /* ansi_revision */ + scsi_buf[2] |= 2; + /* response data format */ + scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; } } if (atapi_buf && atapi_buf != scsi_buf) @@ -256,34 +276,65 @@ printk("]\n"); } -static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup) +static int idescsi_do_end_request (ide_drive_t *drive, int uptodate) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&io_request_lock, flags); + rq = HWGROUP(drive)->rq; + + /* + * 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->dmaproc(ide_dma_on, drive); + } + + if (!end_that_request_first(rq, uptodate, drive->name)) { + add_blkdev_randomness(MAJOR(rq->rq_dev)); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&io_request_lock, flags); + return ret; +} + +static int idescsi_end_request (ide_drive_t *drive, int uptodate) { - ide_drive_t *drive = hwgroup->drive; idescsi_scsi_t *scsi = drive->driver_data; - struct request *rq = hwgroup->rq; + struct request *rq = HWGROUP(drive)->rq; idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer; int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); u8 *scsi_buf; unsigned long flags; if (rq->cmd != IDESCSI_PC_RQ) { - ide_end_request (uptodate, hwgroup); - return; + idescsi_do_end_request(drive, uptodate); + return 0; } ide_end_drive_cmd (drive, 0, 0); if (rq->errors >= ERROR_MAX) { pc->scsi_cmd->result = DID_ERROR << 16; if (log) - printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number); + printk ("ide-scsi: %s: I/O error for %lu\n", + drive->name, pc->scsi_cmd->serial_number); } else if (rq->errors) { pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); if (log) - printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number); + printk ("ide-scsi: %s: check condition for %lu\n", + drive->name, pc->scsi_cmd->serial_number); } else { pc->scsi_cmd->result = DID_OK << 16; idescsi_transform_pc2 (drive, pc); if (log) { - printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number); + printk ("ide-scsi: %s: suc %lu", drive->name, + pc->scsi_cmd->serial_number); if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) { printk(", rst = "); scsi_buf = pc->scsi_cmd->request_buffer; @@ -297,6 +348,7 @@ idescsi_free_bh (rq->bh); kfree(pc); kfree(rq); scsi->pc = NULL; + return 0; } static inline unsigned long get_timeout(idescsi_pc_t *pc) @@ -328,23 +380,23 @@ (void) (HWIF(drive)->dmaproc(ide_dma_end, drive)); } - status = GET_STAT(); /* Clear the interrupt */ + status = GET_STAT(); /* Clear the interrupt */ if ((status & DRQ_STAT) == 0) { /* No more interrupts */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); - ide__sti(); + local_irq_enable(); if (status & ERR_STAT) rq->errors++; - idescsi_end_request (1, HWGROUP(drive)); + idescsi_end_request(drive, 1); return ide_stopped; } - bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG); - ireason = IN_BYTE (IDE_IREASON_REG); + bcount = IN_BYTE(IDE_BCOUNTH_REG) << 8 | IN_BYTE(IDE_BCOUNTL_REG); + ireason = IN_BYTE(IDE_IREASON_REG); if (ireason & IDESCSI_IREASON_COD) { printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n"); - return ide_do_reset (drive); + return ide_do_reset(drive); } if (ireason & IDESCSI_IREASON_IO) { temp = pc->actually_transferred + bcount; @@ -362,7 +414,9 @@ } pc->actually_transferred += temp; pc->current_position += temp; - idescsi_discard_data (drive,bcount - temp); + idescsi_discard_data(drive,bcount - temp); + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); return ide_started; } @@ -374,24 +428,26 @@ if (ireason & IDESCSI_IREASON_IO) { clear_bit(PC_WRITING, &pc->flags); if (pc->sg) - idescsi_input_buffers (drive, pc, bcount); + idescsi_input_buffers(drive, pc, bcount); else - atapi_input_bytes (drive,pc->current_position,bcount); + atapi_input_bytes(drive,pc->current_position,bcount); } else { set_bit(PC_WRITING, &pc->flags); if (pc->sg) - idescsi_output_buffers (drive, pc, bcount); + idescsi_output_buffers(drive, pc, bcount); else - atapi_output_bytes (drive,pc->current_position,bcount); + atapi_output_bytes(drive,pc->current_position,bcount); } - pc->actually_transferred+=bcount; /* Update the current position */ + pc->actually_transferred+=bcount; /* Update the current position */ pc->current_position+=bcount; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); /* And set the interrupt handler again */ return ide_started; } -static ide_startstop_t idescsi_transfer_pc (ide_drive_t *drive) +static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) { idescsi_scsi_t *scsi = drive->driver_data; idescsi_pc_t *pc = scsi->pc; @@ -399,16 +455,19 @@ ide_startstop_t startstop; if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { - printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n"); + printk (KERN_ERR "ide-scsi: Strange, packet command " \ + "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason = IN_BYTE (IDE_IREASON_REG); + ireason = IN_BYTE(IDE_IREASON_REG); if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) { printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n"); - return ide_do_reset (drive); + return ide_do_reset(drive); } + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL); /* Set the interrupt routine */ - atapi_output_bytes (drive, scsi->pc->c, 12); /* Send the actual packet */ + atapi_output_bytes(drive, scsi->pc->c, 12); /* Send the actual packet */ return ide_started; } @@ -422,31 +481,36 @@ struct request *rq = pc->rq; int dma_ok = 0; - scsi->pc=pc; /* Set the current packet command */ - pc->actually_transferred=0; /* We haven't transferred any data yet */ + /* Set the current packet command */ + scsi->pc=pc; + /* We haven't transferred any data yet */ + pc->actually_transferred=0; pc->current_position=pc->buffer; - bcount = IDE_MIN (pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */ + /* Request to transfer the entire buffer at once */ + bcount = IDE_MIN (pc->request_transfer, 63 * 1024); if (drive->using_dma && rq->bh) dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); SELECT_DRIVE(HWIF(drive), drive); if (IDE_CONTROL_REG) - OUT_BYTE (drive->ctl,IDE_CONTROL_REG); - OUT_BYTE (dma_ok,IDE_FEATURE_REG); - OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG); - OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG); + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); + OUT_BYTE(dma_ok,IDE_FEATURE_REG); + OUT_BYTE(bcount >> 8,IDE_BCOUNTH_REG); + OUT_BYTE(bcount & 0xff,IDE_BCOUNTL_REG); if (dma_ok) { set_bit (PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL); - OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ return ide_started; } else { - OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); + OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); return idescsi_transfer_pc (drive); } } @@ -465,7 +529,7 @@ return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer); } printk (KERN_ERR "ide-scsi: %s: unsupported command in request queue (%x)\n", drive->name, rq->cmd); - idescsi_end_request (0,HWGROUP (drive)); + idescsi_end_request(drive, 0); return ide_stopped; } @@ -502,6 +566,8 @@ */ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id) { + int minor = (drive->select.b.unit) << PARTN_BITS; + DRIVER(drive)->busy++; idescsi_drives[id] = drive; drive->driver_data = scsi; @@ -516,6 +582,10 @@ set_bit(IDESCSI_LOG_CMD, &scsi->log); #endif /* IDESCSI_DEBUG_LOG */ idescsi_add_settings(drive); + scsi->de = devfs_register(drive->de, "generic", DEVFS_FL_DEFAULT, + HWIF(drive)->major, minor, + S_IFBLK | S_IRUSR | S_IWUSR, + ide_fops, NULL); } static int idescsi_cleanup (ide_drive_t *drive) @@ -524,11 +594,14 @@ if (ide_unregister_subdriver (drive)) return 1; + if (scsi->de) + devfs_unregister(scsi->de); drive->driver_data = NULL; kfree (scsi); return 0; } +int idescsi_init (void); int idescsi_reinit(ide_drive_t *drive); /* @@ -539,13 +612,21 @@ version: IDESCSI_VERSION, media: ide_scsi, busy: 0, +#ifdef CONFIG_IDEDMA_ONLYDISK + supports_dma: 0, +#else supports_dma: 1, +#endif supports_dsc_overlap: 0, cleanup: idescsi_cleanup, standby: NULL, + suspend: NULL, + resume: NULL, flushcache: NULL, do_request: idescsi_do_request, end_request: idescsi_end_request, + sense: NULL, + error: NULL, ioctl: NULL, open: idescsi_open, release: idescsi_ide_release, @@ -555,12 +636,12 @@ capacity: NULL, special: NULL, proc: NULL, + init: idescsi_init, reinit: idescsi_reinit, ata_prebuilder: NULL, atapi_prebuilder: NULL, }; -int idescsi_init (void); static ide_module_t idescsi_module = { IDE_DRIVER_MODULE, idescsi_init, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/Makefile linux.20pre2-ac1/drivers/scsi/Makefile --- linux.20pre2/drivers/scsi/Makefile 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/Makefile 2002-08-06 15:42:07.000000000 +0100 @@ -118,6 +118,7 @@ obj-$(CONFIG_SCSI_PLUTO) += pluto.o obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o +obj-$(CONFIG_SCSI_ZALON) += zalon7xx_mod.o obj-$(CONFIG_SCSI_PPA) += ppa.o obj-$(CONFIG_SCSI_IMM) += imm.o obj-$(CONFIG_JAZZ_ESP) += NCR53C9x.o jazz_esp.o @@ -136,7 +137,8 @@ obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o -list-multi := scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o +list-multi := scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o \ + zalon7xx_mod.o scsi_mod-objs := scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_proc.o scsi_error.o \ scsi_obsolete.o scsi_queue.o scsi_lib.o \ @@ -146,6 +148,7 @@ sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o a100u2w-objs := inia100.o i60uscsi.o +zalon7xx_mod-objs := zalon7xx.o ncr53c8xx.o cpqfc-objs := cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \ cpqfcTSworker.o cpqfcTStrigger.o @@ -167,6 +170,9 @@ a100u2w.o: $(a100u2w-objs) $(LD) -r -o $@ $(a100u2w-objs) +zalon7xx_mod.o: $(zalon7xx_mod-objs) + $(LD) -r -o $@ $(zalon7xx_mod-objs) + cpqfc.o: $(cpqfc-objs) $(LD) -r -o $@ $(cpqfc-objs) @@ -183,7 +189,7 @@ 53c7xx_d.h: 53c7xx.scr script_asm.pl ln -sf 53c7xx.scr fake7.c - $(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr7x0_family + $(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr710 mv script.h 53c7xx_d.h mv scriptu.h 53c7xx_u.h rm fake7.c @@ -194,7 +200,7 @@ sim710_d.h: sim710.scr script_asm.pl ln -sf sim710.scr fake7.c - $(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr7x0_family + $(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr710 mv script.h sim710_d.h mv scriptu.h sim710_u.h rm fake7.c diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/NCR53C9x.c linux.20pre2-ac1/drivers/scsi/NCR53C9x.c --- linux.20pre2/drivers/scsi/NCR53C9x.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/NCR53C9x.c 2002-08-06 15:42:07.000000000 +0100 @@ -289,7 +289,7 @@ #endif #ifdef DEBUG_ESP_CMDS -extern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, +inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs, unchar cmd) { esp->espcmdlog[esp->espcmdent] = cmd; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/qlogicisp.h linux.20pre2-ac1/drivers/scsi/qlogicisp.h --- linux.20pre2/drivers/scsi/qlogicisp.h 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/qlogicisp.h 2002-08-06 15:42:07.000000000 +0100 @@ -84,7 +84,8 @@ cmd_per_lun: 1, \ present: 0, \ unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING \ + use_clustering: DISABLE_CLUSTERING, \ + can_do_varyio: 1 \ } #endif /* _QLOGICISP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/script_asm.pl linux.20pre2-ac1/drivers/scsi/script_asm.pl --- linux.20pre2/drivers/scsi/script_asm.pl 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/script_asm.pl 2002-08-06 15:42:07.000000000 +0100 @@ -12,6 +12,7 @@ # # Support for 53c710 (via -ncr7x0_family switch) added by Richard # Hirst - 15th March 1997 +# Renamed to -ncr7x0_family to -ncr710, and added -ncr700 - 5th May 2000. # # 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 @@ -77,7 +78,7 @@ # and = 0x04_00_00_00 # add = 0x06_00_00_00 -if ($ncr7x0_family) { +if ($ncr700 || $ncr710) { %operators = ( '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, '&', 0x04_00_00_00, 'AND', 0x04_00_00_00, @@ -99,7 +100,24 @@ # Table of register addresses -if ($ncr7x0_family) { +if ($ncr700) { + %registers = ( + 'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3, + 'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7, + 'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11, + 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15, + 'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23, + 'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27, + 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31, + 'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, + 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39, + 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43, + 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47, + 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51, + 'DMODE', 52, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59, + ); +} +elsif ($ncr710) { %registers = ( 'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3, 'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7, @@ -171,7 +189,7 @@ # be escaped, I can't use the join() trick I used for the register # regex -if ($ncr7x0_family) { +if ($ncr700 || $ncr710) { $operator = '\||OR|AND|\&|\+'; } else { @@ -468,7 +486,7 @@ # Process MOVE length, address, WITH|WHEN phase instruction } elsif (/^\s*MOVE\s+(.*)/i) { $rest = $1; - if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) { + if (!$ncr700 && ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i)) { $transfer_addr = $1; $with_when = $2; $scsi_phase = $3; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/scsi.c linux.20pre2-ac1/drivers/scsi/scsi.c --- linux.20pre2/drivers/scsi/scsi.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/scsi.c 2002-08-13 14:35:10.000000000 +0100 @@ -352,8 +352,9 @@ int interruptable) { struct Scsi_Host *host; - Scsi_Cmnd *SCpnt = NULL; + Scsi_Cmnd *SCpnt; Scsi_Device *SDpnt; + struct list_head *lp; unsigned long flags; if (!device) @@ -364,7 +365,6 @@ spin_lock_irqsave(&device_request_lock, flags); while (1 == 1) { - SCpnt = NULL; if (!device->device_blocked) { if (device->single_lun) { /* @@ -404,26 +404,21 @@ * If asked to wait, we need to wait, otherwise * return NULL. */ - SCpnt = NULL; goto busy; } } /* - * Now we can check for a free command block for this device. + * Is there a free command block for this device? */ - for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) { - if (SCpnt->request.rq_status == RQ_INACTIVE) - break; - } + if (!list_empty(&device->sdev_free_q)) + goto found; } + /* - * If we couldn't find a free command block, and we have been + * Couldn't find a free command block, and we have been * asked to wait, then do so. */ - if (SCpnt) { - break; - } - busy: +busy: /* * If we have been asked to wait for a free block, then * wait here. @@ -475,12 +470,20 @@ return NULL; } } + continue; } else { spin_unlock_irqrestore(&device_request_lock, flags); return NULL; } } +found: + lp = device->sdev_free_q.next; + list_del(lp); + SCpnt = list_entry(lp, Scsi_Cmnd, sc_list); + if (SCpnt->request.rq_status != RQ_INACTIVE) + BUG(); + SCpnt->request.rq_status = RQ_SCSI_BUSY; SCpnt->request.waiting = NULL; /* And no one is waiting for this * to complete */ @@ -526,6 +529,9 @@ SDpnt = SCpnt->device; + /* command is now free - add to list */ + list_add(&SCpnt->sc_list, &SDpnt->sdev_free_q); + SCpnt->request.rq_status = RQ_INACTIVE; SCpnt->state = SCSI_STATE_UNUSED; SCpnt->owner = SCSI_OWNER_NOBODY; @@ -1448,6 +1454,7 @@ spin_lock_irqsave(&device_request_lock, flags); for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) { SDpnt->device_queue = SCnext = SCpnt->next; + list_del(&SCpnt->sc_list); kfree((char *) SCpnt); } SDpnt->has_cmdblocks = 0; @@ -1484,6 +1491,7 @@ SDpnt->queue_depth = 1; /* live to fight another day */ } SDpnt->device_queue = NULL; + INIT_LIST_HEAD(&SDpnt->sdev_free_q); for (j = 0; j < SDpnt->queue_depth; j++) { SCpnt = (Scsi_Cmnd *) @@ -1513,6 +1521,7 @@ SDpnt->device_queue = SCpnt; SCpnt->state = SCSI_STATE_UNUSED; SCpnt->owner = SCSI_OWNER_NOBODY; + list_add(&SCpnt->sc_list, &SDpnt->sdev_free_q); } if (j < SDpnt->queue_depth) { /* low on space (D.Gilbert 990424) */ printk(KERN_WARNING "scsi_build_commandblocks: want=%d, space for=%d blocks\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/scsi_error.c linux.20pre2-ac1/drivers/scsi/scsi_error.c --- linux.20pre2/drivers/scsi/scsi_error.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/scsi_error.c 2002-08-06 15:42:07.000000000 +0100 @@ -1884,7 +1884,7 @@ /* * Wake up the thread that created us. */ - SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", host->eh_notify->count.counter)); + SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", sem_getcount(host->eh_notify))); up(host->eh_notify); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/scsi.h linux.20pre2-ac1/drivers/scsi/scsi.h --- linux.20pre2/drivers/scsi/scsi.h 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/scsi.h 2002-08-14 14:41:30.000000000 +0100 @@ -48,7 +48,7 @@ #if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE)) #define scsi_to_pci_dma_dir(scsi_dir) ((int)(scsi_dir)) #else -extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir) +static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { if (scsi_dir == SCSI_DATA_UNKNOWN) return PCI_DMA_BIDIRECTIONAL; @@ -66,7 +66,7 @@ #if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE)) #define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) #else -extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir) +static inline int scsi_to_sbus_dma_dir(unsigned char scsi_dir) { if (scsi_dir == SCSI_DATA_UNKNOWN) return SBUS_DMA_BIDIRECTIONAL; @@ -558,6 +558,7 @@ int (*scsi_init_io_fn) (Scsi_Cmnd *); /* Used to initialize new request */ Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */ + struct list_head sdev_free_q; /* list of free cmds */ /* public: */ unsigned int id, lun, channel; @@ -775,6 +776,8 @@ * received on original command * (auto-sense) */ + struct list_head sc_list; /* Inactive cmd list linkage, guarded + * by device_request_lock. */ unsigned flags; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/scsi_lib.c linux.20pre2-ac1/drivers/scsi/scsi_lib.c --- linux.20pre2/drivers/scsi/scsi_lib.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/scsi_lib.c 2002-08-13 14:35:17.000000000 +0100 @@ -696,7 +696,7 @@ switch (SCpnt->sense_buffer[2]) { case ILLEGAL_REQUEST: - if (SCpnt->device->ten) { + if (SCpnt->device->ten && SCSI_RETRY_10(SCpnt->cmnd[0])) { SCpnt->device->ten = 0; /* * This will cause a retry with a 6-byte diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/sd.c linux.20pre2-ac1/drivers/scsi/sd.c --- linux.20pre2/drivers/scsi/sd.c 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/sd.c 2002-08-06 15:42:07.000000000 +0100 @@ -95,6 +95,7 @@ static int *sd_blocksizes; static int *sd_hardsizes; /* Hardware sector size */ static int *sd_max_sectors; +static char *sd_varyio; static int check_scsidisk_media_change(kdev_t); static int fop_revalidate_scsidisk(kdev_t); @@ -1140,6 +1141,12 @@ if (!sd_max_sectors) goto cleanup_max_sectors; + sd_varyio = kmalloc((sd_template.dev_max << 4), GFP_ATOMIC); + if (!sd_varyio) + goto cleanup_varyio; + + memset(sd_varyio, 0, (sd_template.dev_max << 4)); + for (i = 0; i < sd_template.dev_max << 4; i++) { sd_blocksizes[i] = 1024; sd_hardsizes[i] = 512; @@ -1204,6 +1211,8 @@ kfree(sd_gendisks); sd_gendisks = NULL; cleanup_sd_gendisks: + kfree(sd_varyio); +cleanup_varyio: kfree(sd_max_sectors); cleanup_max_sectors: kfree(sd_hardsizes); @@ -1268,6 +1277,8 @@ return 1; } +#define SD_DISK_MAJOR(i) SD_MAJOR((i) >> 4) + static int sd_attach(Scsi_Device * SDp) { unsigned int devnum; @@ -1306,6 +1317,14 @@ printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", SDp->removable ? "removable " : "", nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + + if (SDp->host->hostt->can_do_varyio) { + if (blkdev_varyio[SD_DISK_MAJOR(i)] == NULL) { + blkdev_varyio[SD_DISK_MAJOR(i)] = + sd_varyio + ((i / SCSI_DISKS_PER_MAJOR) << 8); + } + memset(blkdev_varyio[SD_DISK_MAJOR(i)] + (devnum << 4), 1, 16); + } return 0; } @@ -1438,6 +1457,7 @@ kfree(sd_sizes); kfree(sd_blocksizes); kfree(sd_hardsizes); + kfree(sd_varyio); for (i = 0; i < N_USED_SD_MAJORS; i++) { #if 0 /* XXX aren't we forgetting to deallocate something? */ kfree(sd_gendisks[i].de_arr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/sd.h linux.20pre2-ac1/drivers/scsi/sd.h --- linux.20pre2/drivers/scsi/sd.h 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/sd.h 2002-08-14 14:41:30.000000000 +0100 @@ -24,13 +24,13 @@ #endif typedef struct scsi_disk { - unsigned capacity; /* size in blocks */ Scsi_Device *device; - unsigned char ready; /* flag ready for FLOPTICAL */ - unsigned char write_prot; /* flag write_protect for rmvable dev */ - unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */ - unsigned char sector_bit_shift; /* power of 2 sectors per FS block */ + unsigned capacity; /* size in blocks */ + unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */ + unsigned char sector_bit_shift; /* power of 2 sectors per FS block */ unsigned has_part_table:1; /* has partition table */ + unsigned ready:1; /* flag ready for FLOPTICAL */ + unsigned write_prot:1; /* flag write_protect for rmvable dev */ } Scsi_Disk; extern int revalidate_scsidisk(kdev_t dev, int maxusage); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/scsi/sim710_d.h linux.20pre2-ac1/drivers/scsi/sim710_d.h --- linux.20pre2/drivers/scsi/sim710_d.h 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/scsi/sim710_d.h 2002-08-06 15:42:07.000000000 +0100 @@ -18,15 +18,12 @@ ABSOLUTE reselected_identify = 0 ABSOLUTE msgin_buf = 0 +ABSOLUTE msg_reject = 0 +ABSOLUTE test1_src = 0 +ABSOLUTE test1_dst = 0 -ABSOLUTE int_bad_extmsg1a = 0xab930000 -ABSOLUTE int_bad_extmsg1b = 0xab930001 -ABSOLUTE int_bad_extmsg2a = 0xab930002 -ABSOLUTE int_bad_extmsg2b = 0xab930003 -ABSOLUTE int_bad_extmsg3a = 0xab930004 -ABSOLUTE int_bad_extmsg3b = 0xab930005 ABSOLUTE int_bad_msg1 = 0xab930006 ABSOLUTE int_bad_msg2 = 0xab930007 ABSOLUTE int_bad_msg3 = 0xab930008 @@ -50,7 +47,7 @@ ABSOLUTE int_disc2 = 0xab93001a ABSOLUTE int_disc3 = 0xab93001b ABSOLUTE int_not_rej = 0xab93001c - +ABSOLUTE int_test1 = 0xab93001d @@ -65,6 +62,9 @@ +ABSOLUTE did_reject = 0x01 + + @@ -74,1641 +74,1709 @@ at 0x00000000 : */ 0x60000200,0x00000000, /* - MOVE SCRATCH0 & 0 TO SCRATCH0 - -at 0x00000002 : */ 0x7c340000,0x00000000, -/* ; Enable selection timer MOVE CTEST7 & 0xef TO CTEST7 -at 0x00000004 : */ 0x7c1bef00,0x00000000, +at 0x00000002 : */ 0x7c1bef00,0x00000000, /* SELECT ATN FROM dsa_select, reselect -at 0x00000006 : */ 0x43000000,0x00000c48, +at 0x00000004 : */ 0x43000000,0x00000cd0, /* JUMP get_status, WHEN STATUS -at 0x00000008 : */ 0x830b0000,0x000000a0, +at 0x00000006 : */ 0x830b0000,0x00000098, /* ; Disable selection timer MOVE CTEST7 | 0x10 TO CTEST7 -at 0x0000000a : */ 0x7a1b1000,0x00000000, +at 0x00000008 : */ 0x7a1b1000,0x00000000, /* MOVE SCRATCH0 | had_select TO SCRATCH0 -at 0x0000000c : */ 0x7a340100,0x00000000, +at 0x0000000a : */ 0x7a340100,0x00000000, /* INT int_sel_no_ident, IF NOT MSG_OUT -at 0x0000000e : */ 0x9e020000,0xab930013, +at 0x0000000c : */ 0x9e020000,0xab930013, /* MOVE SCRATCH0 | had_msgout TO SCRATCH0 -at 0x00000010 : */ 0x7a340200,0x00000000, +at 0x0000000e : */ 0x7a340200,0x00000000, /* MOVE FROM dsa_msgout, when MSG_OUT -at 0x00000012 : */ 0x1e000000,0x00000008, +at 0x00000010 : */ 0x1e000000,0x00000008, /* ENTRY done_ident done_ident: JUMP get_status, IF STATUS -at 0x00000014 : */ 0x830a0000,0x000000a0, +at 0x00000012 : */ 0x830a0000,0x00000098, /* redo_msgin1: JUMP get_msgin1, WHEN MSG_IN -at 0x00000016 : */ 0x870b0000,0x00000920, +at 0x00000014 : */ 0x870b0000,0x00000918, /* INT int_sel_not_cmd, IF NOT CMD -at 0x00000018 : */ 0x9a020000,0xab930014, +at 0x00000016 : */ 0x9a020000,0xab930014, /* ENTRY resume_cmd resume_cmd: MOVE SCRATCH0 | had_cmdout TO SCRATCH0 -at 0x0000001a : */ 0x7a340400,0x00000000, +at 0x00000018 : */ 0x7a340400,0x00000000, /* MOVE FROM dsa_cmnd, WHEN CMD -at 0x0000001c : */ 0x1a000000,0x00000010, +at 0x0000001a : */ 0x1a000000,0x00000010, /* ENTRY resume_pmm resume_pmm: redo_msgin2: JUMP get_msgin2, WHEN MSG_IN -at 0x0000001e : */ 0x870b0000,0x00000a20, +at 0x0000001c : */ 0x870b0000,0x00000a48, /* JUMP get_status, IF STATUS -at 0x00000020 : */ 0x830a0000,0x000000a0, +at 0x0000001e : */ 0x830a0000,0x00000098, /* JUMP input_data, IF DATA_IN -at 0x00000022 : */ 0x810a0000,0x000000e0, +at 0x00000020 : */ 0x810a0000,0x000000d8, /* JUMP output_data, IF DATA_OUT -at 0x00000024 : */ 0x800a0000,0x000004f8, +at 0x00000022 : */ 0x800a0000,0x000004f0, /* INT int_cmd_bad_phase -at 0x00000026 : */ 0x98080000,0xab930009, +at 0x00000024 : */ 0x98080000,0xab930009, /* get_status: ; Disable selection timer MOVE CTEST7 | 0x10 TO CTEST7 -at 0x00000028 : */ 0x7a1b1000,0x00000000, +at 0x00000026 : */ 0x7a1b1000,0x00000000, /* MOVE FROM dsa_status, WHEN STATUS -at 0x0000002a : */ 0x1b000000,0x00000018, +at 0x00000028 : */ 0x1b000000,0x00000018, /* INT int_status_not_msgin, WHEN NOT MSG_IN -at 0x0000002c : */ 0x9f030000,0xab930015, +at 0x0000002a : */ 0x9f030000,0xab930015, /* MOVE FROM dsa_msgin, WHEN MSG_IN -at 0x0000002e : */ 0x1f000000,0x00000020, +at 0x0000002c : */ 0x1f000000,0x00000020, /* INT int_not_cmd_complete, IF NOT 0x00 -at 0x00000030 : */ 0x98040000,0xab930012, +at 0x0000002e : */ 0x98040000,0xab930012, /* CLEAR ACK -at 0x00000032 : */ 0x60000040,0x00000000, +at 0x00000030 : */ 0x60000040,0x00000000, /* ENTRY wait_disc_complete wait_disc_complete: WAIT DISCONNECT -at 0x00000034 : */ 0x48000000,0x00000000, +at 0x00000032 : */ 0x48000000,0x00000000, /* INT int_cmd_complete -at 0x00000036 : */ 0x98080000,0xab93000a, +at 0x00000034 : */ 0x98080000,0xab93000a, /* input_data: MOVE SCRATCH0 | had_datain TO SCRATCH0 -at 0x00000038 : */ 0x7a340800,0x00000000, +at 0x00000036 : */ 0x7a340800,0x00000000, /* ENTRY patch_input_data patch_input_data: JUMP 0 -at 0x0000003a : */ 0x80080000,0x00000000, +at 0x00000038 : */ 0x80080000,0x00000000, /* MOVE FROM dsa_datain+0x0000, WHEN DATA_IN -at 0x0000003c : */ 0x19000000,0x00000028, +at 0x0000003a : */ 0x19000000,0x00000028, /* MOVE FROM dsa_datain+0x0008, WHEN DATA_IN -at 0x0000003e : */ 0x19000000,0x00000030, +at 0x0000003c : */ 0x19000000,0x00000030, /* MOVE FROM dsa_datain+0x0010, WHEN DATA_IN -at 0x00000040 : */ 0x19000000,0x00000038, +at 0x0000003e : */ 0x19000000,0x00000038, /* MOVE FROM dsa_datain+0x0018, WHEN DATA_IN -at 0x00000042 : */ 0x19000000,0x00000040, +at 0x00000040 : */ 0x19000000,0x00000040, /* MOVE FROM dsa_datain+0x0020, WHEN DATA_IN -at 0x00000044 : */ 0x19000000,0x00000048, +at 0x00000042 : */ 0x19000000,0x00000048, /* MOVE FROM dsa_datain+0x0028, WHEN DATA_IN -at 0x00000046 : */ 0x19000000,0x00000050, +at 0x00000044 : */ 0x19000000,0x00000050, /* MOVE FROM dsa_datain+0x0030, WHEN DATA_IN -at 0x00000048 : */ 0x19000000,0x00000058, +at 0x00000046 : */ 0x19000000,0x00000058, /* MOVE FROM dsa_datain+0x0038, WHEN DATA_IN -at 0x0000004a : */ 0x19000000,0x00000060, +at 0x00000048 : */ 0x19000000,0x00000060, /* MOVE FROM dsa_datain+0x0040, WHEN DATA_IN -at 0x0000004c : */ 0x19000000,0x00000068, +at 0x0000004a : */ 0x19000000,0x00000068, /* MOVE FROM dsa_datain+0x0048, WHEN DATA_IN -at 0x0000004e : */ 0x19000000,0x00000070, +at 0x0000004c : */ 0x19000000,0x00000070, /* MOVE FROM dsa_datain+0x0050, WHEN DATA_IN -at 0x00000050 : */ 0x19000000,0x00000078, +at 0x0000004e : */ 0x19000000,0x00000078, /* MOVE FROM dsa_datain+0x0058, WHEN DATA_IN -at 0x00000052 : */ 0x19000000,0x00000080, +at 0x00000050 : */ 0x19000000,0x00000080, /* MOVE FROM dsa_datain+0x0060, WHEN DATA_IN -at 0x00000054 : */ 0x19000000,0x00000088, +at 0x00000052 : */ 0x19000000,0x00000088, /* MOVE FROM dsa_datain+0x0068, WHEN DATA_IN -at 0x00000056 : */ 0x19000000,0x00000090, +at 0x00000054 : */ 0x19000000,0x00000090, /* MOVE FROM dsa_datain+0x0070, WHEN DATA_IN -at 0x00000058 : */ 0x19000000,0x00000098, +at 0x00000056 : */ 0x19000000,0x00000098, /* MOVE FROM dsa_datain+0x0078, WHEN DATA_IN -at 0x0000005a : */ 0x19000000,0x000000a0, +at 0x00000058 : */ 0x19000000,0x000000a0, /* MOVE FROM dsa_datain+0x0080, WHEN DATA_IN -at 0x0000005c : */ 0x19000000,0x000000a8, +at 0x0000005a : */ 0x19000000,0x000000a8, /* MOVE FROM dsa_datain+0x0088, WHEN DATA_IN -at 0x0000005e : */ 0x19000000,0x000000b0, +at 0x0000005c : */ 0x19000000,0x000000b0, /* MOVE FROM dsa_datain+0x0090, WHEN DATA_IN -at 0x00000060 : */ 0x19000000,0x000000b8, +at 0x0000005e : */ 0x19000000,0x000000b8, /* MOVE FROM dsa_datain+0x0098, WHEN DATA_IN -at 0x00000062 : */ 0x19000000,0x000000c0, +at 0x00000060 : */ 0x19000000,0x000000c0, /* MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN -at 0x00000064 : */ 0x19000000,0x000000c8, +at 0x00000062 : */ 0x19000000,0x000000c8, /* MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN -at 0x00000066 : */ 0x19000000,0x000000d0, +at 0x00000064 : */ 0x19000000,0x000000d0, /* MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN -at 0x00000068 : */ 0x19000000,0x000000d8, +at 0x00000066 : */ 0x19000000,0x000000d8, /* MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN -at 0x0000006a : */ 0x19000000,0x000000e0, +at 0x00000068 : */ 0x19000000,0x000000e0, /* MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN -at 0x0000006c : */ 0x19000000,0x000000e8, +at 0x0000006a : */ 0x19000000,0x000000e8, /* MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN -at 0x0000006e : */ 0x19000000,0x000000f0, +at 0x0000006c : */ 0x19000000,0x000000f0, /* MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN -at 0x00000070 : */ 0x19000000,0x000000f8, +at 0x0000006e : */ 0x19000000,0x000000f8, /* MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN -at 0x00000072 : */ 0x19000000,0x00000100, +at 0x00000070 : */ 0x19000000,0x00000100, /* MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN -at 0x00000074 : */ 0x19000000,0x00000108, +at 0x00000072 : */ 0x19000000,0x00000108, /* MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN -at 0x00000076 : */ 0x19000000,0x00000110, +at 0x00000074 : */ 0x19000000,0x00000110, /* MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN -at 0x00000078 : */ 0x19000000,0x00000118, +at 0x00000076 : */ 0x19000000,0x00000118, /* MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN -at 0x0000007a : */ 0x19000000,0x00000120, +at 0x00000078 : */ 0x19000000,0x00000120, /* MOVE FROM dsa_datain+0x0100, WHEN DATA_IN -at 0x0000007c : */ 0x19000000,0x00000128, +at 0x0000007a : */ 0x19000000,0x00000128, /* MOVE FROM dsa_datain+0x0108, WHEN DATA_IN -at 0x0000007e : */ 0x19000000,0x00000130, +at 0x0000007c : */ 0x19000000,0x00000130, /* MOVE FROM dsa_datain+0x0110, WHEN DATA_IN -at 0x00000080 : */ 0x19000000,0x00000138, +at 0x0000007e : */ 0x19000000,0x00000138, /* MOVE FROM dsa_datain+0x0118, WHEN DATA_IN -at 0x00000082 : */ 0x19000000,0x00000140, +at 0x00000080 : */ 0x19000000,0x00000140, /* MOVE FROM dsa_datain+0x0120, WHEN DATA_IN -at 0x00000084 : */ 0x19000000,0x00000148, +at 0x00000082 : */ 0x19000000,0x00000148, /* MOVE FROM dsa_datain+0x0128, WHEN DATA_IN -at 0x00000086 : */ 0x19000000,0x00000150, +at 0x00000084 : */ 0x19000000,0x00000150, /* MOVE FROM dsa_datain+0x0130, WHEN DATA_IN -at 0x00000088 : */ 0x19000000,0x00000158, +at 0x00000086 : */ 0x19000000,0x00000158, /* MOVE FROM dsa_datain+0x0138, WHEN DATA_IN -at 0x0000008a : */ 0x19000000,0x00000160, +at 0x00000088 : */ 0x19000000,0x00000160, /* MOVE FROM dsa_datain+0x0140, WHEN DATA_IN -at 0x0000008c : */ 0x19000000,0x00000168, +at 0x0000008a : */ 0x19000000,0x00000168, /* MOVE FROM dsa_datain+0x0148, WHEN DATA_IN -at 0x0000008e : */ 0x19000000,0x00000170, +at 0x0000008c : */ 0x19000000,0x00000170, /* MOVE FROM dsa_datain+0x0150, WHEN DATA_IN -at 0x00000090 : */ 0x19000000,0x00000178, +at 0x0000008e : */ 0x19000000,0x00000178, /* MOVE FROM dsa_datain+0x0158, WHEN DATA_IN -at 0x00000092 : */ 0x19000000,0x00000180, +at 0x00000090 : */ 0x19000000,0x00000180, /* MOVE FROM dsa_datain+0x0160, WHEN DATA_IN -at 0x00000094 : */ 0x19000000,0x00000188, +at 0x00000092 : */ 0x19000000,0x00000188, /* MOVE FROM dsa_datain+0x0168, WHEN DATA_IN -at 0x00000096 : */ 0x19000000,0x00000190, +at 0x00000094 : */ 0x19000000,0x00000190, /* MOVE FROM dsa_datain+0x0170, WHEN DATA_IN -at 0x00000098 : */ 0x19000000,0x00000198, +at 0x00000096 : */ 0x19000000,0x00000198, /* MOVE FROM dsa_datain+0x0178, WHEN DATA_IN -at 0x0000009a : */ 0x19000000,0x000001a0, +at 0x00000098 : */ 0x19000000,0x000001a0, /* MOVE FROM dsa_datain+0x0180, WHEN DATA_IN -at 0x0000009c : */ 0x19000000,0x000001a8, +at 0x0000009a : */ 0x19000000,0x000001a8, /* MOVE FROM dsa_datain+0x0188, WHEN DATA_IN -at 0x0000009e : */ 0x19000000,0x000001b0, +at 0x0000009c : */ 0x19000000,0x000001b0, /* MOVE FROM dsa_datain+0x0190, WHEN DATA_IN -at 0x000000a0 : */ 0x19000000,0x000001b8, +at 0x0000009e : */ 0x19000000,0x000001b8, /* MOVE FROM dsa_datain+0x0198, WHEN DATA_IN -at 0x000000a2 : */ 0x19000000,0x000001c0, +at 0x000000a0 : */ 0x19000000,0x000001c0, /* MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN -at 0x000000a4 : */ 0x19000000,0x000001c8, +at 0x000000a2 : */ 0x19000000,0x000001c8, /* MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN -at 0x000000a6 : */ 0x19000000,0x000001d0, +at 0x000000a4 : */ 0x19000000,0x000001d0, /* MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN -at 0x000000a8 : */ 0x19000000,0x000001d8, +at 0x000000a6 : */ 0x19000000,0x000001d8, /* MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN -at 0x000000aa : */ 0x19000000,0x000001e0, +at 0x000000a8 : */ 0x19000000,0x000001e0, /* MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN -at 0x000000ac : */ 0x19000000,0x000001e8, +at 0x000000aa : */ 0x19000000,0x000001e8, /* MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN -at 0x000000ae : */ 0x19000000,0x000001f0, +at 0x000000ac : */ 0x19000000,0x000001f0, /* MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN -at 0x000000b0 : */ 0x19000000,0x000001f8, +at 0x000000ae : */ 0x19000000,0x000001f8, /* MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN -at 0x000000b2 : */ 0x19000000,0x00000200, +at 0x000000b0 : */ 0x19000000,0x00000200, /* MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN -at 0x000000b4 : */ 0x19000000,0x00000208, +at 0x000000b2 : */ 0x19000000,0x00000208, /* MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN -at 0x000000b6 : */ 0x19000000,0x00000210, +at 0x000000b4 : */ 0x19000000,0x00000210, /* MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN -at 0x000000b8 : */ 0x19000000,0x00000218, +at 0x000000b6 : */ 0x19000000,0x00000218, /* MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN -at 0x000000ba : */ 0x19000000,0x00000220, +at 0x000000b8 : */ 0x19000000,0x00000220, /* MOVE FROM dsa_datain+0x0200, WHEN DATA_IN -at 0x000000bc : */ 0x19000000,0x00000228, +at 0x000000ba : */ 0x19000000,0x00000228, /* MOVE FROM dsa_datain+0x0208, WHEN DATA_IN -at 0x000000be : */ 0x19000000,0x00000230, +at 0x000000bc : */ 0x19000000,0x00000230, /* MOVE FROM dsa_datain+0x0210, WHEN DATA_IN -at 0x000000c0 : */ 0x19000000,0x00000238, +at 0x000000be : */ 0x19000000,0x00000238, /* MOVE FROM dsa_datain+0x0218, WHEN DATA_IN -at 0x000000c2 : */ 0x19000000,0x00000240, +at 0x000000c0 : */ 0x19000000,0x00000240, /* MOVE FROM dsa_datain+0x0220, WHEN DATA_IN -at 0x000000c4 : */ 0x19000000,0x00000248, +at 0x000000c2 : */ 0x19000000,0x00000248, /* MOVE FROM dsa_datain+0x0228, WHEN DATA_IN -at 0x000000c6 : */ 0x19000000,0x00000250, +at 0x000000c4 : */ 0x19000000,0x00000250, /* MOVE FROM dsa_datain+0x0230, WHEN DATA_IN -at 0x000000c8 : */ 0x19000000,0x00000258, +at 0x000000c6 : */ 0x19000000,0x00000258, /* MOVE FROM dsa_datain+0x0238, WHEN DATA_IN -at 0x000000ca : */ 0x19000000,0x00000260, +at 0x000000c8 : */ 0x19000000,0x00000260, /* MOVE FROM dsa_datain+0x0240, WHEN DATA_IN -at 0x000000cc : */ 0x19000000,0x00000268, +at 0x000000ca : */ 0x19000000,0x00000268, /* MOVE FROM dsa_datain+0x0248, WHEN DATA_IN -at 0x000000ce : */ 0x19000000,0x00000270, +at 0x000000cc : */ 0x19000000,0x00000270, /* MOVE FROM dsa_datain+0x0250, WHEN DATA_IN -at 0x000000d0 : */ 0x19000000,0x00000278, +at 0x000000ce : */ 0x19000000,0x00000278, /* MOVE FROM dsa_datain+0x0258, WHEN DATA_IN -at 0x000000d2 : */ 0x19000000,0x00000280, +at 0x000000d0 : */ 0x19000000,0x00000280, /* MOVE FROM dsa_datain+0x0260, WHEN DATA_IN -at 0x000000d4 : */ 0x19000000,0x00000288, +at 0x000000d2 : */ 0x19000000,0x00000288, /* MOVE FROM dsa_datain+0x0268, WHEN DATA_IN -at 0x000000d6 : */ 0x19000000,0x00000290, +at 0x000000d4 : */ 0x19000000,0x00000290, /* MOVE FROM dsa_datain+0x0270, WHEN DATA_IN -at 0x000000d8 : */ 0x19000000,0x00000298, +at 0x000000d6 : */ 0x19000000,0x00000298, /* MOVE FROM dsa_datain+0x0278, WHEN DATA_IN -at 0x000000da : */ 0x19000000,0x000002a0, +at 0x000000d8 : */ 0x19000000,0x000002a0, /* MOVE FROM dsa_datain+0x0280, WHEN DATA_IN -at 0x000000dc : */ 0x19000000,0x000002a8, +at 0x000000da : */ 0x19000000,0x000002a8, /* MOVE FROM dsa_datain+0x0288, WHEN DATA_IN -at 0x000000de : */ 0x19000000,0x000002b0, +at 0x000000dc : */ 0x19000000,0x000002b0, /* MOVE FROM dsa_datain+0x0290, WHEN DATA_IN -at 0x000000e0 : */ 0x19000000,0x000002b8, +at 0x000000de : */ 0x19000000,0x000002b8, /* MOVE FROM dsa_datain+0x0298, WHEN DATA_IN -at 0x000000e2 : */ 0x19000000,0x000002c0, +at 0x000000e0 : */ 0x19000000,0x000002c0, /* MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN -at 0x000000e4 : */ 0x19000000,0x000002c8, +at 0x000000e2 : */ 0x19000000,0x000002c8, /* MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN -at 0x000000e6 : */ 0x19000000,0x000002d0, +at 0x000000e4 : */ 0x19000000,0x000002d0, /* MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN -at 0x000000e8 : */ 0x19000000,0x000002d8, +at 0x000000e6 : */ 0x19000000,0x000002d8, /* MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN -at 0x000000ea : */ 0x19000000,0x000002e0, +at 0x000000e8 : */ 0x19000000,0x000002e0, /* MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN -at 0x000000ec : */ 0x19000000,0x000002e8, +at 0x000000ea : */ 0x19000000,0x000002e8, /* MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN -at 0x000000ee : */ 0x19000000,0x000002f0, +at 0x000000ec : */ 0x19000000,0x000002f0, /* MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN -at 0x000000f0 : */ 0x19000000,0x000002f8, +at 0x000000ee : */ 0x19000000,0x000002f8, /* MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN -at 0x000000f2 : */ 0x19000000,0x00000300, +at 0x000000f0 : */ 0x19000000,0x00000300, /* MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN -at 0x000000f4 : */ 0x19000000,0x00000308, +at 0x000000f2 : */ 0x19000000,0x00000308, /* MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN -at 0x000000f6 : */ 0x19000000,0x00000310, +at 0x000000f4 : */ 0x19000000,0x00000310, /* MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN -at 0x000000f8 : */ 0x19000000,0x00000318, +at 0x000000f6 : */ 0x19000000,0x00000318, /* MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN -at 0x000000fa : */ 0x19000000,0x00000320, +at 0x000000f8 : */ 0x19000000,0x00000320, /* MOVE FROM dsa_datain+0x0300, WHEN DATA_IN -at 0x000000fc : */ 0x19000000,0x00000328, +at 0x000000fa : */ 0x19000000,0x00000328, /* MOVE FROM dsa_datain+0x0308, WHEN DATA_IN -at 0x000000fe : */ 0x19000000,0x00000330, +at 0x000000fc : */ 0x19000000,0x00000330, /* MOVE FROM dsa_datain+0x0310, WHEN DATA_IN -at 0x00000100 : */ 0x19000000,0x00000338, +at 0x000000fe : */ 0x19000000,0x00000338, /* MOVE FROM dsa_datain+0x0318, WHEN DATA_IN -at 0x00000102 : */ 0x19000000,0x00000340, +at 0x00000100 : */ 0x19000000,0x00000340, /* MOVE FROM dsa_datain+0x0320, WHEN DATA_IN -at 0x00000104 : */ 0x19000000,0x00000348, +at 0x00000102 : */ 0x19000000,0x00000348, /* MOVE FROM dsa_datain+0x0328, WHEN DATA_IN -at 0x00000106 : */ 0x19000000,0x00000350, +at 0x00000104 : */ 0x19000000,0x00000350, /* MOVE FROM dsa_datain+0x0330, WHEN DATA_IN -at 0x00000108 : */ 0x19000000,0x00000358, +at 0x00000106 : */ 0x19000000,0x00000358, /* MOVE FROM dsa_datain+0x0338, WHEN DATA_IN -at 0x0000010a : */ 0x19000000,0x00000360, +at 0x00000108 : */ 0x19000000,0x00000360, /* MOVE FROM dsa_datain+0x0340, WHEN DATA_IN -at 0x0000010c : */ 0x19000000,0x00000368, +at 0x0000010a : */ 0x19000000,0x00000368, /* MOVE FROM dsa_datain+0x0348, WHEN DATA_IN -at 0x0000010e : */ 0x19000000,0x00000370, +at 0x0000010c : */ 0x19000000,0x00000370, /* MOVE FROM dsa_datain+0x0350, WHEN DATA_IN -at 0x00000110 : */ 0x19000000,0x00000378, +at 0x0000010e : */ 0x19000000,0x00000378, /* MOVE FROM dsa_datain+0x0358, WHEN DATA_IN -at 0x00000112 : */ 0x19000000,0x00000380, +at 0x00000110 : */ 0x19000000,0x00000380, /* MOVE FROM dsa_datain+0x0360, WHEN DATA_IN -at 0x00000114 : */ 0x19000000,0x00000388, +at 0x00000112 : */ 0x19000000,0x00000388, /* MOVE FROM dsa_datain+0x0368, WHEN DATA_IN -at 0x00000116 : */ 0x19000000,0x00000390, +at 0x00000114 : */ 0x19000000,0x00000390, /* MOVE FROM dsa_datain+0x0370, WHEN DATA_IN -at 0x00000118 : */ 0x19000000,0x00000398, +at 0x00000116 : */ 0x19000000,0x00000398, /* MOVE FROM dsa_datain+0x0378, WHEN DATA_IN -at 0x0000011a : */ 0x19000000,0x000003a0, +at 0x00000118 : */ 0x19000000,0x000003a0, /* MOVE FROM dsa_datain+0x0380, WHEN DATA_IN -at 0x0000011c : */ 0x19000000,0x000003a8, +at 0x0000011a : */ 0x19000000,0x000003a8, /* MOVE FROM dsa_datain+0x0388, WHEN DATA_IN -at 0x0000011e : */ 0x19000000,0x000003b0, +at 0x0000011c : */ 0x19000000,0x000003b0, /* MOVE FROM dsa_datain+0x0390, WHEN DATA_IN -at 0x00000120 : */ 0x19000000,0x000003b8, +at 0x0000011e : */ 0x19000000,0x000003b8, /* MOVE FROM dsa_datain+0x0398, WHEN DATA_IN -at 0x00000122 : */ 0x19000000,0x000003c0, +at 0x00000120 : */ 0x19000000,0x000003c0, /* MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN -at 0x00000124 : */ 0x19000000,0x000003c8, +at 0x00000122 : */ 0x19000000,0x000003c8, /* MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN -at 0x00000126 : */ 0x19000000,0x000003d0, +at 0x00000124 : */ 0x19000000,0x000003d0, /* MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN -at 0x00000128 : */ 0x19000000,0x000003d8, +at 0x00000126 : */ 0x19000000,0x000003d8, /* MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN -at 0x0000012a : */ 0x19000000,0x000003e0, +at 0x00000128 : */ 0x19000000,0x000003e0, /* MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN -at 0x0000012c : */ 0x19000000,0x000003e8, +at 0x0000012a : */ 0x19000000,0x000003e8, /* MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN -at 0x0000012e : */ 0x19000000,0x000003f0, +at 0x0000012c : */ 0x19000000,0x000003f0, /* MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN -at 0x00000130 : */ 0x19000000,0x000003f8, +at 0x0000012e : */ 0x19000000,0x000003f8, /* MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN -at 0x00000132 : */ 0x19000000,0x00000400, +at 0x00000130 : */ 0x19000000,0x00000400, /* MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN -at 0x00000134 : */ 0x19000000,0x00000408, +at 0x00000132 : */ 0x19000000,0x00000408, /* MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN -at 0x00000136 : */ 0x19000000,0x00000410, +at 0x00000134 : */ 0x19000000,0x00000410, /* MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN -at 0x00000138 : */ 0x19000000,0x00000418, +at 0x00000136 : */ 0x19000000,0x00000418, /* MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN -at 0x0000013a : */ 0x19000000,0x00000420, +at 0x00000138 : */ 0x19000000,0x00000420, /* JUMP end_data_trans -at 0x0000013c : */ 0x80080000,0x00000908, +at 0x0000013a : */ 0x80080000,0x00000900, /* output_data: MOVE SCRATCH0 | had_dataout TO SCRATCH0 -at 0x0000013e : */ 0x7a341000,0x00000000, +at 0x0000013c : */ 0x7a341000,0x00000000, /* ENTRY patch_output_data patch_output_data: JUMP 0 -at 0x00000140 : */ 0x80080000,0x00000000, +at 0x0000013e : */ 0x80080000,0x00000000, /* MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT -at 0x00000142 : */ 0x18000000,0x00000428, +at 0x00000140 : */ 0x18000000,0x00000428, /* MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT -at 0x00000144 : */ 0x18000000,0x00000430, +at 0x00000142 : */ 0x18000000,0x00000430, /* MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT -at 0x00000146 : */ 0x18000000,0x00000438, +at 0x00000144 : */ 0x18000000,0x00000438, /* MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT -at 0x00000148 : */ 0x18000000,0x00000440, +at 0x00000146 : */ 0x18000000,0x00000440, /* MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT -at 0x0000014a : */ 0x18000000,0x00000448, +at 0x00000148 : */ 0x18000000,0x00000448, /* MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT -at 0x0000014c : */ 0x18000000,0x00000450, +at 0x0000014a : */ 0x18000000,0x00000450, /* MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT -at 0x0000014e : */ 0x18000000,0x00000458, +at 0x0000014c : */ 0x18000000,0x00000458, /* MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT -at 0x00000150 : */ 0x18000000,0x00000460, +at 0x0000014e : */ 0x18000000,0x00000460, /* MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT -at 0x00000152 : */ 0x18000000,0x00000468, +at 0x00000150 : */ 0x18000000,0x00000468, /* MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT -at 0x00000154 : */ 0x18000000,0x00000470, +at 0x00000152 : */ 0x18000000,0x00000470, /* MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT -at 0x00000156 : */ 0x18000000,0x00000478, +at 0x00000154 : */ 0x18000000,0x00000478, /* MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT -at 0x00000158 : */ 0x18000000,0x00000480, +at 0x00000156 : */ 0x18000000,0x00000480, /* MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT -at 0x0000015a : */ 0x18000000,0x00000488, +at 0x00000158 : */ 0x18000000,0x00000488, /* MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT -at 0x0000015c : */ 0x18000000,0x00000490, +at 0x0000015a : */ 0x18000000,0x00000490, /* MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT -at 0x0000015e : */ 0x18000000,0x00000498, +at 0x0000015c : */ 0x18000000,0x00000498, /* MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT -at 0x00000160 : */ 0x18000000,0x000004a0, +at 0x0000015e : */ 0x18000000,0x000004a0, /* MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT -at 0x00000162 : */ 0x18000000,0x000004a8, +at 0x00000160 : */ 0x18000000,0x000004a8, /* MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT -at 0x00000164 : */ 0x18000000,0x000004b0, +at 0x00000162 : */ 0x18000000,0x000004b0, /* MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT -at 0x00000166 : */ 0x18000000,0x000004b8, +at 0x00000164 : */ 0x18000000,0x000004b8, /* MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT -at 0x00000168 : */ 0x18000000,0x000004c0, +at 0x00000166 : */ 0x18000000,0x000004c0, /* MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT -at 0x0000016a : */ 0x18000000,0x000004c8, +at 0x00000168 : */ 0x18000000,0x000004c8, /* MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT -at 0x0000016c : */ 0x18000000,0x000004d0, +at 0x0000016a : */ 0x18000000,0x000004d0, /* MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT -at 0x0000016e : */ 0x18000000,0x000004d8, +at 0x0000016c : */ 0x18000000,0x000004d8, /* MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT -at 0x00000170 : */ 0x18000000,0x000004e0, +at 0x0000016e : */ 0x18000000,0x000004e0, /* MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT -at 0x00000172 : */ 0x18000000,0x000004e8, +at 0x00000170 : */ 0x18000000,0x000004e8, /* MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT -at 0x00000174 : */ 0x18000000,0x000004f0, +at 0x00000172 : */ 0x18000000,0x000004f0, /* MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT -at 0x00000176 : */ 0x18000000,0x000004f8, +at 0x00000174 : */ 0x18000000,0x000004f8, /* MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT -at 0x00000178 : */ 0x18000000,0x00000500, +at 0x00000176 : */ 0x18000000,0x00000500, /* MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT -at 0x0000017a : */ 0x18000000,0x00000508, +at 0x00000178 : */ 0x18000000,0x00000508, /* MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT -at 0x0000017c : */ 0x18000000,0x00000510, +at 0x0000017a : */ 0x18000000,0x00000510, /* MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT -at 0x0000017e : */ 0x18000000,0x00000518, +at 0x0000017c : */ 0x18000000,0x00000518, /* MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT -at 0x00000180 : */ 0x18000000,0x00000520, +at 0x0000017e : */ 0x18000000,0x00000520, /* MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT -at 0x00000182 : */ 0x18000000,0x00000528, +at 0x00000180 : */ 0x18000000,0x00000528, /* MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT -at 0x00000184 : */ 0x18000000,0x00000530, +at 0x00000182 : */ 0x18000000,0x00000530, /* MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT -at 0x00000186 : */ 0x18000000,0x00000538, +at 0x00000184 : */ 0x18000000,0x00000538, /* MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT -at 0x00000188 : */ 0x18000000,0x00000540, +at 0x00000186 : */ 0x18000000,0x00000540, /* MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT -at 0x0000018a : */ 0x18000000,0x00000548, +at 0x00000188 : */ 0x18000000,0x00000548, /* MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT -at 0x0000018c : */ 0x18000000,0x00000550, +at 0x0000018a : */ 0x18000000,0x00000550, /* MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT -at 0x0000018e : */ 0x18000000,0x00000558, +at 0x0000018c : */ 0x18000000,0x00000558, /* MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT -at 0x00000190 : */ 0x18000000,0x00000560, +at 0x0000018e : */ 0x18000000,0x00000560, /* MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT -at 0x00000192 : */ 0x18000000,0x00000568, +at 0x00000190 : */ 0x18000000,0x00000568, /* MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT -at 0x00000194 : */ 0x18000000,0x00000570, +at 0x00000192 : */ 0x18000000,0x00000570, /* MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT -at 0x00000196 : */ 0x18000000,0x00000578, +at 0x00000194 : */ 0x18000000,0x00000578, /* MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT -at 0x00000198 : */ 0x18000000,0x00000580, +at 0x00000196 : */ 0x18000000,0x00000580, /* MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT -at 0x0000019a : */ 0x18000000,0x00000588, +at 0x00000198 : */ 0x18000000,0x00000588, /* MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT -at 0x0000019c : */ 0x18000000,0x00000590, +at 0x0000019a : */ 0x18000000,0x00000590, /* MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT -at 0x0000019e : */ 0x18000000,0x00000598, +at 0x0000019c : */ 0x18000000,0x00000598, /* MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT -at 0x000001a0 : */ 0x18000000,0x000005a0, +at 0x0000019e : */ 0x18000000,0x000005a0, /* MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT -at 0x000001a2 : */ 0x18000000,0x000005a8, +at 0x000001a0 : */ 0x18000000,0x000005a8, /* MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT -at 0x000001a4 : */ 0x18000000,0x000005b0, +at 0x000001a2 : */ 0x18000000,0x000005b0, /* MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT -at 0x000001a6 : */ 0x18000000,0x000005b8, +at 0x000001a4 : */ 0x18000000,0x000005b8, /* MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT -at 0x000001a8 : */ 0x18000000,0x000005c0, +at 0x000001a6 : */ 0x18000000,0x000005c0, /* MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT -at 0x000001aa : */ 0x18000000,0x000005c8, +at 0x000001a8 : */ 0x18000000,0x000005c8, /* MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT -at 0x000001ac : */ 0x18000000,0x000005d0, +at 0x000001aa : */ 0x18000000,0x000005d0, /* MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT -at 0x000001ae : */ 0x18000000,0x000005d8, +at 0x000001ac : */ 0x18000000,0x000005d8, /* MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT -at 0x000001b0 : */ 0x18000000,0x000005e0, +at 0x000001ae : */ 0x18000000,0x000005e0, /* MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT -at 0x000001b2 : */ 0x18000000,0x000005e8, +at 0x000001b0 : */ 0x18000000,0x000005e8, /* MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT -at 0x000001b4 : */ 0x18000000,0x000005f0, +at 0x000001b2 : */ 0x18000000,0x000005f0, /* MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT -at 0x000001b6 : */ 0x18000000,0x000005f8, +at 0x000001b4 : */ 0x18000000,0x000005f8, /* MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT -at 0x000001b8 : */ 0x18000000,0x00000600, +at 0x000001b6 : */ 0x18000000,0x00000600, /* MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT -at 0x000001ba : */ 0x18000000,0x00000608, +at 0x000001b8 : */ 0x18000000,0x00000608, /* MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT -at 0x000001bc : */ 0x18000000,0x00000610, +at 0x000001ba : */ 0x18000000,0x00000610, /* MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT -at 0x000001be : */ 0x18000000,0x00000618, +at 0x000001bc : */ 0x18000000,0x00000618, /* MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT -at 0x000001c0 : */ 0x18000000,0x00000620, +at 0x000001be : */ 0x18000000,0x00000620, /* MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT -at 0x000001c2 : */ 0x18000000,0x00000628, +at 0x000001c0 : */ 0x18000000,0x00000628, /* MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT -at 0x000001c4 : */ 0x18000000,0x00000630, +at 0x000001c2 : */ 0x18000000,0x00000630, /* MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT -at 0x000001c6 : */ 0x18000000,0x00000638, +at 0x000001c4 : */ 0x18000000,0x00000638, /* MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT -at 0x000001c8 : */ 0x18000000,0x00000640, +at 0x000001c6 : */ 0x18000000,0x00000640, /* MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT -at 0x000001ca : */ 0x18000000,0x00000648, +at 0x000001c8 : */ 0x18000000,0x00000648, /* MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT -at 0x000001cc : */ 0x18000000,0x00000650, +at 0x000001ca : */ 0x18000000,0x00000650, /* MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT -at 0x000001ce : */ 0x18000000,0x00000658, +at 0x000001cc : */ 0x18000000,0x00000658, /* MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT -at 0x000001d0 : */ 0x18000000,0x00000660, +at 0x000001ce : */ 0x18000000,0x00000660, /* MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT -at 0x000001d2 : */ 0x18000000,0x00000668, +at 0x000001d0 : */ 0x18000000,0x00000668, /* MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT -at 0x000001d4 : */ 0x18000000,0x00000670, +at 0x000001d2 : */ 0x18000000,0x00000670, /* MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT -at 0x000001d6 : */ 0x18000000,0x00000678, +at 0x000001d4 : */ 0x18000000,0x00000678, /* MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT -at 0x000001d8 : */ 0x18000000,0x00000680, +at 0x000001d6 : */ 0x18000000,0x00000680, /* MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT -at 0x000001da : */ 0x18000000,0x00000688, +at 0x000001d8 : */ 0x18000000,0x00000688, /* MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT -at 0x000001dc : */ 0x18000000,0x00000690, +at 0x000001da : */ 0x18000000,0x00000690, /* MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT -at 0x000001de : */ 0x18000000,0x00000698, +at 0x000001dc : */ 0x18000000,0x00000698, /* MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT -at 0x000001e0 : */ 0x18000000,0x000006a0, +at 0x000001de : */ 0x18000000,0x000006a0, /* MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT -at 0x000001e2 : */ 0x18000000,0x000006a8, +at 0x000001e0 : */ 0x18000000,0x000006a8, /* MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT -at 0x000001e4 : */ 0x18000000,0x000006b0, +at 0x000001e2 : */ 0x18000000,0x000006b0, /* MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT -at 0x000001e6 : */ 0x18000000,0x000006b8, +at 0x000001e4 : */ 0x18000000,0x000006b8, /* MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT -at 0x000001e8 : */ 0x18000000,0x000006c0, +at 0x000001e6 : */ 0x18000000,0x000006c0, /* MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT -at 0x000001ea : */ 0x18000000,0x000006c8, +at 0x000001e8 : */ 0x18000000,0x000006c8, /* MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT -at 0x000001ec : */ 0x18000000,0x000006d0, +at 0x000001ea : */ 0x18000000,0x000006d0, /* MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT -at 0x000001ee : */ 0x18000000,0x000006d8, +at 0x000001ec : */ 0x18000000,0x000006d8, /* MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT -at 0x000001f0 : */ 0x18000000,0x000006e0, +at 0x000001ee : */ 0x18000000,0x000006e0, /* MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT -at 0x000001f2 : */ 0x18000000,0x000006e8, +at 0x000001f0 : */ 0x18000000,0x000006e8, /* MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT -at 0x000001f4 : */ 0x18000000,0x000006f0, +at 0x000001f2 : */ 0x18000000,0x000006f0, /* MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT -at 0x000001f6 : */ 0x18000000,0x000006f8, +at 0x000001f4 : */ 0x18000000,0x000006f8, /* MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT -at 0x000001f8 : */ 0x18000000,0x00000700, +at 0x000001f6 : */ 0x18000000,0x00000700, /* MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT -at 0x000001fa : */ 0x18000000,0x00000708, +at 0x000001f8 : */ 0x18000000,0x00000708, /* MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT -at 0x000001fc : */ 0x18000000,0x00000710, +at 0x000001fa : */ 0x18000000,0x00000710, /* MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT -at 0x000001fe : */ 0x18000000,0x00000718, +at 0x000001fc : */ 0x18000000,0x00000718, /* MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT -at 0x00000200 : */ 0x18000000,0x00000720, +at 0x000001fe : */ 0x18000000,0x00000720, /* MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT -at 0x00000202 : */ 0x18000000,0x00000728, +at 0x00000200 : */ 0x18000000,0x00000728, /* MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT -at 0x00000204 : */ 0x18000000,0x00000730, +at 0x00000202 : */ 0x18000000,0x00000730, /* MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT -at 0x00000206 : */ 0x18000000,0x00000738, +at 0x00000204 : */ 0x18000000,0x00000738, /* MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT -at 0x00000208 : */ 0x18000000,0x00000740, +at 0x00000206 : */ 0x18000000,0x00000740, /* MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT -at 0x0000020a : */ 0x18000000,0x00000748, +at 0x00000208 : */ 0x18000000,0x00000748, /* MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT -at 0x0000020c : */ 0x18000000,0x00000750, +at 0x0000020a : */ 0x18000000,0x00000750, /* MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT -at 0x0000020e : */ 0x18000000,0x00000758, +at 0x0000020c : */ 0x18000000,0x00000758, /* MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT -at 0x00000210 : */ 0x18000000,0x00000760, +at 0x0000020e : */ 0x18000000,0x00000760, /* MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT -at 0x00000212 : */ 0x18000000,0x00000768, +at 0x00000210 : */ 0x18000000,0x00000768, /* MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT -at 0x00000214 : */ 0x18000000,0x00000770, +at 0x00000212 : */ 0x18000000,0x00000770, /* MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT -at 0x00000216 : */ 0x18000000,0x00000778, +at 0x00000214 : */ 0x18000000,0x00000778, /* MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT -at 0x00000218 : */ 0x18000000,0x00000780, +at 0x00000216 : */ 0x18000000,0x00000780, /* MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT -at 0x0000021a : */ 0x18000000,0x00000788, +at 0x00000218 : */ 0x18000000,0x00000788, /* MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT -at 0x0000021c : */ 0x18000000,0x00000790, +at 0x0000021a : */ 0x18000000,0x00000790, /* MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT -at 0x0000021e : */ 0x18000000,0x00000798, +at 0x0000021c : */ 0x18000000,0x00000798, /* MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT -at 0x00000220 : */ 0x18000000,0x000007a0, +at 0x0000021e : */ 0x18000000,0x000007a0, /* MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT -at 0x00000222 : */ 0x18000000,0x000007a8, +at 0x00000220 : */ 0x18000000,0x000007a8, /* MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT -at 0x00000224 : */ 0x18000000,0x000007b0, +at 0x00000222 : */ 0x18000000,0x000007b0, /* MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT -at 0x00000226 : */ 0x18000000,0x000007b8, +at 0x00000224 : */ 0x18000000,0x000007b8, /* MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT -at 0x00000228 : */ 0x18000000,0x000007c0, +at 0x00000226 : */ 0x18000000,0x000007c0, /* MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT -at 0x0000022a : */ 0x18000000,0x000007c8, +at 0x00000228 : */ 0x18000000,0x000007c8, /* MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT -at 0x0000022c : */ 0x18000000,0x000007d0, +at 0x0000022a : */ 0x18000000,0x000007d0, /* MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT -at 0x0000022e : */ 0x18000000,0x000007d8, +at 0x0000022c : */ 0x18000000,0x000007d8, /* MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT -at 0x00000230 : */ 0x18000000,0x000007e0, +at 0x0000022e : */ 0x18000000,0x000007e0, /* MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT -at 0x00000232 : */ 0x18000000,0x000007e8, +at 0x00000230 : */ 0x18000000,0x000007e8, /* MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT -at 0x00000234 : */ 0x18000000,0x000007f0, +at 0x00000232 : */ 0x18000000,0x000007f0, /* MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT -at 0x00000236 : */ 0x18000000,0x000007f8, +at 0x00000234 : */ 0x18000000,0x000007f8, /* MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT -at 0x00000238 : */ 0x18000000,0x00000800, +at 0x00000236 : */ 0x18000000,0x00000800, /* MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT -at 0x0000023a : */ 0x18000000,0x00000808, +at 0x00000238 : */ 0x18000000,0x00000808, /* MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT -at 0x0000023c : */ 0x18000000,0x00000810, +at 0x0000023a : */ 0x18000000,0x00000810, /* MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT -at 0x0000023e : */ 0x18000000,0x00000818, +at 0x0000023c : */ 0x18000000,0x00000818, /* MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT -at 0x00000240 : */ 0x18000000,0x00000820, +at 0x0000023e : */ 0x18000000,0x00000820, /* ENTRY end_data_trans end_data_trans: redo_msgin3: JUMP get_status, WHEN STATUS -at 0x00000242 : */ 0x830b0000,0x000000a0, +at 0x00000240 : */ 0x830b0000,0x00000098, /* JUMP get_msgin3, WHEN MSG_IN -at 0x00000244 : */ 0x870b0000,0x00000b20, +at 0x00000242 : */ 0x870b0000,0x00000b78, /* INT int_data_bad_phase -at 0x00000246 : */ 0x98080000,0xab93000b, +at 0x00000244 : */ 0x98080000,0xab93000b, /* get_msgin1: MOVE SCRATCH0 | had_msgin TO SCRATCH0 -at 0x00000248 : */ 0x7a344000,0x00000000, +at 0x00000246 : */ 0x7a344000,0x00000000, /* MOVE 1, msgin_buf, WHEN MSG_IN -at 0x0000024a : */ 0x0f000001,0x00000000, +at 0x00000248 : */ 0x0f000001,0x00000000, /* JUMP ext_msg1, IF 0x01 ; Extended Message -at 0x0000024c : */ 0x800c0001,0x00000968, +at 0x0000024a : */ 0x800c0001,0x00000960, /* JUMP ignore_msg1, IF 0x02 ; Save Data Pointers -at 0x0000024e : */ 0x800c0002,0x00000958, +at 0x0000024c : */ 0x800c0002,0x00000950, /* JUMP ignore_msg1, IF 0x03 ; Save Restore Pointers -at 0x00000250 : */ 0x800c0003,0x00000958, +at 0x0000024e : */ 0x800c0003,0x00000950, /* JUMP disc1, IF 0x04 ; Disconnect -at 0x00000252 : */ 0x800c0004,0x000009c8, +at 0x00000250 : */ 0x800c0004,0x000009f0, /* INT int_bad_msg1 -at 0x00000254 : */ 0x98080000,0xab930006, +at 0x00000252 : */ 0x98080000,0xab930006, /* ignore_msg1: CLEAR ACK -at 0x00000256 : */ 0x60000040,0x00000000, +at 0x00000254 : */ 0x60000040,0x00000000, /* JUMP redo_msgin1 -at 0x00000258 : */ 0x80080000,0x00000058, +at 0x00000256 : */ 0x80080000,0x00000050, /* ext_msg1: MOVE SCRATCH0 | had_extmsg TO SCRATCH0 -at 0x0000025a : */ 0x7a348000,0x00000000, +at 0x00000258 : */ 0x7a348000,0x00000000, /* CLEAR ACK -at 0x0000025c : */ 0x60000040,0x00000000, +at 0x0000025a : */ 0x60000040,0x00000000, /* MOVE 1, msgin_buf + 1, WHEN MSG_IN -at 0x0000025e : */ 0x0f000001,0x00000001, +at 0x0000025c : */ 0x0f000001,0x00000001, /* - JUMP ext_msg1a, IF 0x03 + JUMP reject_msg1, IF NOT 0x03 ; Only handle SDTR -at 0x00000260 : */ 0x800c0003,0x00000990, +at 0x0000025e : */ 0x80040003,0x000009b0, /* - INT int_bad_extmsg1a + CLEAR ACK -at 0x00000262 : */ 0x98080000,0xab930000, +at 0x00000260 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 2, WHEN MSG_IN + +at 0x00000262 : */ 0x0f000001,0x00000002, +/* + JUMP reject_msg1, IF NOT 0x01 ; Only handle SDTR + +at 0x00000264 : */ 0x80040001,0x000009b0, /* -ext_msg1a: CLEAR ACK -at 0x00000264 : */ 0x60000040,0x00000000, +at 0x00000266 : */ 0x60000040,0x00000000, /* - MOVE 1, msgin_buf + 2, WHEN MSG_IN + MOVE 2, msgin_buf + 3, WHEN MSG_IN -at 0x00000266 : */ 0x0f000001,0x00000002, +at 0x00000268 : */ 0x0f000002,0x00000003, /* - JUMP ext_msg1b, IF 0x01 ; Must be SDTR + INT int_msg_sdtr1 + +at 0x0000026a : */ 0x98080000,0xab93000c, +/* +reject_msg1: + MOVE SCRATCH1 | did_reject TO SCRATCH1 -at 0x00000268 : */ 0x800c0001,0x000009b0, +at 0x0000026c : */ 0x7a350100,0x00000000, /* - INT int_bad_extmsg1b + SET ATN -at 0x0000026a : */ 0x98080000,0xab930001, +at 0x0000026e : */ 0x58000008,0x00000000, /* -ext_msg1b: CLEAR ACK -at 0x0000026c : */ 0x60000040,0x00000000, +at 0x00000270 : */ 0x60000040,0x00000000, /* - MOVE 2, msgin_buf + 3, WHEN MSG_IN + JUMP reject_msg1a, WHEN NOT MSG_IN -at 0x0000026e : */ 0x0f000002,0x00000003, +at 0x00000272 : */ 0x87030000,0x000009e0, /* - INT int_msg_sdtr1 + MOVE 1, msgin_buf + 7, WHEN MSG_IN -at 0x00000270 : */ 0x98080000,0xab93000c, +at 0x00000274 : */ 0x0f000001,0x00000007, +/* + JUMP reject_msg1 + +at 0x00000276 : */ 0x80080000,0x000009b0, +/* +reject_msg1a: + MOVE 1, msg_reject, WHEN MSG_OUT + +at 0x00000278 : */ 0x0e000001,0x00000000, +/* + JUMP redo_msgin1 + +at 0x0000027a : */ 0x80080000,0x00000050, /* disc1: CLEAR ACK -at 0x00000272 : */ 0x60000040,0x00000000, +at 0x0000027c : */ 0x60000040,0x00000000, /* ENTRY wait_disc1 wait_disc1: WAIT DISCONNECT -at 0x00000274 : */ 0x48000000,0x00000000, +at 0x0000027e : */ 0x48000000,0x00000000, /* INT int_disc1 -at 0x00000276 : */ 0x98080000,0xab930019, +at 0x00000280 : */ 0x98080000,0xab930019, /* ENTRY resume_msgin1a resume_msgin1a: CLEAR ACK -at 0x00000278 : */ 0x60000040,0x00000000, +at 0x00000282 : */ 0x60000040,0x00000000, /* JUMP redo_msgin1 -at 0x0000027a : */ 0x80080000,0x00000058, +at 0x00000284 : */ 0x80080000,0x00000050, /* ENTRY resume_msgin1b resume_msgin1b: SET ATN -at 0x0000027c : */ 0x58000008,0x00000000, +at 0x00000286 : */ 0x58000008,0x00000000, /* CLEAR ACK -at 0x0000027e : */ 0x60000040,0x00000000, +at 0x00000288 : */ 0x60000040,0x00000000, /* INT int_no_msgout1, WHEN NOT MSG_OUT -at 0x00000280 : */ 0x9e030000,0xab93000f, +at 0x0000028a : */ 0x9e030000,0xab93000f, /* MOVE SCRATCH0 | had_msgout TO SCRATCH0 -at 0x00000282 : */ 0x7a340200,0x00000000, +at 0x0000028c : */ 0x7a340200,0x00000000, /* MOVE FROM dsa_msgout, when MSG_OUT -at 0x00000284 : */ 0x1e000000,0x00000008, +at 0x0000028e : */ 0x1e000000,0x00000008, /* JUMP redo_msgin1 -at 0x00000286 : */ 0x80080000,0x00000058, +at 0x00000290 : */ 0x80080000,0x00000050, /* get_msgin2: MOVE SCRATCH0 | had_msgin TO SCRATCH0 -at 0x00000288 : */ 0x7a344000,0x00000000, +at 0x00000292 : */ 0x7a344000,0x00000000, /* MOVE 1, msgin_buf, WHEN MSG_IN -at 0x0000028a : */ 0x0f000001,0x00000000, +at 0x00000294 : */ 0x0f000001,0x00000000, /* JUMP ext_msg2, IF 0x01 ; Extended Message -at 0x0000028c : */ 0x800c0001,0x00000a68, +at 0x00000296 : */ 0x800c0001,0x00000a90, /* JUMP ignore_msg2, IF 0x02 ; Save Data Pointers -at 0x0000028e : */ 0x800c0002,0x00000a58, +at 0x00000298 : */ 0x800c0002,0x00000a80, /* JUMP ignore_msg2, IF 0x03 ; Save Restore Pointers -at 0x00000290 : */ 0x800c0003,0x00000a58, +at 0x0000029a : */ 0x800c0003,0x00000a80, /* JUMP disc2, IF 0x04 ; Disconnect -at 0x00000292 : */ 0x800c0004,0x00000ac8, +at 0x0000029c : */ 0x800c0004,0x00000b20, /* INT int_bad_msg2 -at 0x00000294 : */ 0x98080000,0xab930007, +at 0x0000029e : */ 0x98080000,0xab930007, /* ignore_msg2: CLEAR ACK -at 0x00000296 : */ 0x60000040,0x00000000, +at 0x000002a0 : */ 0x60000040,0x00000000, /* JUMP redo_msgin2 -at 0x00000298 : */ 0x80080000,0x00000078, +at 0x000002a2 : */ 0x80080000,0x00000070, /* ext_msg2: MOVE SCRATCH0 | had_extmsg TO SCRATCH0 -at 0x0000029a : */ 0x7a348000,0x00000000, +at 0x000002a4 : */ 0x7a348000,0x00000000, /* CLEAR ACK -at 0x0000029c : */ 0x60000040,0x00000000, +at 0x000002a6 : */ 0x60000040,0x00000000, /* MOVE 1, msgin_buf + 1, WHEN MSG_IN -at 0x0000029e : */ 0x0f000001,0x00000001, +at 0x000002a8 : */ 0x0f000001,0x00000001, +/* + JUMP reject_msg2, IF NOT 0x03 ; Only handle SDTR + +at 0x000002aa : */ 0x80040003,0x00000ae0, +/* + CLEAR ACK + +at 0x000002ac : */ 0x60000040,0x00000000, /* - JUMP ext_msg2a, IF 0x03 + MOVE 1, msgin_buf + 2, WHEN MSG_IN -at 0x000002a0 : */ 0x800c0003,0x00000a90, +at 0x000002ae : */ 0x0f000001,0x00000002, /* - INT int_bad_extmsg2a + JUMP reject_msg2, IF NOT 0x01 ; Only handle SDTR -at 0x000002a2 : */ 0x98080000,0xab930002, +at 0x000002b0 : */ 0x80040001,0x00000ae0, /* -ext_msg2a: CLEAR ACK -at 0x000002a4 : */ 0x60000040,0x00000000, +at 0x000002b2 : */ 0x60000040,0x00000000, /* - MOVE 1, msgin_buf + 2, WHEN MSG_IN + MOVE 2, msgin_buf + 3, WHEN MSG_IN + +at 0x000002b4 : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr2 -at 0x000002a6 : */ 0x0f000001,0x00000002, +at 0x000002b6 : */ 0x98080000,0xab93000d, /* - JUMP ext_msg2b, IF 0x01 ; Must be SDTR +reject_msg2: + MOVE SCRATCH1 | did_reject TO SCRATCH1 -at 0x000002a8 : */ 0x800c0001,0x00000ab0, +at 0x000002b8 : */ 0x7a350100,0x00000000, /* - INT int_bad_extmsg2b + SET ATN -at 0x000002aa : */ 0x98080000,0xab930003, +at 0x000002ba : */ 0x58000008,0x00000000, /* -ext_msg2b: CLEAR ACK -at 0x000002ac : */ 0x60000040,0x00000000, +at 0x000002bc : */ 0x60000040,0x00000000, /* - MOVE 2, msgin_buf + 3, WHEN MSG_IN + JUMP reject_msg2a, WHEN NOT MSG_IN -at 0x000002ae : */ 0x0f000002,0x00000003, +at 0x000002be : */ 0x87030000,0x00000b10, /* - INT int_msg_sdtr2 + MOVE 1, msgin_buf + 7, WHEN MSG_IN + +at 0x000002c0 : */ 0x0f000001,0x00000007, +/* + JUMP reject_msg2 + +at 0x000002c2 : */ 0x80080000,0x00000ae0, +/* +reject_msg2a: + MOVE 1, msg_reject, WHEN MSG_OUT + +at 0x000002c4 : */ 0x0e000001,0x00000000, +/* + JUMP redo_msgin2 -at 0x000002b0 : */ 0x98080000,0xab93000d, +at 0x000002c6 : */ 0x80080000,0x00000070, /* disc2: CLEAR ACK -at 0x000002b2 : */ 0x60000040,0x00000000, +at 0x000002c8 : */ 0x60000040,0x00000000, /* ENTRY wait_disc2 wait_disc2: WAIT DISCONNECT -at 0x000002b4 : */ 0x48000000,0x00000000, +at 0x000002ca : */ 0x48000000,0x00000000, /* INT int_disc2 -at 0x000002b6 : */ 0x98080000,0xab93001a, +at 0x000002cc : */ 0x98080000,0xab93001a, /* ENTRY resume_msgin2a resume_msgin2a: CLEAR ACK -at 0x000002b8 : */ 0x60000040,0x00000000, +at 0x000002ce : */ 0x60000040,0x00000000, /* JUMP redo_msgin2 -at 0x000002ba : */ 0x80080000,0x00000078, +at 0x000002d0 : */ 0x80080000,0x00000070, /* ENTRY resume_msgin2b resume_msgin2b: SET ATN -at 0x000002bc : */ 0x58000008,0x00000000, +at 0x000002d2 : */ 0x58000008,0x00000000, /* CLEAR ACK -at 0x000002be : */ 0x60000040,0x00000000, +at 0x000002d4 : */ 0x60000040,0x00000000, /* INT int_no_msgout2, WHEN NOT MSG_OUT -at 0x000002c0 : */ 0x9e030000,0xab930010, +at 0x000002d6 : */ 0x9e030000,0xab930010, /* MOVE SCRATCH0 | had_msgout TO SCRATCH0 -at 0x000002c2 : */ 0x7a340200,0x00000000, +at 0x000002d8 : */ 0x7a340200,0x00000000, /* MOVE FROM dsa_msgout, when MSG_OUT -at 0x000002c4 : */ 0x1e000000,0x00000008, +at 0x000002da : */ 0x1e000000,0x00000008, /* JUMP redo_msgin2 -at 0x000002c6 : */ 0x80080000,0x00000078, +at 0x000002dc : */ 0x80080000,0x00000070, /* get_msgin3: MOVE SCRATCH0 | had_msgin TO SCRATCH0 -at 0x000002c8 : */ 0x7a344000,0x00000000, +at 0x000002de : */ 0x7a344000,0x00000000, /* MOVE 1, msgin_buf, WHEN MSG_IN -at 0x000002ca : */ 0x0f000001,0x00000000, +at 0x000002e0 : */ 0x0f000001,0x00000000, /* JUMP ext_msg3, IF 0x01 ; Extended Message -at 0x000002cc : */ 0x800c0001,0x00000b68, +at 0x000002e2 : */ 0x800c0001,0x00000bc0, /* JUMP ignore_msg3, IF 0x02 ; Save Data Pointers -at 0x000002ce : */ 0x800c0002,0x00000b58, +at 0x000002e4 : */ 0x800c0002,0x00000bb0, /* JUMP ignore_msg3, IF 0x03 ; Save Restore Pointers -at 0x000002d0 : */ 0x800c0003,0x00000b58, +at 0x000002e6 : */ 0x800c0003,0x00000bb0, /* JUMP disc3, IF 0x04 ; Disconnect -at 0x000002d2 : */ 0x800c0004,0x00000bc8, +at 0x000002e8 : */ 0x800c0004,0x00000c50, /* INT int_bad_msg3 -at 0x000002d4 : */ 0x98080000,0xab930008, +at 0x000002ea : */ 0x98080000,0xab930008, /* ignore_msg3: CLEAR ACK -at 0x000002d6 : */ 0x60000040,0x00000000, +at 0x000002ec : */ 0x60000040,0x00000000, /* JUMP redo_msgin3 -at 0x000002d8 : */ 0x80080000,0x00000908, +at 0x000002ee : */ 0x80080000,0x00000900, /* ext_msg3: MOVE SCRATCH0 | had_extmsg TO SCRATCH0 -at 0x000002da : */ 0x7a348000,0x00000000, +at 0x000002f0 : */ 0x7a348000,0x00000000, /* CLEAR ACK -at 0x000002dc : */ 0x60000040,0x00000000, +at 0x000002f2 : */ 0x60000040,0x00000000, /* MOVE 1, msgin_buf + 1, WHEN MSG_IN -at 0x000002de : */ 0x0f000001,0x00000001, +at 0x000002f4 : */ 0x0f000001,0x00000001, /* - JUMP ext_msg3a, IF 0x03 + JUMP reject_msg3, IF NOT 0x03 ; Only handle SDTR -at 0x000002e0 : */ 0x800c0003,0x00000b90, +at 0x000002f6 : */ 0x80040003,0x00000c10, /* - INT int_bad_extmsg3a + CLEAR ACK -at 0x000002e2 : */ 0x98080000,0xab930004, +at 0x000002f8 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 2, WHEN MSG_IN + +at 0x000002fa : */ 0x0f000001,0x00000002, +/* + JUMP reject_msg3, IF NOT 0x01 ; Only handle SDTR + +at 0x000002fc : */ 0x80040001,0x00000c10, /* -ext_msg3a: CLEAR ACK -at 0x000002e4 : */ 0x60000040,0x00000000, +at 0x000002fe : */ 0x60000040,0x00000000, /* - MOVE 1, msgin_buf + 2, WHEN MSG_IN + MOVE 2, msgin_buf + 3, WHEN MSG_IN + +at 0x00000300 : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr3 -at 0x000002e6 : */ 0x0f000001,0x00000002, +at 0x00000302 : */ 0x98080000,0xab93000e, /* - JUMP ext_msg3b, IF 0x01 ; Must be SDTR +reject_msg3: + MOVE SCRATCH1 | did_reject TO SCRATCH1 -at 0x000002e8 : */ 0x800c0001,0x00000bb0, +at 0x00000304 : */ 0x7a350100,0x00000000, /* - INT int_bad_extmsg3b + SET ATN -at 0x000002ea : */ 0x98080000,0xab930005, +at 0x00000306 : */ 0x58000008,0x00000000, /* -ext_msg3b: CLEAR ACK -at 0x000002ec : */ 0x60000040,0x00000000, +at 0x00000308 : */ 0x60000040,0x00000000, /* - MOVE 2, msgin_buf + 3, WHEN MSG_IN + JUMP reject_msg3a, WHEN NOT MSG_IN -at 0x000002ee : */ 0x0f000002,0x00000003, +at 0x0000030a : */ 0x87030000,0x00000c40, /* - INT int_msg_sdtr3 + MOVE 1, msgin_buf + 7, WHEN MSG_IN + +at 0x0000030c : */ 0x0f000001,0x00000007, +/* + JUMP reject_msg3 + +at 0x0000030e : */ 0x80080000,0x00000c10, +/* +reject_msg3a: + MOVE 1, msg_reject, WHEN MSG_OUT -at 0x000002f0 : */ 0x98080000,0xab93000e, +at 0x00000310 : */ 0x0e000001,0x00000000, +/* + JUMP redo_msgin3 + +at 0x00000312 : */ 0x80080000,0x00000900, /* disc3: CLEAR ACK -at 0x000002f2 : */ 0x60000040,0x00000000, +at 0x00000314 : */ 0x60000040,0x00000000, /* ENTRY wait_disc3 wait_disc3: WAIT DISCONNECT -at 0x000002f4 : */ 0x48000000,0x00000000, +at 0x00000316 : */ 0x48000000,0x00000000, /* INT int_disc3 -at 0x000002f6 : */ 0x98080000,0xab93001b, +at 0x00000318 : */ 0x98080000,0xab93001b, /* ENTRY resume_msgin3a resume_msgin3a: CLEAR ACK -at 0x000002f8 : */ 0x60000040,0x00000000, +at 0x0000031a : */ 0x60000040,0x00000000, /* JUMP redo_msgin3 -at 0x000002fa : */ 0x80080000,0x00000908, +at 0x0000031c : */ 0x80080000,0x00000900, /* ENTRY resume_msgin3b resume_msgin3b: SET ATN -at 0x000002fc : */ 0x58000008,0x00000000, +at 0x0000031e : */ 0x58000008,0x00000000, /* CLEAR ACK -at 0x000002fe : */ 0x60000040,0x00000000, +at 0x00000320 : */ 0x60000040,0x00000000, /* INT int_no_msgout3, WHEN NOT MSG_OUT -at 0x00000300 : */ 0x9e030000,0xab930011, +at 0x00000322 : */ 0x9e030000,0xab930011, /* MOVE SCRATCH0 | had_msgout TO SCRATCH0 -at 0x00000302 : */ 0x7a340200,0x00000000, +at 0x00000324 : */ 0x7a340200,0x00000000, /* MOVE FROM dsa_msgout, when MSG_OUT -at 0x00000304 : */ 0x1e000000,0x00000008, +at 0x00000326 : */ 0x1e000000,0x00000008, /* JUMP redo_msgin3 -at 0x00000306 : */ 0x80080000,0x00000908, +at 0x00000328 : */ 0x80080000,0x00000900, /* ENTRY resume_rej_ident resume_rej_ident: CLEAR ATN -at 0x00000308 : */ 0x60000008,0x00000000, +at 0x0000032a : */ 0x60000008,0x00000000, /* MOVE 1, msgin_buf, WHEN MSG_IN -at 0x0000030a : */ 0x0f000001,0x00000000, +at 0x0000032c : */ 0x0f000001,0x00000000, /* INT int_not_rej, IF NOT 0x07 ; Reject -at 0x0000030c : */ 0x98040007,0xab93001c, +at 0x0000032e : */ 0x98040007,0xab93001c, /* CLEAR ACK -at 0x0000030e : */ 0x60000040,0x00000000, +at 0x00000330 : */ 0x60000040,0x00000000, /* JUMP done_ident -at 0x00000310 : */ 0x80080000,0x00000050, +at 0x00000332 : */ 0x80080000,0x00000048, /* ENTRY reselect @@ -1716,73 +1784,92 @@ ; Disable selection timer MOVE CTEST7 | 0x10 TO CTEST7 -at 0x00000312 : */ 0x7a1b1000,0x00000000, +at 0x00000334 : */ 0x7a1b1000,0x00000000, /* WAIT RESELECT resel_err -at 0x00000314 : */ 0x50000000,0x00000c70, +at 0x00000336 : */ 0x50000000,0x00000cf8, /* INT int_resel_not_msgin, WHEN NOT MSG_IN -at 0x00000316 : */ 0x9f030000,0xab930016, +at 0x00000338 : */ 0x9f030000,0xab930016, /* MOVE 1, reselected_identify, WHEN MSG_IN -at 0x00000318 : */ 0x0f000001,0x00000000, +at 0x0000033a : */ 0x0f000001,0x00000000, /* INT int_reselected -at 0x0000031a : */ 0x98080000,0xab930017, +at 0x0000033c : */ 0x98080000,0xab930017, /* resel_err: MOVE CTEST2 & 0x40 TO SFBR -at 0x0000031c : */ 0x74164000,0x00000000, +at 0x0000033e : */ 0x74164000,0x00000000, /* JUMP selected, IF 0x00 -at 0x0000031e : */ 0x800c0000,0x00000cb0, +at 0x00000340 : */ 0x800c0000,0x00000d38, /* MOVE SFBR & 0 TO SFBR -at 0x00000320 : */ 0x7c080000,0x00000000, +at 0x00000342 : */ 0x7c080000,0x00000000, /* ENTRY patch_new_dsa patch_new_dsa: MOVE SFBR | 0x11 TO DSA0 -at 0x00000322 : */ 0x6a101100,0x00000000, +at 0x00000344 : */ 0x6a101100,0x00000000, /* MOVE SFBR | 0x22 TO DSA1 -at 0x00000324 : */ 0x6a112200,0x00000000, +at 0x00000346 : */ 0x6a112200,0x00000000, /* MOVE SFBR | 0x33 TO DSA2 -at 0x00000326 : */ 0x6a123300,0x00000000, +at 0x00000348 : */ 0x6a123300,0x00000000, /* MOVE SFBR | 0x44 TO DSA3 -at 0x00000328 : */ 0x6a134400,0x00000000, +at 0x0000034a : */ 0x6a134400,0x00000000, /* JUMP do_select -at 0x0000032a : */ 0x80080000,0x00000000, +at 0x0000034c : */ 0x80080000,0x00000000, /* selected: INT int_selected -at 0x0000032c : */ 0x98080000,0xab930018, +at 0x0000034e : */ 0x98080000,0xab930018, +/* + +ENTRY test1 +test1: + MOVE MEMORY 4, test1_src, test1_dst + +at 0x00000350 : */ 0xc0000004,0x00000000,0x00000000, +/* + INT int_test1 + +at 0x00000353 : */ 0x98080000,0xab93001d, +}; + +#define A_did_reject 0x00000001 +static u32 A_did_reject_used[] __attribute((unused)) = { + 0x0000026c, + 0x000002b8, + 0x00000304, }; #define A_dsa_cmnd 0x00000010 static u32 A_dsa_cmnd_used[] __attribute((unused)) = { - 0x0000001d, + 0x0000001b, }; #define A_dsa_datain 0x00000028 static u32 A_dsa_datain_used[] __attribute((unused)) = { + 0x0000003b, 0x0000003d, 0x0000003f, 0x00000041, @@ -1910,11 +1997,11 @@ 0x00000135, 0x00000137, 0x00000139, - 0x0000013b, }; #define A_dsa_dataout 0x00000428 static u32 A_dsa_dataout_used[] __attribute((unused)) = { + 0x00000141, 0x00000143, 0x00000145, 0x00000147, @@ -2042,25 +2129,24 @@ 0x0000023b, 0x0000023d, 0x0000023f, - 0x00000241, }; #define A_dsa_msgin 0x00000020 static u32 A_dsa_msgin_used[] __attribute((unused)) = { - 0x0000002f, + 0x0000002d, }; #define A_dsa_msgout 0x00000008 static u32 A_dsa_msgout_used[] __attribute((unused)) = { - 0x00000013, - 0x00000285, - 0x000002c5, - 0x00000305, + 0x00000011, + 0x0000028f, + 0x000002db, + 0x00000327, }; #define A_dsa_select 0x00000000 static u32 A_dsa_select_used[] __attribute((unused)) = { - 0x00000006, + 0x00000004, }; #define A_dsa_size 0x00000828 @@ -2069,285 +2155,290 @@ #define A_dsa_status 0x00000018 static u32 A_dsa_status_used[] __attribute((unused)) = { - 0x0000002b, + 0x00000029, }; #define A_had_cmdout 0x00000004 static u32 A_had_cmdout_used[] __attribute((unused)) = { - 0x0000001a, + 0x00000018, }; #define A_had_datain 0x00000008 static u32 A_had_datain_used[] __attribute((unused)) = { - 0x00000038, + 0x00000036, }; #define A_had_dataout 0x00000010 static u32 A_had_dataout_used[] __attribute((unused)) = { - 0x0000013e, + 0x0000013c, }; #define A_had_extmsg 0x00000080 static u32 A_had_extmsg_used[] __attribute((unused)) = { - 0x0000025a, - 0x0000029a, - 0x000002da, + 0x00000258, + 0x000002a4, + 0x000002f0, }; #define A_had_msgin 0x00000040 static u32 A_had_msgin_used[] __attribute((unused)) = { - 0x00000248, - 0x00000288, - 0x000002c8, + 0x00000246, + 0x00000292, + 0x000002de, }; #define A_had_msgout 0x00000002 static u32 A_had_msgout_used[] __attribute((unused)) = { - 0x00000010, - 0x00000282, - 0x000002c2, - 0x00000302, + 0x0000000e, + 0x0000028c, + 0x000002d8, + 0x00000324, }; #define A_had_select 0x00000001 static u32 A_had_select_used[] __attribute((unused)) = { - 0x0000000c, + 0x0000000a, }; #define A_had_status 0x00000020 static u32 A_had_status_used[] __attribute((unused)) = { }; -#define A_int_bad_extmsg1a 0xab930000 -static u32 A_int_bad_extmsg1a_used[] __attribute((unused)) = { - 0x00000263, -}; - -#define A_int_bad_extmsg1b 0xab930001 -static u32 A_int_bad_extmsg1b_used[] __attribute((unused)) = { - 0x0000026b, -}; - -#define A_int_bad_extmsg2a 0xab930002 -static u32 A_int_bad_extmsg2a_used[] __attribute((unused)) = { - 0x000002a3, -}; - -#define A_int_bad_extmsg2b 0xab930003 -static u32 A_int_bad_extmsg2b_used[] __attribute((unused)) = { - 0x000002ab, -}; - -#define A_int_bad_extmsg3a 0xab930004 -static u32 A_int_bad_extmsg3a_used[] __attribute((unused)) = { - 0x000002e3, -}; - -#define A_int_bad_extmsg3b 0xab930005 -static u32 A_int_bad_extmsg3b_used[] __attribute((unused)) = { - 0x000002eb, -}; - #define A_int_bad_msg1 0xab930006 static u32 A_int_bad_msg1_used[] __attribute((unused)) = { - 0x00000255, + 0x00000253, }; #define A_int_bad_msg2 0xab930007 static u32 A_int_bad_msg2_used[] __attribute((unused)) = { - 0x00000295, + 0x0000029f, }; #define A_int_bad_msg3 0xab930008 static u32 A_int_bad_msg3_used[] __attribute((unused)) = { - 0x000002d5, + 0x000002eb, }; #define A_int_cmd_bad_phase 0xab930009 static u32 A_int_cmd_bad_phase_used[] __attribute((unused)) = { - 0x00000027, + 0x00000025, }; #define A_int_cmd_complete 0xab93000a static u32 A_int_cmd_complete_used[] __attribute((unused)) = { - 0x00000037, + 0x00000035, }; #define A_int_data_bad_phase 0xab93000b static u32 A_int_data_bad_phase_used[] __attribute((unused)) = { - 0x00000247, + 0x00000245, }; #define A_int_disc1 0xab930019 static u32 A_int_disc1_used[] __attribute((unused)) = { - 0x00000277, + 0x00000281, }; #define A_int_disc2 0xab93001a static u32 A_int_disc2_used[] __attribute((unused)) = { - 0x000002b7, + 0x000002cd, }; #define A_int_disc3 0xab93001b static u32 A_int_disc3_used[] __attribute((unused)) = { - 0x000002f7, + 0x00000319, }; #define A_int_msg_sdtr1 0xab93000c static u32 A_int_msg_sdtr1_used[] __attribute((unused)) = { - 0x00000271, + 0x0000026b, }; #define A_int_msg_sdtr2 0xab93000d static u32 A_int_msg_sdtr2_used[] __attribute((unused)) = { - 0x000002b1, + 0x000002b7, }; #define A_int_msg_sdtr3 0xab93000e static u32 A_int_msg_sdtr3_used[] __attribute((unused)) = { - 0x000002f1, + 0x00000303, }; #define A_int_no_msgout1 0xab93000f static u32 A_int_no_msgout1_used[] __attribute((unused)) = { - 0x00000281, + 0x0000028b, }; #define A_int_no_msgout2 0xab930010 static u32 A_int_no_msgout2_used[] __attribute((unused)) = { - 0x000002c1, + 0x000002d7, }; #define A_int_no_msgout3 0xab930011 static u32 A_int_no_msgout3_used[] __attribute((unused)) = { - 0x00000301, + 0x00000323, }; #define A_int_not_cmd_complete 0xab930012 static u32 A_int_not_cmd_complete_used[] __attribute((unused)) = { - 0x00000031, + 0x0000002f, }; #define A_int_not_rej 0xab93001c static u32 A_int_not_rej_used[] __attribute((unused)) = { - 0x0000030d, + 0x0000032f, }; #define A_int_resel_not_msgin 0xab930016 static u32 A_int_resel_not_msgin_used[] __attribute((unused)) = { - 0x00000317, + 0x00000339, }; #define A_int_reselected 0xab930017 static u32 A_int_reselected_used[] __attribute((unused)) = { - 0x0000031b, + 0x0000033d, }; #define A_int_sel_no_ident 0xab930013 static u32 A_int_sel_no_ident_used[] __attribute((unused)) = { - 0x0000000f, + 0x0000000d, }; #define A_int_sel_not_cmd 0xab930014 static u32 A_int_sel_not_cmd_used[] __attribute((unused)) = { - 0x00000019, + 0x00000017, }; #define A_int_selected 0xab930018 static u32 A_int_selected_used[] __attribute((unused)) = { - 0x0000032d, + 0x0000034f, }; #define A_int_status_not_msgin 0xab930015 static u32 A_int_status_not_msgin_used[] __attribute((unused)) = { - 0x0000002d, + 0x0000002b, +}; + +#define A_int_test1 0xab93001d +static u32 A_int_test1_used[] __attribute((unused)) = { + 0x00000354, +}; + +#define A_msg_reject 0x00000000 +static u32 A_msg_reject_used[] __attribute((unused)) = { + 0x00000279, + 0x000002c5, + 0x00000311, }; #define A_msgin_buf 0x00000000 static u32 A_msgin_buf_used[] __attribute((unused)) = { - 0x0000024b, - 0x0000025f, - 0x00000267, - 0x0000026f, - 0x0000028b, - 0x0000029f, - 0x000002a7, + 0x00000249, + 0x0000025d, + 0x00000263, + 0x00000269, + 0x00000275, + 0x00000295, + 0x000002a9, 0x000002af, - 0x000002cb, - 0x000002df, - 0x000002e7, - 0x000002ef, - 0x0000030b, + 0x000002b5, + 0x000002c1, + 0x000002e1, + 0x000002f5, + 0x000002fb, + 0x00000301, + 0x0000030d, + 0x0000032d, }; #define A_reselected_identify 0x00000000 static u32 A_reselected_identify_used[] __attribute((unused)) = { - 0x00000319, + 0x0000033b, +}; + +#define A_test1_dst 0x00000000 +static u32 A_test1_dst_used[] __attribute((unused)) = { + 0x00000352, +}; + +#define A_test1_src 0x00000000 +static u32 A_test1_src_used[] __attribute((unused)) = { + 0x00000351, }; #define Ent_do_select 0x00000000 -#define Ent_done_ident 0x00000050 -#define Ent_end_data_trans 0x00000908 -#define Ent_patch_input_data 0x000000e8 -#define Ent_patch_new_dsa 0x00000c88 -#define Ent_patch_output_data 0x00000500 -#define Ent_reselect 0x00000c48 -#define Ent_resume_cmd 0x00000068 -#define Ent_resume_msgin1a 0x000009e0 -#define Ent_resume_msgin1b 0x000009f0 -#define Ent_resume_msgin2a 0x00000ae0 -#define Ent_resume_msgin2b 0x00000af0 -#define Ent_resume_msgin3a 0x00000be0 -#define Ent_resume_msgin3b 0x00000bf0 -#define Ent_resume_pmm 0x00000078 -#define Ent_resume_rej_ident 0x00000c20 -#define Ent_wait_disc1 0x000009d0 -#define Ent_wait_disc2 0x00000ad0 -#define Ent_wait_disc3 0x00000bd0 -#define Ent_wait_disc_complete 0x000000d0 +#define Ent_done_ident 0x00000048 +#define Ent_end_data_trans 0x00000900 +#define Ent_patch_input_data 0x000000e0 +#define Ent_patch_new_dsa 0x00000d10 +#define Ent_patch_output_data 0x000004f8 +#define Ent_reselect 0x00000cd0 +#define Ent_resume_cmd 0x00000060 +#define Ent_resume_msgin1a 0x00000a08 +#define Ent_resume_msgin1b 0x00000a18 +#define Ent_resume_msgin2a 0x00000b38 +#define Ent_resume_msgin2b 0x00000b48 +#define Ent_resume_msgin3a 0x00000c68 +#define Ent_resume_msgin3b 0x00000c78 +#define Ent_resume_pmm 0x00000070 +#define Ent_resume_rej_ident 0x00000ca8 +#define Ent_test1 0x00000d40 +#define Ent_wait_disc1 0x000009f8 +#define Ent_wait_disc2 0x00000b28 +#define Ent_wait_disc3 0x00000c58 +#define Ent_wait_disc_complete 0x000000c8 static u32 LABELPATCHES[] __attribute((unused)) = { + 0x00000005, 0x00000007, - 0x00000009, + 0x00000013, 0x00000015, - 0x00000017, + 0x0000001d, 0x0000001f, 0x00000021, 0x00000023, - 0x00000025, - 0x0000013d, + 0x0000013b, + 0x00000241, 0x00000243, - 0x00000245, + 0x0000024b, 0x0000024d, 0x0000024f, 0x00000251, - 0x00000253, - 0x00000259, - 0x00000261, - 0x00000269, + 0x00000257, + 0x0000025f, + 0x00000265, + 0x00000273, + 0x00000277, 0x0000027b, - 0x00000287, - 0x0000028d, - 0x0000028f, + 0x00000285, 0x00000291, - 0x00000293, + 0x00000297, 0x00000299, - 0x000002a1, - 0x000002a9, - 0x000002bb, + 0x0000029b, + 0x0000029d, + 0x000002a3, + 0x000002ab, + 0x000002b1, + 0x000002bf, + 0x000002c3, 0x000002c7, - 0x000002cd, - 0x000002cf, 0x000002d1, - 0x000002d3, - 0x000002d9, - 0x000002e1, + 0x000002dd, + 0x000002e3, + 0x000002e5, + 0x000002e7, 0x000002e9, - 0x000002fb, - 0x00000307, - 0x00000311, - 0x00000315, - 0x0000031f, - 0x0000032b, + 0x000002ef, + 0x000002f7, + 0x000002fd, + 0x0000030b, + 0x0000030f, + 0x00000313, + 0x0000031d, + 0x00000329, + 0x00000333, + 0x00000337, + 0x00000341, + 0x0000034d, }; static struct { @@ -2356,6 +2447,6 @@ } EXTERNAL_PATCHES[] __attribute((unused)) = { }; -static u32 INSTRUCTIONS __attribute((unused)) = 407; -static u32 PATCHES __attribute((unused)) = 42; +static u32 INSTRUCTIONS __attribute((unused)) = 426; +static u32 PATCHES __attribute((unused)) = 51; static u32 EXTERNAL_PATCHES_LEN __attribute((unused)) = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/sgi/char/sgiserial.h linux.20pre2-ac1/drivers/sgi/char/sgiserial.h --- linux.20pre2/drivers/sgi/char/sgiserial.h 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/sgi/char/sgiserial.h 2002-08-06 15:42:11.000000000 +0100 @@ -406,7 +406,7 @@ /* Read Register 15 (value of WR 15) */ /* Misc inlines */ -extern inline void ZS_CLEARERR(struct sgi_zschannel *channel) +static inline void ZS_CLEARERR(struct sgi_zschannel *channel) { volatile unsigned char junk; @@ -416,7 +416,7 @@ junk = ioc_icontrol->istat0; } -extern inline void ZS_CLEARFIFO(struct sgi_zschannel *channel) +static inline void ZS_CLEARFIFO(struct sgi_zschannel *channel) { volatile unsigned char junk; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/sound/ac97_codec.c linux.20pre2-ac1/drivers/sound/ac97_codec.c --- linux.20pre2/drivers/sound/ac97_codec.c 2002-08-13 13:58:28.000000000 +0100 +++ linux.20pre2-ac1/drivers/sound/ac97_codec.c 2002-08-12 10:32:43.000000000 +0100 @@ -698,7 +698,8 @@ if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", - codec->id ? "Secondary" : "Primary"); + (codec->id & 0x2) ? (codec->id&1 ? "4th" : "Tertiary") + : (codec->id&1 ? "Secondary": "Primary")); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/sound/ali5455.c linux.20pre2-ac1/drivers/sound/ali5455.c --- linux.20pre2/drivers/sound/ali5455.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/sound/ali5455.c 2002-08-06 15:42:10.000000000 +0100 @@ -0,0 +1,3731 @@ +/* + * ALI ali5455 and friends ICH driver for Linux + * LEI HU + * + * Built from: + * drivers/sound/i810_audio + * + * The ALi 5455 is similar but not quite identical to the Intel ICH + * series of controllers. Its easier to keep the driver seperated from + * the i810 driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * ALi 5455 theory of operation + * + * The chipset provides three DMA channels that talk to an AC97 + * CODEC (AC97 is a digital/analog mixer standard). At its simplest + * you get 48Khz audio with basic volume and mixer controls. At the + * best you get rate adaption in the codec. We set the card up so + * that we never take completion interrupts but instead keep the card + * chasing its tail around a ring buffer. This is needed for mmap + * mode audio and happens to work rather well for non-mmap modes too. + * + * The board has one output channel for PCM audio (supported) and + * a stereo line in and mono microphone input. Again these are normally + * locked to 48Khz only. Right now recording is not finished. + * + * There is no midi support, no synth support. Use timidity. To get + * esd working you need to use esd -r 48000 as it won't probe 48KHz + * by default. mpg123 can't handle 48Khz only audio so use xmms. + * + * If you need to force a specific rate set the clocking= option + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PCI_DEVICE_ID_ALI_5455 +#define PCI_DEVICE_ID_ALI_5455 0x5455 +#endif + +#ifndef PCI_VENDOR_ID_ALI +#define PCI_VENDOR_ID_ALI 0x10b9 +#endif + +static int strict_clocking = 0; +static unsigned int clocking = 0; +static unsigned int codec_pcmout_share_spdif_locked = 0; +static unsigned int codec_independent_spdif_locked = 0; +static unsigned int controller_pcmout_share_spdif_locked = 0; +static unsigned int controller_independent_spdif_locked = 0; +static unsigned int globel = 0; + +#define ADC_RUNNING 1 +#define DAC_RUNNING 2 +#define CODEC_SPDIFOUT_RUNNING 8 +#define CONTROLLER_SPDIFOUT_RUNNING 4 + +#define SPDIF_ENABLE_OUTPUT 4 /* bits 0,1 are PCM */ + +#define ALI5455_FMT_16BIT 1 +#define ALI5455_FMT_STEREO 2 +#define ALI5455_FMT_MASK 3 + +#define SPDIF_ON 0x0004 +#define SURR_ON 0x0010 +#define CENTER_LFE_ON 0x0020 +#define VOL_MUTED 0x8000 + + +#define ALI_SPDIF_OUT_CH_STATUS 0xbf +/* the 810's array of pointers to data buffers */ + +struct sg_item { +#define BUSADDR_MASK 0xFFFFFFFE + u32 busaddr; +#define CON_IOC 0x80000000 /* interrupt on completion */ +#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */ +#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */ + u32 control; +}; + +/* an instance of the ali channel */ +#define SG_LEN 32 +struct ali_channel { + /* these sg guys should probably be allocated + seperately as nocache. Must be 8 byte aligned */ + struct sg_item sg[SG_LEN]; /* 32*8 */ + u32 offset; /* 4 */ + u32 port; /* 4 */ + u32 used; + u32 num; +}; + +/* + * we have 3 seperate dma engines. pcm in, pcm out, and mic. + * each dma engine has controlling registers. These goofy + * names are from the datasheet, but make it easy to write + * code while leafing through it. + */ + +#define ENUM_ENGINE(PRE,DIG) \ +enum { \ + PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \ + PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \ + PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \ + PRE##_SR = 0x##DIG##6, /* Status Register */ \ + PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \ + PRE##_CR = 0x##DIG##b /* Control Register */ \ +} + +ENUM_ENGINE(OFF, 0); /* Offsets */ +ENUM_ENGINE(PI, 4); /* PCM In */ +ENUM_ENGINE(PO, 5); /* PCM Out */ +ENUM_ENGINE(MC, 6); /* Mic In */ +ENUM_ENGINE(CODECSPDIFOUT, 7); /* CODEC SPDIF OUT */ +ENUM_ENGINE(CONTROLLERSPDIFIN, A); /* CONTROLLER SPDIF In */ +ENUM_ENGINE(CONTROLLERSPDIFOUT, B); /* CONTROLLER SPDIF OUT */ + + +enum { + ALI_SCR = 0x00, /* System Control Register */ + ALI_SSR = 0x04, /* System Status Register */ + ALI_DMACR = 0x08, /* DMA Control Register */ + ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */ + ALI_INTERFACECR = 0x10, /* Interface Control Register */ + ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */ + ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */ + ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */ + ALI_CPR = 0x20, /* Command Port Register */ + ALI_SPR = 0x24, /* Status Port Register */ + ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */ + ALI_TTSR = 0x30, /* Transmit Tag Slot Register */ + ALI_RTSR = 0x34, /* Receive Tag Slot Register */ + ALI_CSPSR = 0x38, /* Command/Status Port Status Register */ + ALI_CAS = 0x3c, /* Codec Write Semaphore Register */ + ALI_SPDIFCSR = 0xf8, /* spdif channel status register */ + ALI_SPDIFICS = 0xfc /* spdif interface control/status */ +}; + +// x-status register(x:pcm in ,pcm out, mic in,) +/* interrupts for a dma engine */ +#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */ +#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */ +#define DMA_INT_LVI (1<<2) /* last valid done */ +#define DMA_INT_CELV (1<<1) /* last valid is current */ +#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */ //not eqult intel +#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI) + +/* interrupts for the whole chip */// by interrupt status register finish + +#define INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */ +#define INT_SPDIFIN (1<<22) +#define INT_CODECSPDIFOUT (1<<19) +#define INT_MICIN (1<<18) +#define INT_PCMOUT (1<<17) +#define INT_PCMIN (1<<16) +#define INT_CPRAIS (1<<7) +#define INT_SPRAIS (1<<5) +#define INT_GPIO (1<<1) +#define INT_MASK (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN) + +#define DRIVER_VERSION "0.02ac" + +/* magic numbers to protect our data structures */ +#define ALI5455_CARD_MAGIC 0x5072696E /* "Prin" */ +#define ALI5455_STATE_MAGIC 0x63657373 /* "cess" */ +#define ALI5455_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */ +#define NR_HW_CH 5 //I think 5 channel + +/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ +#define NR_AC97 2 + +/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */ +/* stream at a minimum for this card to be happy */ +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */ +/* values are one less than might be expected */ +static const unsigned sample_shift[] = { -1, 0, 0, 1 }; + +#define ALI5455 +static char *card_names[] = { + "ALI 5455" +}; + +static struct pci_device_id ali_pci_tbl[] __initdata = { + {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, ali_pci_tbl); + +#ifdef CONFIG_PM +#define PM_SUSPENDED(card) (card->pm_suspended) +#else +#define PM_SUSPENDED(card) (0) +#endif + +/* "software" or virtual channel, an instance of opened /dev/dsp */ +struct ali_state { + unsigned int magic; + struct ali_card *card; /* Card info */ + + /* single open lock mechanism, only used for recording */ + struct semaphore open_sem; + wait_queue_head_t open_wait; + + /* file mode */ + mode_t open_mode; + + /* virtual channel number */ + int virt; + +#ifdef CONFIG_PM + unsigned int pm_saved_dac_rate, pm_saved_adc_rate; +#endif + struct dmabuf { + /* wave sample stuff */ + unsigned int rate; + unsigned char fmt, enable, trigger; + + /* hardware channel */ + struct ali_channel *read_channel; + struct ali_channel *write_channel; + struct ali_channel *codec_spdifout_channel; + struct ali_channel *controller_spdifout_channel; + + /* OSS buffer management stuff */ + void *rawbuf; + dma_addr_t dma_handle; + unsigned buforder; + unsigned numfrag; + unsigned fragshift; + + /* our buffer acts like a circular ring */ + unsigned hwptr; /* where dma last started, updated by update_ptr */ + unsigned swptr; /* where driver last clear/filled, updated by read/write */ + int count; /* bytes to be consumed or been generated by dma machine */ + unsigned total_bytes; /* total bytes dmaed by hardware */ + + unsigned error; /* number of over/underruns */ + wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ + + /* redundant, but makes calculations easier */ + /* what the hardware uses */ + unsigned dmasize; + unsigned fragsize; + unsigned fragsamples; + + /* what we tell the user to expect */ + unsigned userfrags; + unsigned userfragsize; + + /* OSS stuff */ + unsigned mapped:1; + unsigned ready:1; + unsigned update_flag; + unsigned ossfragsize; + unsigned ossmaxfrags; + unsigned subdivision; + } dmabuf; +}; + + +struct ali_card { + struct ali_channel channel[5]; + unsigned int magic; + + /* We keep ali5455 cards in a linked list */ + struct ali_card *next; + + /* The ali has a certain amount of cross channel interaction + so we use a single per card lock */ + spinlock_t lock; + + /* PCI device stuff */ + struct pci_dev *pci_dev; + u16 pci_id; +#ifdef CONFIG_PM + u16 pm_suspended; + u32 pm_save_state[64 / sizeof(u32)]; + int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97]; +#endif + /* soundcore stuff */ + int dev_audio; + + /* structures for abstraction of hardware facilities, codecs, banks and channels */ + struct ac97_codec *ac97_codec[NR_AC97]; + struct ali_state *states[NR_HW_CH]; + + u16 ac97_features; + u16 ac97_status; + u16 channels; + + /* hardware resources */ + unsigned long iobase; + + u32 irq; + + /* Function support */ + struct ali_channel *(*alloc_pcm_channel) (struct ali_card *); + struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *); + struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *); + struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *); + struct ali_channel *(*alloc_controller_spdifout_channel) (struct ali_card *); + void (*free_pcm_channel) (struct ali_card *, int chan); + + /* We have a *very* long init time possibly, so use this to block */ + /* attempts to open our devices before we are ready (stops oops'es) */ + int initializing; +}; + + +static struct ali_card *devs = NULL; + +static int ali_open_mixdev(struct inode *inode, struct file *file); +static int ali_ioctl_mixdev(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg); +static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data); + +static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card) +{ + if (card->channel[1].used == 1) + return NULL; + card->channel[1].used = 1; + return &card->channel[1]; +} + +static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card) +{ + if (card->channel[0].used == 1) + return NULL; + card->channel[0].used = 1; + return &card->channel[0]; +} + +static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card) +{ + if (card->channel[2].used == 1) + return NULL; + card->channel[2].used = 1; + return &card->channel[2]; +} + +static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card) +{ + if (card->channel[3].used == 1) + return NULL; + card->channel[3].used = 1; + return &card->channel[3]; +} + +static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card) +{ + if (card->channel[4].used == 1) + return NULL; + card->channel[4].used = 1; + return &card->channel[4]; +} +static void ali_free_pcm_channel(struct ali_card *card, int channel) +{ + card->channel[channel].used = 0; +} + + +//add support codec spdif out +static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate) +{ + unsigned long id = 0L; + + id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16); + id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff; + switch (id) { + case 0x41445361: /* AD1886 */ + if (rate == 48000) { + return 1; + } + break; + case 0x414c4720: /* ALC650 */ + if (rate == 48000) { + return 1; + } + break; + default: /* all other codecs, until we know otherwiae */ + if (rate == 48000 || rate == 44100 || rate == 32000) { + return 1; + } + break; + } + return (0); +} + +/* ali_set_spdif_output + * + * Configure the S/PDIF output transmitter. When we turn on + * S/PDIF, we turn off the analog output. This may not be + * the right thing to do. + * + * Assumptions: + * The DSP sample rate must already be set to a supported + * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort. + */ +static void ali_set_spdif_output(struct ali_state *state, int slots, + int rate) +{ + int vol; + int aud_reg; + struct ac97_codec *codec = state->card->ac97_codec[0]; + + if (!(state->card->ac97_features & 4)) { + state->card->ac97_status &= ~SPDIF_ON; + } else { + if (slots == -1) { /* Turn off S/PDIF */ + aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); + ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); + + /* If the volume wasn't muted before we turned on S/PDIF, unmute it */ + if (!(state->card->ac97_status & VOL_MUTED)) { + aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO); + ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, + (aud_reg & ~VOL_MUTED)); + } + state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON); + return; + } + + vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO); + state->card->ac97_status = vol & VOL_MUTED; + + /* Set S/PDIF transmitter sample rate */ + aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL); + switch (rate) { + case 32000: + aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K; + break; + case 44100: + aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K; + break; + case 48000: + aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K; + break; + default: + /* turn off S/PDIF */ + aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); + ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); + state->card->ac97_status &= ~SPDIF_ON; + return; + } + + ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg); + + aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); + aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF; + ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg); + + aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL); + aud_reg |= 0x0002; + ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg); + udelay(1); + + state->card->ac97_status |= SPDIF_ON; + + /* Check to make sure the configuration is valid */ + aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); + if (!(aud_reg & 0x0400)) { + /* turn off S/PDIF */ + ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); + state->card->ac97_status &= ~SPDIF_ON; + return; + } + if (codec_independent_spdif_locked > 0) { + aud_reg = ali_ac97_get(codec, 0x6a); + ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff)); + } + /* Mute the analog output */ + /* Should this only mute the PCM volume??? */ + } +} + +/* ali_set_dac_channels + * + * Configure the codec's multi-channel DACs + * + * The logic is backwards. Setting the bit to 1 turns off the DAC. + * + * What about the ICH? We currently configure it using the + * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC, + * does that imply that we want the ICH set to support + * these channels? + * + * TODO: + * vailidate that the codec really supports these DACs + * before turning them on. + */ +static void ali_set_dac_channels(struct ali_state *state, int channel) +{ + int aud_reg; + struct ac97_codec *codec = state->card->ac97_codec[0]; + + aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); + aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK; + state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON); + + switch (channel) { + case 2: /* always enabled */ + break; + case 4: + aud_reg &= ~AC97_EA_PRJ; + state->card->ac97_status |= SURR_ON; + break; + case 6: + aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK); + state->card->ac97_status |= SURR_ON | CENTER_LFE_ON; + break; + default: + break; + } + ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg); + +} + +/* set playback sample rate */ +static unsigned int ali_set_dac_rate(struct ali_state *state, + unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + u32 new_rate; + struct ac97_codec *codec = state->card->ac97_codec[0]; + + if (!(state->card->ac97_features & 0x0001)) { + dmabuf->rate = clocking; + return clocking; + } + + if (rate > 48000) + rate = 48000; + if (rate < 8000) + rate = 8000; + dmabuf->rate = rate; + + /* + * Adjust for misclocked crap + */ + + rate = (rate * clocking) / 48000; + + if (strict_clocking && rate < 8000) { + rate = 8000; + dmabuf->rate = (rate * 48000) / clocking; + } + + new_rate = ac97_set_dac_rate(codec, rate); + if (new_rate != rate) { + dmabuf->rate = (new_rate * 48000) / clocking; + } + rate = new_rate; + return dmabuf->rate; +} + +/* set recording sample rate */ +static unsigned int ali_set_adc_rate(struct ali_state *state, + unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + u32 new_rate; + struct ac97_codec *codec = state->card->ac97_codec[0]; + + if (!(state->card->ac97_features & 0x0001)) { + dmabuf->rate = clocking; + return clocking; + } + + if (rate > 48000) + rate = 48000; + if (rate < 8000) + rate = 8000; + dmabuf->rate = rate; + + /* + * Adjust for misclocked crap + */ + + rate = (rate * clocking) / 48000; + if (strict_clocking && rate < 8000) { + rate = 8000; + dmabuf->rate = (rate * 48000) / clocking; + } + + new_rate = ac97_set_adc_rate(codec, rate); + + if (new_rate != rate) { + dmabuf->rate = (new_rate * 48000) / clocking; + rate = new_rate; + } + return dmabuf->rate; +} + +/* set codec independent spdifout sample rate */ +static unsigned int ali_set_codecspdifout_rate(struct ali_state *state, + unsigned int rate) +{ + struct dmabuf *dmabuf = &state->dmabuf; + + if (!(state->card->ac97_features & 0x0001)) { + dmabuf->rate = clocking; + return clocking; + } + + if (rate > 48000) + rate = 48000; + if (rate < 8000) + rate = 8000; + dmabuf->rate = rate; + + return dmabuf->rate; +} + +/* set controller independent spdif out function sample rate */ +static void ali_set_spdifout_rate(struct ali_state *state, + unsigned int rate) +{ + unsigned char ch_st_sel; + unsigned short status_rate; + + switch (rate) { + case 44100: + status_rate = 0; + break; + case 32000: + status_rate = 0x300; + break; + case 48000: + default: + status_rate = 0x200; + break; + } + + ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out + + ch_st_sel |= 0x80; //select right + outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS)); + outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2)); + + ch_st_sel &= (~0x80); //select left + outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS)); + outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2)); +} + +/* get current playback/recording dma buffer pointer (byte offset from LBA), + called with spinlock held! */ + +static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned int civ, offset, port, port_picb; + unsigned int data; + + if (!dmabuf->enable) + return 0; + + if (rec == 1) + port = state->card->iobase + dmabuf->read_channel->port; + else if (rec == 2) + port = state->card->iobase + dmabuf->codec_spdifout_channel->port; + else if (rec == 3) + port = state->card->iobase + dmabuf->controller_spdifout_channel->port; + else + port = state->card->iobase + dmabuf->write_channel->port; + + port_picb = port + OFF_PICB; + + do { + civ = inb(port + OFF_CIV) & 31; + offset = inw(port_picb); + /* Must have a delay here! */ + if (offset == 0) + udelay(1); + + /* Reread both registers and make sure that that total + * offset from the first reading to the second is 0. + * There is an issue with SiS hardware where it will count + * picb down to 0, then update civ to the next value, + * then set the new picb to fragsize bytes. We can catch + * it between the civ update and the picb update, making + * it look as though we are 1 fragsize ahead of where we + * are. The next to we get the address though, it will + * be back in thdelay is more than long enough + * that we won't have to worry about the chip still being + * out of sync with reality ;-) + */ + } while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb)); + + data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize; + if (inw(port_picb) == 0) + data -= 2048; + + return data; +} + +/* Stop recording (lock held) */ +static inline void __stop_adc(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct ali_card *card = state->card; + + dmabuf->enable &= ~ADC_RUNNING; + + outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR); + udelay(1); + + outb(0, card->iobase + PI_CR); + while (inb(card->iobase + PI_CR) != 0); + + // now clear any latent interrupt bits (like the halt bit) + outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR); + outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR); +} + +static void stop_adc(struct ali_state *state) +{ + struct ali_card *card = state->card; + unsigned long flags; + spin_lock_irqsave(&card->lock, flags); + __stop_adc(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static inline void __start_adc(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + + if (dmabuf->count < dmabuf->dmasize && dmabuf->ready + && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) { + dmabuf->enable |= ADC_RUNNING; + outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR); + if (state->card->channel[0].used == 1) + outl(1, state->card->iobase + ALI_DMACR); // DMA CONTROL REGISTRER + udelay(100); + if (state->card->channel[2].used == 1) + outl((1 << 2), state->card->iobase + ALI_DMACR); //DMA CONTROL REGISTER + udelay(100); + } +} + +static void start_adc(struct ali_state *state) +{ + struct ali_card *card = state->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + __start_adc(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +/* stop playback (lock held) */ +static inline void __stop_dac(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct ali_card *card = state->card; + + dmabuf->enable &= ~DAC_RUNNING; + outl(0x00020000, card->iobase + 0x08); + outb(0, card->iobase + PO_CR); + while (inb(card->iobase + PO_CR) != 0) + cpu_relax(); + + outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR); + + outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR); +} + +static void stop_dac(struct ali_state *state) +{ + struct ali_card *card = state->card; + unsigned long flags; + spin_lock_irqsave(&card->lock, flags); + __stop_dac(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static inline void __start_dac(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && + (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { + dmabuf->enable |= DAC_RUNNING; + outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR); + outl((1 << 1), state->card->iobase + 0x08); //dma control register + } +} + +static void start_dac(struct ali_state *state) +{ + struct ali_card *card = state->card; + unsigned long flags; + spin_lock_irqsave(&card->lock, flags); + __start_dac(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +/* stop codec and controller spdif out (lock held) */ +static inline void __stop_spdifout(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct ali_card *card = state->card; + + if (codec_independent_spdif_locked > 0) { + dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING; + outl((1 << 19), card->iobase + 0x08); + outb(0, card->iobase + CODECSPDIFOUT_CR); + + while (inb(card->iobase + CODECSPDIFOUT_CR) != 0) + cpu_relax(); + + outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR); + outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR); + } else { + if (controller_independent_spdif_locked > 0) { + dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING; + outl((1 << 23), card->iobase + 0x08); + outb(0, card->iobase + CONTROLLERSPDIFOUT_CR); + while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0) + cpu_relax(); + outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR); + outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR); + } + } +} + +static void stop_spdifout(struct ali_state *state) +{ + struct ali_card *card = state->card; + unsigned long flags; + spin_lock_irqsave(&card->lock, flags); + __stop_spdifout(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +static inline void __start_spdifout(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && + (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) { + if (codec_independent_spdif_locked > 0) { + dmabuf->enable |= CODEC_SPDIFOUT_RUNNING; + outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR); + outl((1 << 3), state->card->iobase + 0x08); //dma control register + } else { + if (controller_independent_spdif_locked > 0) { + dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING; + outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR); + outl((1 << 7), state->card->iobase + 0x08); //dma control register + } + } + } +} + +static void start_spdifout(struct ali_state *state) +{ + struct ali_card *card = state->card; + unsigned long flags; + spin_lock_irqsave(&card->lock, flags); + __start_spdifout(state); + spin_unlock_irqrestore(&card->lock, flags); +} + +#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) +#define DMABUF_MINORDER 1 + +/* allocate DMA buffer, playback , recording,spdif out buffer should be allocated seperately */ +static int alloc_dmabuf(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + void *rawbuf = NULL; + int order, size; + struct page *page, *pend; + + /* If we don't have any oss frag params, then use our default ones */ + if (dmabuf->ossmaxfrags == 0) + dmabuf->ossmaxfrags = 4; + if (dmabuf->ossfragsize == 0) + dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags; + size = dmabuf->ossfragsize * dmabuf->ossmaxfrags; + + if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size) + return 0; + /* alloc enough to satisfy the oss params */ + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) { + if ((PAGE_SIZE << order) > size) + continue; + if ((rawbuf = pci_alloc_consistent(state->card->pci_dev, + PAGE_SIZE << order, + &dmabuf->dma_handle))) + break; + } + if (!rawbuf) + return -ENOMEM; + + dmabuf->ready = dmabuf->mapped = 0; + dmabuf->rawbuf = rawbuf; + dmabuf->buforder = order; + + /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ + pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); + for (page = virt_to_page(rawbuf); page <= pend; page++) + mem_map_reserve(page); + return 0; +} + +/* free DMA buffer */ +static void dealloc_dmabuf(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct page *page, *pend; + + if (dmabuf->rawbuf) { + /* undo marking the pages as reserved */ + pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); + for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) + mem_map_unreserve(page); + pci_free_consistent(state->card->pci_dev, + PAGE_SIZE << dmabuf->buforder, + dmabuf->rawbuf, dmabuf->dma_handle); + } + dmabuf->rawbuf = NULL; + dmabuf->mapped = dmabuf->ready = 0; +} + +static int prog_dmabuf(struct ali_state *state, unsigned rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + struct ali_channel *c = NULL; + struct sg_item *sg; + unsigned long flags; + int ret; + unsigned fragint; + int i; + + spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->enable & DAC_RUNNING) + __stop_dac(state); + if (dmabuf->enable & ADC_RUNNING) + __stop_adc(state); + if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) + __stop_spdifout(state); + if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) + __stop_spdifout(state); + + dmabuf->total_bytes = 0; + dmabuf->count = dmabuf->error = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + spin_unlock_irqrestore(&state->card->lock, flags); + + /* allocate DMA buffer, let alloc_dmabuf determine if we are already + * allocated well enough or if we should replace the current buffer + * (assuming one is already allocated, if it isn't, then allocate it). + */ + if ((ret = alloc_dmabuf(state))) + return ret; + + /* FIXME: figure out all this OSS fragment stuff */ + /* I did, it now does what it should according to the OSS API. DL */ + /* We may not have realloced our dmabuf, but the fragment size to + * fragment number ratio may have changed, so go ahead and reprogram + * things + */ + + dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder; + dmabuf->numfrag = SG_LEN; + dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag; + dmabuf->fragsamples = dmabuf->fragsize >> 1; + dmabuf->userfragsize = dmabuf->ossfragsize; + dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize; + + memset(dmabuf->rawbuf, 0, dmabuf->dmasize); + + if (dmabuf->ossmaxfrags == 4) { + fragint = 8; + dmabuf->fragshift = 2; + } else if (dmabuf->ossmaxfrags == 8) { + fragint = 4; + dmabuf->fragshift = 3; + } else if (dmabuf->ossmaxfrags == 16) { + fragint = 2; + dmabuf->fragshift = 4; + } else { + fragint = 1; + dmabuf->fragshift = 5; + } + /* + * Now set up the ring + */ + + if (rec == 1) + c = dmabuf->read_channel; + else if (rec == 2) + c = dmabuf->codec_spdifout_channel; + else if (rec == 3) + c = dmabuf->controller_spdifout_channel; + else if (rec == 0) + c = dmabuf->write_channel; + if (c != NULL) { + sg = &c->sg[0]; + /* + * Load up 32 sg entries and take an interrupt at half + * way (we might want more interrupts later..) + */ + for (i = 0; i < dmabuf->numfrag; i++) { + sg->busaddr = + virt_to_bus(dmabuf->rawbuf + + dmabuf->fragsize * i); + // the card will always be doing 16bit stereo + sg->control = dmabuf->fragsamples; + sg->control |= CON_BUFPAD; //I modify + // set us up to get IOC interrupts as often as needed to + // satisfy numfrag requirements, no more + if (((i + 1) % fragint) == 0) { + sg->control |= CON_IOC; + } + sg++; + } + spin_lock_irqsave(&state->card->lock, flags); + outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */ + outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR); + outb(0, state->card->iobase + c->port + OFF_CIV); + outb(0, state->card->iobase + c->port + OFF_LVI); + spin_unlock_irqrestore(&state->card->lock, flags); + } + /* set the ready flag for the dma buffer */ + dmabuf->ready = 1; + return 0; +} + +static void __ali_update_lvi(struct ali_state *state, int rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + int x, port; + port = state->card->iobase; + if (rec == 1) + port += dmabuf->read_channel->port; + else if (rec == 2) + port += dmabuf->codec_spdifout_channel->port; + else if (rec == 3) + port += dmabuf->controller_spdifout_channel->port; + else if (rec == 0) + port += dmabuf->write_channel->port; + /* if we are currently stopped, then our CIV is actually set to our + * *last* sg segment and we are ready to wrap to the next. However, + * if we set our LVI to the last sg segment, then it won't wrap to + * the next sg segment, it won't even get a start. So, instead, when + * we are stopped, we set both the LVI value and also we increment + * the CIV value to the next sg segment to be played so that when + * we call start_{dac,adc}, things will operate properly + */ + if (!dmabuf->enable && dmabuf->ready) { + if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) { + outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI); + __start_adc(state); + while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2)))) + cpu_relax(); + } else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { + outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI); + __start_dac(state); + while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2)))) + cpu_relax(); + } else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) { + if (codec_independent_spdif_locked > 0) { + // outb((inb(port+OFF_CIV))&31, port+OFF_LVI); + outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI); + __start_spdifout(state); + while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2)))) + cpu_relax(); + } else { + if (controller_independent_spdif_locked > 0) { + outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI); + __start_spdifout(state); + while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2)))) + cpu_relax(); + } + } + } + } + + /* swptr - 1 is the tail of our transfer */ + x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize; + x /= dmabuf->fragsize; + outb(x, port + OFF_LVI); +} + +static void ali_update_lvi(struct ali_state *state, int rec) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + if (!dmabuf->ready) + return; + spin_lock_irqsave(&state->card->lock, flags); + __ali_update_lvi(state, rec); + spin_unlock_irqrestore(&state->card->lock, flags); +} + +/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ +static void ali_update_ptr(struct ali_state *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + unsigned hwptr; + int diff; + + /* error handling and process wake up for DAC */ + if (dmabuf->enable == ADC_RUNNING) { + /* update hardware pointer */ + hwptr = ali_get_dma_addr(state, 1); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count += diff; + if (dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun */ + /* this is normal for the end of a read */ + /* only give an error if we went past the */ + /* last valid sg entry */ + if ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) { + printk(KERN_WARNING "ali_audio: DMA overrun on read\n"); + dmabuf->error++; + } + } + if (dmabuf->count > dmabuf->userfragsize) + wake_up(&dmabuf->wait); + } + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { + /* update hardware pointer */ + hwptr = ali_get_dma_addr(state, 0); + diff = + (dmabuf->dmasize + hwptr - + dmabuf->hwptr) % dmabuf->dmasize; +#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP) + printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); +#endif + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count -= diff; + if (dmabuf->count < 0) { + /* buffer underrun or buffer overrun */ + /* this is normal for the end of a write */ + /* only give an error if we went past the */ + /* last valid sg entry */ + if ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) { + printk(KERN_WARNING "ali_audio: DMA overrun on write\n"); + printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n", + inb(state->card->iobase + PO_CIV) & 31, + inb(state->card->iobase + PO_LVI) & 31, + dmabuf->hwptr, + dmabuf->count); + dmabuf->error++; + } + } + if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize)) + wake_up(&dmabuf->wait); + } + + /* error handling and process wake up for CODEC SPDIF OUT */ + if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) { + /* update hardware pointer */ + hwptr = ali_get_dma_addr(state, 2); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count -= diff; + if (dmabuf->count < 0) { + /* buffer underrun or buffer overrun */ + /* this is normal for the end of a write */ + /* only give an error if we went past the */ + /* last valid sg entry */ + if ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) { + printk(KERN_WARNING "ali_audio: DMA overrun on write\n"); + printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n", + inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31, + inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31, + dmabuf->hwptr, dmabuf->count); + dmabuf->error++; + } + } + if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize)) + wake_up(&dmabuf->wait); + } + /* error handling and process wake up for CONTROLLER SPDIF OUT */ + if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) { + /* update hardware pointer */ + hwptr = ali_get_dma_addr(state, 3); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; + dmabuf->count -= diff; + if (dmabuf->count < 0) { + /* buffer underrun or buffer overrun */ + /* this is normal for the end of a write */ + /* only give an error if we went past the */ + /* last valid sg entry */ + if ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) { + printk(KERN_WARNING + "ali_audio: DMA overrun on write\n"); + printk("ali_audio: CIV %d, LVI %d, hwptr %x, " + "count %d\n", + inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31, + inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31, + dmabuf->hwptr, dmabuf->count); + dmabuf->error++; + } + } + if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize)) + wake_up(&dmabuf->wait); + } +} + +static inline int ali_get_free_write_space(struct + ali_state + *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + int free; + ali_update_ptr(state); + // catch underruns during playback + if (dmabuf->count < 0) { + dmabuf->count = 0; + dmabuf->swptr = dmabuf->hwptr; + } + free = dmabuf->dmasize - dmabuf->count; + free -= (dmabuf->hwptr % dmabuf->fragsize); + if (free < 0) + return (0); + return (free); +} + +static inline int ali_get_available_read_data(struct + ali_state + *state) +{ + struct dmabuf *dmabuf = &state->dmabuf; + int avail; + ali_update_ptr(state); + // catch overruns during record + if (dmabuf->count > dmabuf->dmasize) { + dmabuf->count = dmabuf->dmasize; + dmabuf->swptr = dmabuf->hwptr; + } + avail = dmabuf->count; + avail -= (dmabuf->hwptr % dmabuf->fragsize); + if (avail < 0) + return (0); + return (avail); +} + +static int drain_dac(struct ali_state *state, int signals_allowed) +{ + + DECLARE_WAITQUEUE(wait, current); + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned long tmo; + int count; + if (!dmabuf->ready) + return 0; + if (dmabuf->mapped) { + stop_dac(state); + return 0; + } + add_wait_queue(&dmabuf->wait, &wait); + for (;;) { + + spin_lock_irqsave(&state->card->lock, flags); + ali_update_ptr(state); + count = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + if (count <= 0) + break; + /* + * This will make sure that our LVI is correct, that our + * pointer is updated, and that the DAC is running. We + * have to force the setting of dmabuf->trigger to avoid + * any possible deadlocks. + */ + if (!dmabuf->enable) { + dmabuf->trigger = PCM_ENABLE_OUTPUT; + ali_update_lvi(state, 0); + } + if (signal_pending(current) && signals_allowed) { + break; + } + + /* It seems that we have to set the current state to + * TASK_INTERRUPTIBLE every time to make the process + * really go to sleep. This also has to be *after* the + * update_ptr() call because update_ptr is likely to + * do a wake_up() which will unset this before we ever + * try to sleep, resuling in a tight loop in this code + * instead of actually sleeping and waiting for an + * interrupt to wake us up! + */ + set_current_state(TASK_INTERRUPTIBLE); + /* + * set the timeout to significantly longer than it *should* + * take for the DAC to drain the DMA buffer + */ + tmo = (count * HZ) / (dmabuf->rate); + if (!schedule_timeout(tmo >= 2 ? tmo : 2)) { + printk(KERN_ERR "ali_audio: drain_dac, dma timeout?\n"); + count = 0; + break; + } + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&dmabuf->wait, &wait); + if (count > 0 && signal_pending(current) && signals_allowed) + return -ERESTARTSYS; + stop_dac(state); + return 0; +} + + +static int drain_spdifout(struct ali_state *state, int signals_allowed) +{ + + DECLARE_WAITQUEUE(wait, current); + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned long tmo; + int count; + if (!dmabuf->ready) + return 0; + if (dmabuf->mapped) { + stop_spdifout(state); + return 0; + } + add_wait_queue(&dmabuf->wait, &wait); + for (;;) { + + spin_lock_irqsave(&state->card->lock, flags); + ali_update_ptr(state); + count = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); + if (count <= 0) + break; + /* + * This will make sure that our LVI is correct, that our + * pointer is updated, and that the DAC is running. We + * have to force the setting of dmabuf->trigger to avoid + * any possible deadlocks. + */ + if (!dmabuf->enable) { + if (codec_independent_spdif_locked > 0) { + dmabuf->trigger = SPDIF_ENABLE_OUTPUT; + ali_update_lvi(state, 2); + } else { + if (controller_independent_spdif_locked > 0) { + dmabuf->trigger = SPDIF_ENABLE_OUTPUT; + ali_update_lvi(state, 3); + } + } + } + if (signal_pending(current) && signals_allowed) { + break; + } + + /* It seems that we have to set the current state to + * TASK_INTERRUPTIBLE every time to make the process + * really go to sleep. This also has to be *after* the + * update_ptr() call because update_ptr is likely to + * do a wake_up() which will unset this before we ever + * try to sleep, resuling in a tight loop in this code + * instead of actually sleeping and waiting for an + * interrupt to wake us up! + */ + set_current_state(TASK_INTERRUPTIBLE); + /* + * set the timeout to significantly longer than it *should* + * take for the DAC to drain the DMA buffer + */ + tmo = (count * HZ) / (dmabuf->rate); + if (!schedule_timeout(tmo >= 2 ? tmo : 2)) { + printk(KERN_ERR "ali_audio: drain_spdifout, dma timeout?\n"); + count = 0; + break; + } + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&dmabuf->wait, &wait); + if (count > 0 && signal_pending(current) && signals_allowed) + return -ERESTARTSYS; + stop_spdifout(state); + return 0; +} + +static void ali_channel_interrupt(struct ali_card *card) +{ + int i, count; + + for (i = 0; i < NR_HW_CH; i++) { + struct ali_state *state = card->states[i]; + struct ali_channel *c = NULL; + struct dmabuf *dmabuf; + unsigned long port = card->iobase; + u16 status; + if (!state) + continue; + if (!state->dmabuf.ready) + continue; + dmabuf = &state->dmabuf; + if (codec_independent_spdif_locked > 0) { + if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) { + c = dmabuf->codec_spdifout_channel; + } + } else { + if (controller_independent_spdif_locked > 0) { + if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) + c = dmabuf->controller_spdifout_channel; + } else { + if (dmabuf->enable & DAC_RUNNING) { + c = dmabuf->write_channel; + } else if (dmabuf->enable & ADC_RUNNING) { + c = dmabuf->read_channel; + } else + continue; + } + } + port += c->port; + + status = inw(port + OFF_SR); + + if (status & DMA_INT_COMPLETE) { + /* only wake_up() waiters if this interrupt signals + * us being beyond a userfragsize of data open or + * available, and ali_update_ptr() does that for + * us + */ + ali_update_ptr(state); + } + + if (status & DMA_INT_LVI) { + ali_update_ptr(state); + wake_up(&dmabuf->wait); + + if (dmabuf->enable & DAC_RUNNING) + count = dmabuf->count; + else if (dmabuf->enable & ADC_RUNNING) + count = dmabuf->dmasize - dmabuf->count; + else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) + count = dmabuf->count; + else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) + count = dmabuf->count; + else count = 0; + + if (count > 0) { + if (dmabuf->enable & DAC_RUNNING) + outl((1 << 1), state->card->iobase + ALI_DMACR); + else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) + outl((1 << 3), state->card->iobase + ALI_DMACR); + else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) + outl((1 << 7), state->card->iobase + ALI_DMACR); + } else { + if (dmabuf->enable & DAC_RUNNING) + __stop_dac(state); + if (dmabuf->enable & ADC_RUNNING) + __stop_adc(state); + if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) + __stop_spdifout(state); + if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) + __stop_spdifout(state); + dmabuf->enable = 0; + wake_up(&dmabuf->wait); + } + + } + if (!(status & DMA_INT_DCH)) { + ali_update_ptr(state); + wake_up(&dmabuf->wait); + if (dmabuf->enable & DAC_RUNNING) + count = dmabuf->count; + else if (dmabuf->enable & ADC_RUNNING) + count = dmabuf->dmasize - dmabuf->count; + else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) + count = dmabuf->count; + else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) + count = dmabuf->count; + else + count = 0; + + if (count > 0) { + if (dmabuf->enable & DAC_RUNNING) + outl((1 << 1), state->card->iobase + ALI_DMACR); + else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) + outl((1 << 3), state->card->iobase + ALI_DMACR); + else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) + outl((1 << 7), state->card->iobase + ALI_DMACR); + } else { + if (dmabuf->enable & DAC_RUNNING) + __stop_dac(state); + if (dmabuf->enable & ADC_RUNNING) + __stop_adc(state); + if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) + __stop_spdifout(state); + if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) + __stop_spdifout(state); + dmabuf->enable = 0; + wake_up(&dmabuf->wait); + } + } + outw(status & DMA_INT_MASK, port + OFF_SR); + } +} + +static void ali_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct ali_card *card = (struct ali_card *) dev_id; + u32 status; + u16 status2; + + spin_lock(&card->lock); + status = inl(card->iobase + ALI_INTERRUPTSR); + if (!(status & INT_MASK)) { + spin_unlock(&card->lock); + return; /* not for us */ + } + + if (codec_independent_spdif_locked > 0) { + if (globel == 0) { + globel += 1; + status2 = inw(card->iobase + 0x76); + outw(status2 | 0x000c, card->iobase + 0x76); + } else { + if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT)) + ali_channel_interrupt(card); + } + } else { + if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT)) + ali_channel_interrupt(card); + } + + /* clear 'em */ + outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR); + spin_unlock(&card->lock); +} + +/* in this loop, dmabuf.count signifies the amount of data that is + waiting to be copied to the user's buffer. It is filled by the dma + machine and drained by this loop. */ + +static ssize_t ali_read(struct file *file, char *buffer, + size_t count, loff_t * ppos) +{ + struct ali_state *state = (struct ali_state *) file->private_data; + struct ali_card *card = state ? state->card : 0; + struct dmabuf *dmabuf = &state->dmabuf; + ssize_t ret; + unsigned long flags; + unsigned int swptr; + int cnt; + DECLARE_WAITQUEUE(waita, current); +#ifdef DEBUG2 + printk("ali_audio: ali_read called, count = %d\n", count); +#endif + if (ppos != &file->f_pos) + return -ESPIPE; + if (dmabuf->mapped) + return -ENXIO; + if (dmabuf->enable & DAC_RUNNING) + return -ENODEV; + if (!dmabuf->read_channel) { + dmabuf->ready = 0; + dmabuf->read_channel = card->alloc_rec_pcm_channel(card); + if (!dmabuf->read_channel) { + return -EBUSY; + } + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + add_wait_queue(&dmabuf->wait, &waita); + while (count > 0) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&card->lock, flags); + if (PM_SUSPENDED(card)) { + spin_unlock_irqrestore(&card->lock, flags); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -EAGAIN; + break; + } + continue; + } + swptr = dmabuf->swptr; + cnt = ali_get_available_read_data(state); + // this is to make the copy_to_user simpler below + if (cnt > (dmabuf->dmasize - swptr)) + cnt = dmabuf->dmasize - swptr; + spin_unlock_irqrestore(&card->lock, flags); + if (cnt > count) + cnt = count; + /* Lop off the last two bits to force the code to always + * write in full samples. This keeps software that sets + * O_NONBLOCK but doesn't check the return value of the + * write call from getting things out of state where they + * think a full 4 byte sample was written when really only + * a portion was, resulting in odd sound and stereo + * hysteresis. + */ + cnt &= ~0x3; + if (cnt <= 0) { + unsigned long tmo; + /* + * Don't let us deadlock. The ADC won't start if + * dmabuf->trigger isn't set. A call to SETTRIGGER + * could have turned it off after we set it to on + * previously. + */ + dmabuf->trigger = PCM_ENABLE_INPUT; + /* + * This does three things. Updates LVI to be correct, + * makes sure the ADC is running, and updates the + * hwptr. + */ + ali_update_lvi(state, 1); + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + goto done; + } + /* Set the timeout to how long it would take to fill + * two of our buffers. If we haven't been woke up + * by then, then we know something is wrong. + */ + tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4); + + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer overrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!schedule_timeout(tmo >= 2 ? tmo : 2)) { + printk(KERN_ERR + "ali_audio: recording schedule timeout, " + "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + dmabuf->dmasize, dmabuf->fragsize, + dmabuf->count, dmabuf->hwptr, + dmabuf->swptr); + /* a buffer overrun, we delay the recovery until next time the + while loop begin and we REALLY have space to record */ + } + if (signal_pending(current)) { + ret = ret ? ret : -ERESTARTSYS; + goto done; + } + continue; + } + + if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { + if (!ret) + ret = -EFAULT; + goto done; + } + + swptr = (swptr + cnt) % dmabuf->dmasize; + spin_lock_irqsave(&card->lock, flags); + if (PM_SUSPENDED(card)) { + spin_unlock_irqrestore(&card->lock, flags); + continue; + } + dmabuf->swptr = swptr; + dmabuf->count -= cnt; + spin_unlock_irqrestore(&card->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + } +done: + ali_update_lvi(state, 1); + set_current_state(TASK_RUNNING); + remove_wait_queue(&dmabuf->wait, &waita); + return ret; +} + +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to + the soundcard. it is drained by the dma machine and filled by this loop. */ +static ssize_t ali_write(struct file *file, + const char *buffer, size_t count, loff_t * ppos) +{ + struct ali_state *state = (struct ali_state *) file->private_data; + struct ali_card *card = state ? state->card : 0; + struct dmabuf *dmabuf = &state->dmabuf; + ssize_t ret; + unsigned long flags; + unsigned int swptr = 0; + int cnt, x; + DECLARE_WAITQUEUE(waita, current); +#ifdef DEBUG2 + printk("ali_audio: ali_write called, count = %d\n", count); +#endif + if (ppos != &file->f_pos) + return -ESPIPE; + if (dmabuf->mapped) + return -ENXIO; + if (dmabuf->enable & ADC_RUNNING) + return -ENODEV; + if (codec_independent_spdif_locked > 0) { + if (!dmabuf->codec_spdifout_channel) { + dmabuf->ready = 0; + dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card); + if (!dmabuf->codec_spdifout_channel) + return -EBUSY; + } + } else { + if (controller_independent_spdif_locked > 0) { + if (!dmabuf->controller_spdifout_channel) { + dmabuf->ready = 0; + dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card); + if (!dmabuf->controller_spdifout_channel) + return -EBUSY; + } + } else { + if (!dmabuf->write_channel) { + dmabuf->ready = 0; + dmabuf->write_channel = + card->alloc_pcm_channel(card); + if (!dmabuf->write_channel) + return -EBUSY; + } + } + } + + if (codec_independent_spdif_locked > 0) { + if (!dmabuf->ready && (ret = prog_dmabuf(state, 2))) + return ret; + } else { + if (controller_independent_spdif_locked > 0) { + if (!dmabuf->ready && (ret = prog_dmabuf(state, 3))) + return ret; + } else { + + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + } + } + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + add_wait_queue(&dmabuf->wait, &waita); + while (count > 0) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&state->card->lock, flags); + if (PM_SUSPENDED(card)) { + spin_unlock_irqrestore(&card->lock, flags); + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -EAGAIN; + break; + } + continue; + } + + swptr = dmabuf->swptr; + cnt = ali_get_free_write_space(state); + /* Bound the maximum size to how much we can copy to the + * dma buffer before we hit the end. If we have more to + * copy then it will get done in a second pass of this + * loop starting from the beginning of the buffer. + */ + if (cnt > (dmabuf->dmasize - swptr)) + cnt = dmabuf->dmasize - swptr; + spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG2 + printk(KERN_INFO + "ali_audio: ali_write: %d bytes available space\n", + cnt); +#endif + if (cnt > count) + cnt = count; + /* Lop off the last two bits to force the code to always + * write in full samples. This keeps software that sets + * O_NONBLOCK but doesn't check the return value of the + * write call from getting things out of state where they + * think a full 4 byte sample was written when really only + * a portion was, resulting in odd sound and stereo + * hysteresis. + */ + cnt &= ~0x3; + if (cnt <= 0) { + unsigned long tmo; + // There is data waiting to be played + /* + * Force the trigger setting since we would + * deadlock with it set any other way + */ + if (codec_independent_spdif_locked > 0) { + dmabuf->trigger = SPDIF_ENABLE_OUTPUT; + ali_update_lvi(state, 2); + } else { + if (controller_independent_spdif_locked > 0) { + dmabuf->trigger = SPDIF_ENABLE_OUTPUT; + ali_update_lvi(state, 3); + } else { + + dmabuf->trigger = PCM_ENABLE_OUTPUT; + ali_update_lvi(state, 0); + } + } + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + goto ret; + } + /* Not strictly correct but works */ + tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4); + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer underrun. And worse, there is + NOTHING we can do to prevent it. */ + + /* FIXME - do timeout handling here !! */ + + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + goto ret; + } + continue; + } + if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + goto ret; + } + + swptr = (swptr + cnt) % dmabuf->dmasize; + spin_lock_irqsave(&state->card->lock, flags); + if (PM_SUSPENDED(card)) { + spin_unlock_irqrestore(&card->lock, flags); + continue; + } + + dmabuf->swptr = swptr; + dmabuf->count += cnt; + count -= cnt; + buffer += cnt; + ret += cnt; + spin_unlock_irqrestore(&state->card->lock, flags); + } + if (swptr % dmabuf->fragsize) { + x = dmabuf->fragsize - (swptr % dmabuf->fragsize); + memset(dmabuf->rawbuf + swptr, '\0', x); + } +ret: + if (codec_independent_spdif_locked > 0) { + ali_update_lvi(state, 2); + } else { + if (controller_independent_spdif_locked > 0) { + ali_update_lvi(state, 3); + } else { + ali_update_lvi(state, 0); + } + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&dmabuf->wait, &waita); + return ret; +} + +/* No kernel lock - we have our own spinlock */ +static unsigned int ali_poll(struct file *file, struct poll_table_struct + *wait) +{ + struct ali_state *state = (struct ali_state *) file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + unsigned int mask = 0; + if (!dmabuf->ready) + return 0; + poll_wait(file, &dmabuf->wait, wait); + spin_lock_irqsave(&state->card->lock, flags); + ali_update_ptr(state); + if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) { + if (dmabuf->count >= (signed) dmabuf->fragsize) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_mode & FMODE_WRITE && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) { + if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize) + mask |= POLLOUT | POLLWRNORM; + } + spin_unlock_irqrestore(&state->card->lock, flags); + return mask; +} + +static int ali_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct ali_state *state = (struct ali_state *) file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; + int ret = -EINVAL; + unsigned long size; + lock_kernel(); + if (vma->vm_flags & VM_WRITE) { + if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) { + ret = -EBUSY; + goto out; + } + } + if (vma->vm_flags & VM_READ) { + if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) { + ret = -EBUSY; + goto out; + } + } + if ((ret = prog_dmabuf(state, 0)) != 0) + goto out; + ret = -EINVAL; + if (vma->vm_pgoff != 0) + goto out; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << dmabuf->buforder)) + goto out; + ret = -EAGAIN; + if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) + goto out; + dmabuf->mapped = 1; + dmabuf->trigger = 0; + ret = 0; +out: + unlock_kernel(); + return ret; +} + +static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ali_state *state = (struct ali_state *) file->private_data; + struct ali_channel *c = NULL; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + unsigned int i_scr; + int val = 0, ret; + struct ac97_codec *codec = state->card->ac97_codec[0]; +#ifdef DEBUG + printk("ali_audio: ali_ioctl, arg=0x%x, cmd=", + arg ? *(int *) arg : 0); +#endif + switch (cmd) { + case OSS_GETVERSION: +#ifdef DEBUG + printk("OSS_GETVERSION\n"); +#endif + return put_user(SOUND_VERSION, (int *) arg); + case SNDCTL_DSP_RESET: +#ifdef DEBUG + printk("SNDCTL_DSP_RESET\n"); +#endif + spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->enable == DAC_RUNNING) { + c = dmabuf->write_channel; + __stop_dac(state); + } + if (dmabuf->enable == ADC_RUNNING) { + c = dmabuf->read_channel; + __stop_adc(state); + } + if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) { + c = dmabuf->codec_spdifout_channel; + __stop_spdifout(state); + } + if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) { + c = dmabuf->controller_spdifout_channel; + __stop_spdifout(state); + } + if (c != NULL) { + outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */ + outl(virt_to_bus(&c->sg[0]), + state->card->iobase + c->port + OFF_BDBAR); + outb(0, state->card->iobase + c->port + OFF_CIV); + outb(0, state->card->iobase + c->port + OFF_LVI); + } + + spin_unlock_irqrestore(&state->card->lock, flags); + synchronize_irq(); + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; + return 0; + case SNDCTL_DSP_SYNC: +#ifdef DEBUG + printk("SNDCTL_DSP_SYNC\n"); +#endif + if (codec_independent_spdif_locked > 0) { + if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING + || file->f_flags & O_NONBLOCK) + return 0; + if ((val = drain_spdifout(state, 1))) + return val; + } else { + if (controller_independent_spdif_locked > 0) { + if (dmabuf->enable != + CONTROLLER_SPDIFOUT_RUNNING + || file->f_flags & O_NONBLOCK) + return 0; + if ((val = drain_spdifout(state, 1))) + return val; + } else { + if (dmabuf->enable != DAC_RUNNING + || file->f_flags & O_NONBLOCK) + return 0; + if ((val = drain_dac(state, 1))) + return val; + } + } + dmabuf->total_bytes = 0; + return 0; + case SNDCTL_DSP_SPEED: /* set smaple rate */ +#ifdef DEBUG + printk("SNDCTL_DSP_SPEED\n"); +#endif + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val >= 0) { + if (file->f_mode & FMODE_WRITE) { + if ((state->card->ac97_status & SPDIF_ON)) { /* S/PDIF Enabled */ + /* RELTEK ALC650 only support 48000, need to check that */ + if (ali_valid_spdif_rate(codec, val)) { + if (codec_independent_spdif_locked > 0) { + ali_set_spdif_output(state, -1, 0); + stop_spdifout(state); + dmabuf->ready = 0; + /* I add test codec independent spdif out */ + spin_lock_irqsave(&state->card->lock, flags); + ali_set_codecspdifout_rate(state, val); // I modified + spin_unlock_irqrestore(&state->card->lock, flags); + /* Set S/PDIF transmitter rate. */ + i_scr = inl(state->card->iobase + ALI_SCR); + if ((i_scr & 0x00300000) == 0x00100000) { + ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); + } else { + if ((i_scr&0x00300000) == 0x00200000) + { + ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked); + } else { + if ((i_scr & 0x00300000) == 0x00300000) { + ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked); + } else { + ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); + } + } + } + + if (!(state->card->ac97_status & SPDIF_ON)) { + val = dmabuf->rate; + } + } else { + if (controller_independent_spdif_locked > 0) + { + stop_spdifout(state); + dmabuf->ready = 0; + spin_lock_irqsave(&state->card->lock, flags); + ali_set_spdifout_rate(state, controller_independent_spdif_locked); + spin_unlock_irqrestore(&state->card->lock, flags); + } else { + /* Set DAC rate */ + ali_set_spdif_output(state, -1, 0); + stop_dac(state); + dmabuf->ready = 0; + spin_lock_irqsave(&state->card->lock, flags); + ali_set_dac_rate(state, val); + spin_unlock_irqrestore(&state->card->lock, flags); + /* Set S/PDIF transmitter rate. */ + ali_set_spdif_output(state, AC97_EA_SPSA_3_4, val); + if (!(state->card->ac97_status & SPDIF_ON)) + { + val = dmabuf->rate; + } + } + } + } else { /* Not a valid rate for S/PDIF, ignore it */ + val = dmabuf->rate; + } + } else { + stop_dac(state); + dmabuf->ready = 0; + spin_lock_irqsave(&state->card->lock, flags); + ali_set_dac_rate(state, val); + spin_unlock_irqrestore(&state->card->lock, flags); + } + } + if (file->f_mode & FMODE_READ) { + stop_adc(state); + dmabuf->ready = 0; + spin_lock_irqsave(&state->card->lock, flags); + ali_set_adc_rate(state, val); + spin_unlock_irqrestore(&state->card->lock, flags); + } + } + return put_user(dmabuf->rate, (int *) arg); + case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ +#ifdef DEBUG + printk("SNDCTL_DSP_STEREO\n"); +#endif + if (dmabuf->enable & DAC_RUNNING) { + stop_dac(state); + } + if (dmabuf->enable & ADC_RUNNING) { + stop_adc(state); + } + if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) { + stop_spdifout(state); + } + if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) { + stop_spdifout(state); + } + return put_user(1, (int *) arg); + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if (codec_independent_spdif_locked > 0) { + if (!dmabuf->ready && (val = prog_dmabuf(state, 2))) + return val; + } else { + if (controller_independent_spdif_locked > 0) { + if (!dmabuf->ready && (val = prog_dmabuf(state, 3))) + return val; + } else { + if (!dmabuf->ready && (val = prog_dmabuf(state, 0))) + return val; + } + } + } + + if (file->f_mode & FMODE_READ) { + if (!dmabuf->ready && (val = prog_dmabuf(state, 1))) + return val; + } +#ifdef DEBUG + printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize); +#endif + return put_user(dmabuf->userfragsize, (int *) arg); + case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */ +#ifdef DEBUG + printk("SNDCTL_DSP_GETFMTS\n"); +#endif + return put_user(AFMT_S16_LE, (int *) arg); + case SNDCTL_DSP_SETFMT: /* Select sample format */ +#ifdef DEBUG + printk("SNDCTL_DSP_SETFMT\n"); +#endif + return put_user(AFMT_S16_LE, (int *) arg); + case SNDCTL_DSP_CHANNELS: // add support 4,6 channel +#ifdef DEBUG + printk("SNDCTL_DSP_CHANNELS\n"); +#endif + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val > 0) { + if (dmabuf->enable & DAC_RUNNING) { + stop_dac(state); + } + if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) { + stop_spdifout(state); + } + if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) { + stop_spdifout(state); + } + if (dmabuf->enable & ADC_RUNNING) { + stop_adc(state); + } + } else { + return put_user(state->card->channels, (int *) arg); + } + + i_scr = inl(state->card->iobase + ALI_SCR); + /* Current # of channels enabled */ + if (i_scr & 0x00000100) + ret = 4; + else if (i_scr & 0x00000200) + ret = 6; + else + ret = 2; + switch (val) { + case 2: /* 2 channels is always supported */ + if (codec_independent_spdif_locked > 0) { + outl(((i_scr & 0xfffffcff) | 0x00100000), (state->card->iobase + ALI_SCR)); + } else + outl((i_scr & 0xfffffcff), (state->card->iobase + ALI_SCR)); + /* Do we need to change mixer settings???? */ + break; + case 4: /* Supported on some chipsets, better check first */ + if (codec_independent_spdif_locked > 0) { + outl(((i_scr & 0xfffffcff) | 0x00000100 | 0x00200000), (state->card->iobase + ALI_SCR)); + } else + outl(((i_scr & 0xfffffcff) | 0x00000100), (state->card->iobase + ALI_SCR)); + break; + case 6: /* Supported on some chipsets, better check first */ + if (codec_independent_spdif_locked > 0) { + outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000 | 0x00300000), (state->card->iobase + ALI_SCR)); + } else + outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000), (state->card->iobase + ALI_SCR)); + break; + default: /* nothing else is ever supported by the chipset */ + val = ret; + break; + } + return put_user(val, (int *) arg); + case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */ + /* we update the swptr to the end of the last sg segment then return */ +#ifdef DEBUG + printk("SNDCTL_DSP_POST\n"); +#endif + if (codec_independent_spdif_locked > 0) { + if (!dmabuf->ready || (dmabuf->enable != CODEC_SPDIFOUT_RUNNING)) + return 0; + } else { + if (controller_independent_spdif_locked > 0) { + if (!dmabuf->ready || (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING)) + return 0; + } else { + if (!dmabuf->ready || (dmabuf->enable != DAC_RUNNING)) + return 0; + } + } + if ((dmabuf->swptr % dmabuf->fragsize) != 0) { + val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize); + dmabuf->swptr += val; + dmabuf->count += val; + } + return 0; + case SNDCTL_DSP_SUBDIVIDE: + if (dmabuf->subdivision) + return -EINVAL; + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val != 1 && val != 2 && val != 4) + return -EINVAL; +#ifdef DEBUG + printk("SNDCTL_DSP_SUBDIVIDE %d\n", val); +#endif + dmabuf->subdivision = val; + dmabuf->ready = 0; + return 0; + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, (int *) arg)) + return -EFAULT; + dmabuf->ossfragsize = 1 << (val & 0xffff); + dmabuf->ossmaxfrags = (val >> 16) & 0xffff; + if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags) + return -EINVAL; + /* + * Bound the frag size into our allowed range of 256 - 4096 + */ + if (dmabuf->ossfragsize < 256) + dmabuf->ossfragsize = 256; + else if (dmabuf->ossfragsize > 4096) + dmabuf->ossfragsize = 4096; + /* + * The numfrags could be something reasonable, or it could + * be 0xffff meaning "Give me as much as possible". So, + * we check the numfrags * fragsize doesn't exceed our + * 64k buffer limit, nor is it less than our 8k minimum. + * If it fails either one of these checks, then adjust the + * number of fragments, not the size of them. It's OK if + * our number of fragments doesn't equal 32 or anything + * like our hardware based number now since we are using + * a different frag count for the hardware. Before we get + * into this though, bound the maxfrags to avoid overflow + * issues. A reasonable bound would be 64k / 256 since our + * maximum buffer size is 64k and our minimum frag size is + * 256. On the other end, our minimum buffer size is 8k and + * our maximum frag size is 4k, so the lower bound should + * be 2. + */ + if (dmabuf->ossmaxfrags > 256) + dmabuf->ossmaxfrags = 256; + else if (dmabuf->ossmaxfrags < 2) + dmabuf->ossmaxfrags = 2; + val = dmabuf->ossfragsize * dmabuf->ossmaxfrags; + while (val < 8192) { + val <<= 1; + dmabuf->ossmaxfrags <<= 1; + } + while (val > 65536) { + val >>= 1; + dmabuf->ossmaxfrags >>= 1; + } + dmabuf->ready = 0; +#ifdef DEBUG + printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val, + dmabuf->ossfragsize, dmabuf->ossmaxfrags); +#endif + return 0; + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (codec_independent_spdif_locked > 0) { + if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0) + return val; + } else { + if (controller_independent_spdif_locked > 0) { + if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0) + return val; + } else { + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) + return val; + } + } + spin_lock_irqsave(&state->card->lock, flags); + ali_update_ptr(state); + abinfo.fragsize = dmabuf->userfragsize; + abinfo.fragstotal = dmabuf->userfrags; + if (dmabuf->mapped) + abinfo.bytes = dmabuf->dmasize; + else + abinfo.bytes = ali_get_free_write_space(state); + abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; + spin_unlock_irqrestore(&state->card->lock, flags); +#if defined(DEBUG) || defined(DEBUG_MMAP) + printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", + abinfo.bytes, abinfo.fragsize, abinfo.fragments, + abinfo.fragstotal); +#endif + return copy_to_user((void *) arg, &abinfo, + sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (codec_independent_spdif_locked > 0) { + if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0) + return val; + } else { + if (controller_independent_spdif_locked > 0) { + if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0) + return val; + } else { + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) + return val; + } + } + spin_lock_irqsave(&state->card->lock, flags); + val = ali_get_free_write_space(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.ptr = dmabuf->hwptr; + cinfo.blocks = val / dmabuf->userfragsize; + if (codec_independent_spdif_locked > 0) { + if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) { + dmabuf->count += val; + dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; + __ali_update_lvi(state, 2); + } + } else { + if (controller_independent_spdif_locked > 0) { + if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) { + dmabuf->count += val; + dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; + __ali_update_lvi(state, 3); + } + } else { + if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { + dmabuf->count += val; + dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; + __ali_update_lvi(state, 0); + } + } + } + spin_unlock_irqrestore(&state->card->lock, flags); +#if defined(DEBUG) || defined(DEBUG_MMAP) + printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes, + cinfo.blocks, cinfo.ptr, dmabuf->count); +#endif + return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + abinfo.bytes = ali_get_available_read_data(state); + abinfo.fragsize = dmabuf->userfragsize; + abinfo.fragstotal = dmabuf->userfrags; + abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; + spin_unlock_irqrestore(&state->card->lock, flags); +#if defined(DEBUG) || defined(DEBUG_MMAP) + printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", + abinfo.bytes, abinfo.fragsize, abinfo.fragments, + abinfo.fragstotal); +#endif + return copy_to_user((void *) arg, &abinfo, + sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) + return val; + spin_lock_irqsave(&state->card->lock, flags); + val = ali_get_available_read_data(state); + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = val / dmabuf->userfragsize; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) { + dmabuf->count -= val; + dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; + __ali_update_lvi(state, 1); + } + spin_unlock_irqrestore(&state->card->lock, flags); +#if defined(DEBUG) || defined(DEBUG_MMAP) + printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes, + cinfo.blocks, cinfo.ptr, dmabuf->count); +#endif + return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); + case SNDCTL_DSP_NONBLOCK: +#ifdef DEBUG + printk("SNDCTL_DSP_NONBLOCK\n"); +#endif + file->f_flags |= O_NONBLOCK; + return 0; + case SNDCTL_DSP_GETCAPS: +#ifdef DEBUG + printk("SNDCTL_DSP_GETCAPS\n"); +#endif + return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | + DSP_CAP_MMAP | DSP_CAP_BIND, (int *) arg); + case SNDCTL_DSP_GETTRIGGER: + val = 0; +#ifdef DEBUG + printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger); +#endif + return put_user(dmabuf->trigger, (int *) arg); + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *) arg)) + return -EFAULT; +#if defined(DEBUG) || defined(DEBUG_MMAP) + printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val); +#endif + if (!(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) { + stop_adc(state); + } + if (!(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) { + stop_dac(state); + } + if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CODEC_SPDIFOUT_RUNNING) { + stop_spdifout(state); + } + if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) { + stop_spdifout(state); + } + dmabuf->trigger = val; + if (val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) { + if (!dmabuf->write_channel) { + dmabuf->ready = 0; + dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); + if (!dmabuf->write_channel) + return -EBUSY; + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + if (dmabuf->mapped) { + spin_lock_irqsave(&state->card->lock, flags); + ali_update_ptr(state); + dmabuf->count = 0; + dmabuf->swptr = dmabuf->hwptr; + dmabuf->count = ali_get_free_write_space(state); + dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; + __ali_update_lvi(state, 0); + spin_unlock_irqrestore(&state->card->lock, + flags); + } else + start_dac(state); + } + if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CODEC_SPDIFOUT_RUNNING)) { + if (!dmabuf->codec_spdifout_channel) { + dmabuf->ready = 0; + dmabuf->codec_spdifout_channel = state->card->alloc_codec_spdifout_channel(state->card); + if (!dmabuf->codec_spdifout_channel) + return -EBUSY; + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 2))) + return ret; + if (dmabuf->mapped) { + spin_lock_irqsave(&state->card->lock, flags); + ali_update_ptr(state); + dmabuf->count = 0; + dmabuf->swptr = dmabuf->hwptr; + dmabuf->count = ali_get_free_write_space(state); + dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; + __ali_update_lvi(state, 2); + spin_unlock_irqrestore(&state->card->lock, + flags); + } else + start_spdifout(state); + } + if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)) { + if (!dmabuf->controller_spdifout_channel) { + dmabuf->ready = 0; + dmabuf->controller_spdifout_channel = state->card->alloc_controller_spdifout_channel(state->card); + if (!dmabuf->controller_spdifout_channel) + return -EBUSY; + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 3))) + return ret; + if (dmabuf->mapped) { + spin_lock_irqsave(&state->card->lock, flags); + ali_update_ptr(state); + dmabuf->count = 0; + dmabuf->swptr = dmabuf->hwptr; + dmabuf->count = ali_get_free_write_space(state); + dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; + __ali_update_lvi(state, 3); + spin_unlock_irqrestore(&state->card->lock, flags); + } else + start_spdifout(state); + } + if (val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) { + if (!dmabuf->read_channel) { + dmabuf->ready = 0; + dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); + if (!dmabuf->read_channel) + return -EBUSY; + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + if (dmabuf->mapped) { + spin_lock_irqsave(&state->card->lock, + flags); + ali_update_ptr(state); + dmabuf->swptr = dmabuf->hwptr; + dmabuf->count = 0; + spin_unlock_irqrestore(&state->card->lock, flags); + } + ali_update_lvi(state, 1); + start_adc(state); + } + return 0; + case SNDCTL_DSP_SETDUPLEX: +#ifdef DEBUG + printk("SNDCTL_DSP_SETDUPLEX\n"); +#endif + return -EINVAL; + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&state->card->lock, flags); + ali_update_ptr(state); + val = dmabuf->count; + spin_unlock_irqrestore(&state->card->lock, flags); +#ifdef DEBUG + printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count); +#endif + return put_user(val, (int *) arg); + case SOUND_PCM_READ_RATE: +#ifdef DEBUG + printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate); +#endif + return put_user(dmabuf->rate, (int *) arg); + case SOUND_PCM_READ_CHANNELS: +#ifdef DEBUG + printk("SOUND_PCM_READ_CHANNELS\n"); +#endif + return put_user(2, (int *) arg); + case SOUND_PCM_READ_BITS: +#ifdef DEBUG + printk("SOUND_PCM_READ_BITS\n"); +#endif + return put_user(AFMT_S16_LE, (int *) arg); + case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */ +#ifdef DEBUG + printk("SNDCTL_DSP_SETSPDIF\n"); +#endif + if (get_user(val, (int *) arg)) + return -EFAULT; + /* Check to make sure the codec supports S/PDIF transmitter */ + if ((state->card->ac97_features & 4)) { + /* mask out the transmitter speed bits so the user can't set them */ + val &= ~0x3000; + /* Add the current transmitter speed bits to the passed value */ + ret = ali_ac97_get(codec, AC97_SPDIF_CONTROL); + val |= (ret & 0x3000); + ali_ac97_set(codec, AC97_SPDIF_CONTROL, val); + if (ali_ac97_get(codec, AC97_SPDIF_CONTROL) != val) { + printk(KERN_ERR "ali_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val); + return -EFAULT; + } + } +#ifdef DEBUG + else + printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n"); +#endif + return put_user(val, (int *) arg); + case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */ +#ifdef DEBUG + printk("SNDCTL_DSP_GETSPDIF\n"); +#endif + if (get_user(val, (int *) arg)) + return -EFAULT; + /* Check to make sure the codec supports S/PDIF transmitter */ + if (!(state->card->ac97_features & 4)) { +#ifdef DEBUG + printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n"); +#endif + val = 0; + } else { + val = ali_ac97_get(codec, AC97_SPDIF_CONTROL); + } + + return put_user(val, (int *) arg); +//end add support spdif out +//add support 4,6 channel + case SNDCTL_DSP_GETCHANNELMASK: +#ifdef DEBUG + printk("SNDCTL_DSP_GETCHANNELMASK\n"); +#endif + if (get_user(val, (int *) arg)) + return -EFAULT; + /* Based on AC'97 DAC support, not ICH hardware */ + val = DSP_BIND_FRONT; + if (state->card->ac97_features & 0x0004) + val |= DSP_BIND_SPDIF; + if (state->card->ac97_features & 0x0080) + val |= DSP_BIND_SURR; + if (state->card->ac97_features & 0x0140) + val |= DSP_BIND_CENTER_LFE; + return put_user(val, (int *) arg); + case SNDCTL_DSP_BIND_CHANNEL: +#ifdef DEBUG + printk("SNDCTL_DSP_BIND_CHANNEL\n"); +#endif + if (get_user(val, (int *) arg)) + return -EFAULT; + if (val == DSP_BIND_QUERY) { + val = DSP_BIND_FRONT; /* Always report this as being enabled */ + if (state->card->ac97_status & SPDIF_ON) + val |= DSP_BIND_SPDIF; + else { + if (state->card->ac97_status & SURR_ON) + val |= DSP_BIND_SURR; + if (state->card-> + ac97_status & CENTER_LFE_ON) + val |= DSP_BIND_CENTER_LFE; + } + } else { /* Not a query, set it */ + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (dmabuf->enable == DAC_RUNNING) { + stop_dac(state); + } + if (val & DSP_BIND_SPDIF) { /* Turn on SPDIF */ + /* Ok, this should probably define what slots + * to use. For now, we'll only set it to the + * defaults: + * + * non multichannel codec maps to slots 3&4 + * 2 channel codec maps to slots 7&8 + * 4 channel codec maps to slots 6&9 + * 6 channel codec maps to slots 10&11 + * + * there should be some way for the app to + * select the slot assignment. + */ + i_scr = inl(state->card->iobase + ALI_SCR); + if (codec_independent_spdif_locked > 0) { + + if ((i_scr & 0x00300000) == 0x00100000) { + ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); + } else { + if ((i_scr & 0x00300000) == 0x00200000) { + ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked); + } else { + if ((i_scr & 0x00300000) == 0x00300000) { + ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked); + } + } + } + } else { /* codec spdif out (pcm out share ) */ + ali_set_spdif_output(state, AC97_EA_SPSA_3_4, dmabuf->rate); //I do not modify + } + + if (!(state->card->ac97_status & SPDIF_ON)) + val &= ~DSP_BIND_SPDIF; + } else { + int mask; + int channels; + /* Turn off S/PDIF if it was on */ + if (state->card->ac97_status & SPDIF_ON) + ali_set_spdif_output(state, -1, 0); + mask = + val & (DSP_BIND_FRONT | DSP_BIND_SURR | + DSP_BIND_CENTER_LFE); + switch (mask) { + case DSP_BIND_FRONT: + channels = 2; + break; + case DSP_BIND_FRONT | DSP_BIND_SURR: + channels = 4; + break; + case DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE: + channels = 6; + break; + default: + val = DSP_BIND_FRONT; + channels = 2; + break; + } + ali_set_dac_channels(state, channels); + /* check that they really got turned on */ + if (!state->card->ac97_status & SURR_ON) + val &= ~DSP_BIND_SURR; + if (!state->card-> + ac97_status & CENTER_LFE_ON) + val &= ~DSP_BIND_CENTER_LFE; + } + } + return put_user(val, (int *) arg); + case SNDCTL_DSP_MAPINBUF: + case SNDCTL_DSP_MAPOUTBUF: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_WRITE_FILTER: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + } + return -EINVAL; +} + +static int ali_open(struct inode *inode, struct file *file) +{ + int i = 0; + struct ali_card *card = devs; + struct ali_state *state = NULL; + struct dmabuf *dmabuf = NULL; + unsigned int i_scr; + + /* find an available virtual channel (instance of /dev/dsp) */ + + while (card != NULL) { + + /* + * If we are initializing and then fail, card could go + * away unuexpectedly while we are in the for() loop. + * So, check for card on each iteration before we check + * for card->initializing to avoid a possible oops. + * This usually only matters for times when the driver is + * autoloaded by kmod. + */ + for (i = 0; i < 50 && card && card->initializing; i++) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 20); + } + + for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) { + if (card->states[i] == NULL) { + state = card->states[i] = (struct ali_state *) kmalloc(sizeof(struct ali_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + memset(state, 0, sizeof(struct ali_state)); + dmabuf = &state->dmabuf; + goto found_virt; + } + } + card = card->next; + } + + /* no more virtual channel avaiable */ + if (!state) + return -ENODEV; +found_virt: + /* initialize the virtual channel */ + + state->virt = i; + state->card = card; + state->magic = ALI5455_STATE_MAGIC; + init_waitqueue_head(&dmabuf->wait); + init_MUTEX(&state->open_sem); + file->private_data = state; + dmabuf->trigger = 0; + /* allocate hardware channels */ + if (file->f_mode & FMODE_READ) { + if ((dmabuf->read_channel = + card->alloc_rec_pcm_channel(card)) == NULL) { + kfree(card->states[i]); + card->states[i] = NULL; + return -EBUSY; + } + dmabuf->trigger |= PCM_ENABLE_INPUT; + ali_set_adc_rate(state, 8000); + } + if (file->f_mode & FMODE_WRITE) { + if (codec_independent_spdif_locked > 0) { + if ((dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card)) == NULL) { + kfree(card->states[i]); + card->states[i] = NULL; + return -EBUSY; + } + dmabuf->trigger |= SPDIF_ENABLE_OUTPUT; + ali_set_codecspdifout_rate(state, codec_independent_spdif_locked); //It must add + i_scr = inl(state->card->iobase + ALI_SCR); + if ((i_scr & 0x00300000) == 0x00100000) { + ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); + } else { + if ((i_scr & 0x00300000) == 0x00200000) { + ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked); + } else { + if ((i_scr & 0x00300000) == 0x00300000) { + ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked); + } else { + ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked); + } + } + + } + } else { + if (controller_independent_spdif_locked > 0) { + if ((dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card)) == NULL) { + kfree(card->states[i]); + card->states[i] = NULL; + return -EBUSY; + } + dmabuf->trigger |= SPDIF_ENABLE_OUTPUT; + ali_set_spdifout_rate(state, controller_independent_spdif_locked); + } else { + if ((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) { + kfree(card->states[i]); + card->states[i] = NULL; + return -EBUSY; + } + /* Initialize to 8kHz? What if we don't support 8kHz? */ + /* Let's change this to check for S/PDIF stuff */ + + dmabuf->trigger |= PCM_ENABLE_OUTPUT; + if (codec_pcmout_share_spdif_locked) { + ali_set_dac_rate(state, codec_pcmout_share_spdif_locked); + ali_set_spdif_output(state, AC97_EA_SPSA_3_4, codec_pcmout_share_spdif_locked); + } else { + ali_set_dac_rate(state, 8000); + } + } + + } + } + + /* set default sample format. According to OSS Programmer's Guide /dev/dsp + should be default to unsigned 8-bits, mono, with sample rate 8kHz and + /dev/dspW will accept 16-bits sample, but we don't support those so we + set it immediately to stereo and 16bit, which is all we do support */ + dmabuf->fmt |= ALI5455_FMT_16BIT | ALI5455_FMT_STEREO; + dmabuf->ossfragsize = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; + state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + outl(0x00000000, card->iobase + ALI_INTERRUPTCR); + outl(0x00000000, card->iobase + ALI_INTERRUPTSR); + return 0; +} + +static int ali_release(struct inode *inode, struct file *file) +{ + struct ali_state *state = (struct ali_state *) file->private_data; + struct ali_card *card = state->card; + struct dmabuf *dmabuf = &state->dmabuf; + unsigned long flags; + lock_kernel(); + + /* stop DMA state machine and free DMA buffers/channels */ + if (dmabuf->trigger & PCM_ENABLE_OUTPUT) + drain_dac(state, 0); + + if (dmabuf->trigger & SPDIF_ENABLE_OUTPUT) + drain_spdifout(state, 0); + + if (dmabuf->trigger & PCM_ENABLE_INPUT) + stop_adc(state); + + spin_lock_irqsave(&card->lock, flags); + dealloc_dmabuf(state); + if (file->f_mode & FMODE_WRITE) { + if (codec_independent_spdif_locked > 0) { + state->card->free_pcm_channel(state->card, dmabuf->codec_spdifout_channel->num); + } else { + if (controller_independent_spdif_locked > 0) + state->card->free_pcm_channel(state->card, + dmabuf->controller_spdifout_channel->num); + else state->card->free_pcm_channel(state->card, + dmabuf->write_channel->num); + } + } + if (file->f_mode & FMODE_READ) + state->card->free_pcm_channel(state->card, dmabuf->read_channel->num); + + state->card->states[state->virt] = NULL; + kfree(state); + spin_unlock_irqrestore(&card->lock, flags); + unlock_kernel(); + return 0; +} + +static /*const */ struct file_operations ali_audio_fops = { + owner:THIS_MODULE, + llseek:no_llseek, + read:ali_read, + write:ali_write, + poll:ali_poll, + ioctl:ali_ioctl, + mmap:ali_mmap, + open:ali_open, + release:ali_release, +}; + +/* Read AC97 codec registers */ +static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg) +{ + struct ali_card *card = dev->private_data; + int count1 = 100; + char val; + unsigned short int data, count, addr1, addr2; + + while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000)) + udelay(1); + + addr1 = reg; + reg |= 0x0080; + for (count = 0; count < 0x7f; count++) { + val = inb(card->iobase + ALI_CSPSR); + if (val & 0x08) + break; + } + if (count == 0x7f) + return -1; + outw(reg, (card->iobase + ALI_CPR) + 2); + for (count = 0; count < 0x7f; count++) { + val = inb(card->iobase + ALI_CSPSR); + if (val & 0x02) { + data = inw(card->iobase + ALI_SPR); + addr2 = inw((card->iobase + ALI_SPR) + 2); + break; + } + } + if (count == 0x7f) + return -1; + if (addr2 != addr1) + return -1; + return ((u16) data); +} + +/* write ac97 codec register */ + +static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data) +{ + struct ali_card *card = dev->private_data; + int count1 = 100; + unsigned long flags; + char val; + unsigned short int count; + + while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000)) + udelay(1); + + for (count = 0; count < 0x7f; count++) { + val = inb(card->iobase + ALI_CSPSR); + if (val & 0x08) + break; + } + if (count == 0x7f) { + printk(KERN_WARNING "ali_ac96_set: AC97 codec register access timed out. \n"); + return; + } + outw(data, (card->iobase + ALI_CPR)); + outb(reg, (card->iobase + ALI_CPR) + 2); + for (count = 0; count < 0x7f; count++) { + val = inb(card->iobase + ALI_CSPSR); + if (val & 0x01) + break; + } + if (count == 0x7f) { + printk(KERN_WARNING "ali_ac96_set: AC97 codec register access timed out. \n"); + return; + } + return; +} + +/* OSS /dev/mixer file operation methods */ + +static int ali_open_mixdev(struct inode *inode, struct file *file) +{ + int i; + int minor = MINOR(inode->i_rdev); + struct ali_card *card = devs; + for (card = devs; card != NULL; card = card->next) { + /* + * If we are initializing and then fail, card could go + * away unuexpectedly while we are in the for() loop. + * So, check for card on each iteration before we check + * for card->initializing to avoid a possible oops. + * This usually only matters for times when the driver is + * autoloaded by kmod. + */ + for (i = 0; i < 50 && card && card->initializing; i++) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 20); + } + for (i = 0; i < NR_AC97 && card && !card->initializing; i++) + if (card->ac97_codec[i] != NULL + && card->ac97_codec[i]->dev_mixer == minor) { + file->private_data = card->ac97_codec[i]; + return 0; + } + } + return -ENODEV; +} + +static int ali_ioctl_mixdev(struct inode *inode, + struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct ac97_codec *codec = (struct ac97_codec *) file->private_data; + return codec->mixer_ioctl(codec, cmd, arg); +} + +static /*const */ struct file_operations ali_mixer_fops = { + owner:THIS_MODULE, + llseek:no_llseek, + ioctl:ali_ioctl_mixdev, + open:ali_open_mixdev, +}; + +/* AC97 codec initialisation. These small functions exist so we don't + duplicate code between module init and apm resume */ + +static inline int ali_ac97_exists(struct ali_card *card, int ac97_number) +{ + unsigned int i = 1; + u32 reg = inl(card->iobase + ALI_RTSR); + if (ac97_number) { + while (i < 100) { + + reg = inl(card->iobase + ALI_RTSR); + if (reg & 0x40) { + break; + } else { + outl(reg | 0x00000040, + card->iobase + 0x34); + udelay(1); + } + i++; + } + + } else { + while (i < 100) { + reg = inl(card->iobase + ALI_RTSR); + if (reg & 0x80) { + break; + } else { + outl(reg | 0x00000080, + card->iobase + 0x34); + udelay(1); + } + i++; + } + } + + if (ac97_number) + return reg & 0x40; + else + return reg & 0x80; +} + +static inline int ali_ac97_enable_variable_rate(struct ac97_codec *codec) +{ + ali_ac97_set(codec, AC97_EXTENDED_STATUS, 9); + ali_ac97_set(codec, AC97_EXTENDED_STATUS, ali_ac97_get(codec, AC97_EXTENDED_STATUS) | 0xE800); + return (ali_ac97_get(codec, AC97_EXTENDED_STATUS) & 1); +} + + +static int ali_ac97_probe_and_powerup(struct ali_card *card, struct ac97_codec *codec) +{ + /* Returns 0 on failure */ + int i; + u16 addr; + if (ac97_probe_codec(codec) == 0) + return 0; + /* ac97_probe_codec is success ,then begin to init codec */ + ali_ac97_set(codec, AC97_RESET, 0xffff); + if (card->channel[0].used == 1) { + ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000); + ali_ac97_set(codec, AC97_LINEIN_VOL, 0x0808); + ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F); + } + + if (card->channel[2].used == 1) //if MICin then init codec + { + ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000); + ali_ac97_set(codec, AC97_MIC_VOL, 0x8808); + ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F); + ali_ac97_set(codec, AC97_RECORD_GAIN_MIC, 0x0000); + } + + ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, 0x0000); + ali_ac97_set(codec, AC97_HEADPHONE_VOL, 0x0000); + ali_ac97_set(codec, AC97_PCMOUT_VOL, 0x0000); + ali_ac97_set(codec, AC97_CD_VOL, 0x0808); + ali_ac97_set(codec, AC97_VIDEO_VOL, 0x0808); + ali_ac97_set(codec, AC97_AUX_VOL, 0x0808); + ali_ac97_set(codec, AC97_PHONE_VOL, 0x8048); + ali_ac97_set(codec, AC97_PCBEEP_VOL, 0x0000); + ali_ac97_set(codec, AC97_GENERAL_PURPOSE, AC97_GP_MIX); + ali_ac97_set(codec, AC97_MASTER_VOL_MONO, 0x0000); + ali_ac97_set(codec, 0x38, 0x0000); + addr = ali_ac97_get(codec, 0x2a); + ali_ac97_set(codec, 0x2a, addr | 0x0001); + addr = ali_ac97_get(codec, 0x2a); + addr = ali_ac97_get(codec, 0x28); + ali_ac97_set(codec, 0x2c, 0xbb80); + addr = ali_ac97_get(codec, 0x2c); + /* power it all up */ + ali_ac97_set(codec, AC97_POWER_CONTROL, + ali_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); + /* wait for analog ready */ + for (i = 10; i && ((ali_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 20); + } + /* FIXME !! */ + i++; + return i; +} + + +/* I clone ali5455(2.4.7 ) not clone i810_audio(2.4.18) */ + +static int ali_reset_5455(struct ali_card *card) +{ + outl(0x80000003, card->iobase + ALI_SCR); + outl(0x83838383, card->iobase + ALI_FIFOCR1); + outl(0x83838383, card->iobase + ALI_FIFOCR2); + if (controller_pcmout_share_spdif_locked > 0) { + outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001), + card->iobase + ALI_SPDIFICS); + outl(0x0408000a, card->iobase + ALI_INTERFACECR); + } else { + if (codec_independent_spdif_locked > 0) { + outl((inl(card->iobase + ALI_SCR) | 0x00100000), card->iobase + ALI_SCR); // now I select slot 7 & 8 + outl(0x00200000, card->iobase + ALI_INTERFACECR); //enable codec independent spdifout + } else + outl(0x04080002, card->iobase + ALI_INTERFACECR); + } + + outl(0x00000000, card->iobase + ALI_INTERRUPTCR); + outl(0x00000000, card->iobase + ALI_INTERRUPTSR); + if (controller_independent_spdif_locked > 0) + outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001), + card->iobase + ALI_SPDIFICS); + return 1; +} + + +static int ali_ac97_random_init_stuff(struct ali_card + *card) +{ + u32 reg = inl(card->iobase + ALI_SCR); + int i = 0; + reg = inl(card->iobase + ALI_SCR); + if ((reg & 2) == 0) /* Cold required */ + reg |= 2; + else + reg |= 1; /* Warm */ + reg &= ~0x80000000; /* ACLink on */ + outl(reg, card->iobase + ALI_SCR); + + while (i < 10) { + if ((inl(card->iobase + 0x18) & (1 << 1)) == 0) + break; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ / 20); + i++; + } + if (i == 10) { + printk(KERN_ERR "ali_audio: AC'97 reset failed.\n"); + return 0; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 2); + return 1; +} + +/* AC97 codec initialisation. */ + +static int __init ali_ac97_init(struct ali_card *card) +{ + int num_ac97 = 0; + int total_channels = 0; + struct ac97_codec *codec; + u16 eid; + + if (!ali_ac97_random_init_stuff(card)) + return 0; + + /* Number of channels supported */ + /* What about the codec? Just because the ICH supports */ + /* multiple channels doesn't mean the codec does. */ + /* we'll have to modify this in the codec section below */ + /* to reflect what the codec has. */ + /* ICH and ICH0 only support 2 channels so don't bother */ + /* to check.... */ + inl(card->iobase + ALI_CPR); + card->channels = 2; + + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + + /* Assume codec isn't available until we go through the + * gauntlet below */ + card->ac97_codec[num_ac97] = NULL; + /* The ICH programmer's reference says you should */ + /* check the ready status before probing. So we chk */ + /* What do we do if it's not ready? Wait and try */ + /* again, or abort? */ + if (!ali_ac97_exists(card, num_ac97)) { + if (num_ac97 == 0) + printk(KERN_ERR "ali_audio: Primary codec not ready.\n"); + break; + } + + if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(codec, 0, sizeof(struct ac97_codec)); + /* initialize some basic codec information, other fields will be filled + in ac97_probe_codec */ + codec->private_data = card; + codec->id = num_ac97; + codec->codec_read = ali_ac97_get; + codec->codec_write = ali_ac97_set; + if (!ali_ac97_probe_and_powerup(card, codec)) { + printk(KERN_ERR "ali_audio: timed out waiting for codec %d analog ready", + num_ac97); + kfree(codec); + break; /* it didn't work */ + } + + /* Store state information about S/PDIF transmitter */ + card->ac97_status = 0; + /* Don't attempt to get eid until powerup is complete */ + eid = ali_ac97_get(codec, AC97_EXTENDED_ID); + if (eid == 0xFFFFFF) { + printk(KERN_ERR "ali_audio: no codec attached ?\n"); + kfree(codec); + break; + } + + card->ac97_features = eid; + /* Now check the codec for useful features to make up for + the dumbness of the ali5455 hardware engine */ + if (!(eid & 0x0001)) + printk(KERN_WARNING + "ali_audio: only 48Khz playback available.\n"); + else { + if (!ali_ac97_enable_variable_rate(codec)) { + printk(KERN_WARNING + "ali_audio: Codec refused to allow VRA, using 48Khz only.\n"); + card->ac97_features &= ~1; + } + } + + /* Determine how many channels the codec(s) support */ + /* - The primary codec always supports 2 */ + /* - If the codec supports AMAP, surround DACs will */ + /* automaticlly get assigned to slots. */ + /* * Check for surround DACs and increment if */ + /* found. */ + /* - Else check if the codec is revision 2.2 */ + /* * If surround DACs exist, assign them to slots */ + /* and increment channel count. */ + + /* All of this only applies to ICH2 and above. ICH */ + /* and ICH0 only support 2 channels. ICH2 will only */ + /* support multiple codecs in a "split audio" config. */ + /* as described above. */ + + /* TODO: Remove all the debugging messages! */ + + if ((eid & 0xc000) == 0) /* primary codec */ + total_channels += 2; + if ((codec->dev_mixer = register_sound_mixer(&ali_mixer_fops, -1)) < 0) { + printk(KERN_ERR "ali_audio: couldn't register mixer!\n"); + kfree(codec); + break; + } + card->ac97_codec[num_ac97] = codec; + } + /* pick the minimum of channels supported by ICHx or codec(s) */ + card->channels = (card->channels > total_channels) ? total_channels : card->channels; + return num_ac97; +} + +static void __init ali_configure_clocking(void) +{ + struct ali_card *card; + struct ali_state *state; + struct dmabuf *dmabuf; + unsigned int i, offset, new_offset; + unsigned long flags; + card = devs; + + /* We could try to set the clocking for multiple cards, but can you even have + * more than one ali in a machine? Besides, clocking is global, so unless + * someone actually thinks more than one ali in a machine is possible and + * decides to rewrite that little bit, setting the rate for more than one card + * is a waste of time. + */ + if (card != NULL) { + state = card->states[0] = (struct ali_state *) + kmalloc(sizeof(struct ali_state), GFP_KERNEL); + if (state == NULL) + return; + memset(state, 0, sizeof(struct ali_state)); + dmabuf = &state->dmabuf; + dmabuf->write_channel = card->alloc_pcm_channel(card); + state->virt = 0; + state->card = card; + state->magic = ALI5455_STATE_MAGIC; + init_waitqueue_head(&dmabuf->wait); + init_MUTEX(&state->open_sem); + dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT; + dmabuf->trigger = PCM_ENABLE_OUTPUT; + ali_set_dac_rate(state, 48000); + if (prog_dmabuf(state, 0) != 0) + goto config_out_nodmabuf; + + if (dmabuf->dmasize < 16384) + goto config_out; + + dmabuf->count = dmabuf->dmasize; + outb(31, card->iobase + dmabuf->write_channel->port + OFF_LVI); + + save_flags(flags); + cli(); + start_dac(state); + offset = ali_get_dma_addr(state, 0); + mdelay(50); + new_offset = ali_get_dma_addr(state, 0); + stop_dac(state); + + outb(2, card->iobase + dmabuf->write_channel->port + OFF_CR); + restore_flags(flags); + + i = new_offset - offset; + + if (i == 0) + goto config_out; + i = i / 4 * 20; + if (i > 48500 || i < 47500) { + clocking = clocking * clocking / i; + } +config_out: + dealloc_dmabuf(state); +config_out_nodmabuf: + state->card->free_pcm_channel(state->card, state->dmabuf. write_channel->num); + kfree(state); + card->states[0] = NULL; + } +} + +/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered + until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ + +static int __init ali_probe(struct pci_dev *pci_dev, const struct pci_device_id + *pci_id) +{ + struct ali_card *card; + if (pci_enable_device(pci_dev)) + return -EIO; + if (pci_set_dma_mask(pci_dev, ALI5455_DMA_MASK)) { + printk(KERN_ERR "ali5455: architecture does not support" + " 32bit PCI busmaster DMA\n"); + return -ENODEV; + } + + if ((card = kmalloc(sizeof(struct ali_card), GFP_KERNEL)) == NULL) { + printk(KERN_ERR "ali_audio: out of memory\n"); + return -ENOMEM; + } + memset(card, 0, sizeof(*card)); + card->initializing = 1; + card->iobase = pci_resource_start(pci_dev, 0); + card->pci_dev = pci_dev; + card->pci_id = pci_id->device; + card->irq = pci_dev->irq; + card->next = devs; + card->magic = ALI5455_CARD_MAGIC; +#ifdef CONFIG_PM + card->pm_suspended = 0; +#endif + spin_lock_init(&card->lock); + devs = card; + pci_set_master(pci_dev); + printk(KERN_INFO "ali: %s found at IO 0x%04lx, IRQ %d\n", + card_names[pci_id->driver_data], card->iobase, card->irq); + card->alloc_pcm_channel = ali_alloc_pcm_channel; + card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel; + card->alloc_rec_mic_channel = ali_alloc_rec_mic_channel; + card->alloc_codec_spdifout_channel = ali_alloc_codec_spdifout_channel; + card->alloc_controller_spdifout_channel = ali_alloc_controller_spdifout_channel; + card->free_pcm_channel = ali_free_pcm_channel; + card->channel[0].offset = 0; + card->channel[0].port = 0x40; + card->channel[0].num = 0; + card->channel[1].offset = 0; + card->channel[1].port = 0x50; + card->channel[1].num = 1; + card->channel[2].offset = 0; + card->channel[2].port = 0x60; + card->channel[2].num = 2; + card->channel[3].offset = 0; + card->channel[3].port = 0x70; + card->channel[3].num = 3; + card->channel[4].offset = 0; + card->channel[4].port = 0xb0; + card->channel[4].num = 4; + /* claim our iospace and irq */ + request_region(card->iobase, 256, card_names[pci_id->driver_data]); + if (request_irq(card->irq, &ali_interrupt, SA_SHIRQ, + card_names[pci_id->driver_data], card)) { + printk(KERN_ERR "ali_audio: unable to allocate irq %d\n", + card->irq); + release_region(card->iobase, 256); + kfree(card); + return -ENODEV; + } + + if (ali_reset_5455(card) <= 0) { + unregister_sound_dsp(card->dev_audio); + release_region(card->iobase, 256); + free_irq(card->irq, card); + kfree(card); + return -ENODEV; + } + + /* initialize AC97 codec and register /dev/mixer */ + if (ali_ac97_init(card) < 0) { + release_region(card->iobase, 256); + free_irq(card->irq, card); + kfree(card); + return -ENODEV; + } + + pci_set_drvdata(pci_dev, card); + + if (clocking == 0) { + clocking = 48000; + ali_configure_clocking(); + } + + /* register /dev/dsp */ + if ((card->dev_audio = register_sound_dsp(&ali_audio_fops, -1)) < 0) { + int i; + printk(KERN_ERR"ali_audio: couldn't register DSP device!\n"); + release_region(card->iobase, 256); + free_irq(card->irq, card); + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL) { + unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); + kfree(card->ac97_codec[i]); + } + kfree(card); + return -ENODEV; + } + card->initializing = 0; + return 0; +} + +static void __devexit ali_remove(struct pci_dev *pci_dev) +{ + int i; + struct ali_card *card = pci_get_drvdata(pci_dev); + /* free hardware resources */ + free_irq(card->irq, devs); + release_region(card->iobase, 256); + /* unregister audio devices */ + for (i = 0; i < NR_AC97; i++) + if (card->ac97_codec[i] != NULL) { + unregister_sound_mixer(card->ac97_codec[i]-> + dev_mixer); + kfree(card->ac97_codec[i]); + card->ac97_codec[i] = NULL; + } + unregister_sound_dsp(card->dev_audio); + kfree(card); +} + +#ifdef CONFIG_PM +static int ali_pm_suspend(struct pci_dev *dev, u32 pm_state) +{ + struct ali_card *card = pci_get_drvdata(dev); + struct ali_state *state; + unsigned long flags; + struct dmabuf *dmabuf; + int i, num_ac97; + + if (!card) + return 0; + spin_lock_irqsave(&card->lock, flags); + card->pm_suspended = 1; + for (i = 0; i < NR_HW_CH; i++) { + state = card->states[i]; + if (!state) + continue; + /* this happens only if there are open files */ + dmabuf = &state->dmabuf; + if (dmabuf->enable & DAC_RUNNING || + (dmabuf->count + && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) { + state->pm_saved_dac_rate = dmabuf->rate; + stop_dac(state); + } else { + state->pm_saved_dac_rate = 0; + } + if (dmabuf->enable & ADC_RUNNING) { + state->pm_saved_adc_rate = dmabuf->rate; + stop_adc(state); + } else { + state->pm_saved_adc_rate = 0; + } + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; + } + + spin_unlock_irqrestore(&card->lock, flags); + /* save mixer settings */ + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + struct ac97_codec *codec = card->ac97_codec[num_ac97]; + if (!codec) + continue; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if ((supported_mixer(codec, i)) && (codec->read_mixer)) { + card->pm_saved_mixer_settings[i][num_ac97] = codec->read_mixer(codec, i); + } + } + } + pci_save_state(dev, card->pm_save_state); /* XXX do we need this? */ + pci_disable_device(dev); /* disable busmastering */ + pci_set_power_state(dev, 3); /* Zzz. */ + return 0; +} + + +static int ali_pm_resume(struct pci_dev *dev) +{ + int num_ac97, i = 0; + struct ali_card *card = pci_get_drvdata(dev); + pci_enable_device(dev); + pci_restore_state(dev, card->pm_save_state); + /* observation of a toshiba portege 3440ct suggests that the + hardware has to be more or less completely reinitialized from + scratch after an apm suspend. Works For Me. -dan */ + ali_ac97_random_init_stuff(card); + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + struct ac97_codec *codec = card->ac97_codec[num_ac97]; + /* check they haven't stolen the hardware while we were + away */ + if (!codec || !ali_ac97_exists(card, num_ac97)) { + if (num_ac97) + continue; + else + BUG(); + } + if (!ali_ac97_probe_and_powerup(card, codec)) + BUG(); + if ((card->ac97_features & 0x0001)) { + /* at probe time we found we could do variable + rates, but APM suspend has made it forget + its magical powers */ + if (!ali_ac97_enable_variable_rate(codec)) + BUG(); + } + /* we lost our mixer settings, so restore them */ + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (supported_mixer(codec, i)) { + int val = card->pm_saved_mixer_settings[i][num_ac97]; + codec->mixer_state[i] = val; + codec->write_mixer(codec, i, + (val & 0xff), + ((val >> 8) & 0xff)); + } + } + } + + /* we need to restore the sample rate from whatever it was */ + for (i = 0; i < NR_HW_CH; i++) { + struct ali_state *state = card->states[i]; + if (state) { + if (state->pm_saved_adc_rate) + ali_set_adc_rate(state, state->pm_saved_adc_rate); + if (state->pm_saved_dac_rate) + ali_set_dac_rate(state, state->pm_saved_dac_rate); + } + } + + card->pm_suspended = 0; + /* any processes that were reading/writing during the suspend + probably ended up here */ + for (i = 0; i < NR_HW_CH; i++) { + struct ali_state *state = card->states[i]; + if (state) + wake_up(&state->dmabuf.wait); + } + return 0; +} +#endif /* CONFIG_PM */ + +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("ALI 5455 audio support"); +MODULE_LICENSE("GPL"); +MODULE_PARM(clocking, "i"); +MODULE_PARM(strict_clocking, "i"); +MODULE_PARM(codec_pcmout_share_spdif_locked, "i"); +MODULE_PARM(codec_independent_spdif_locked, "i"); +MODULE_PARM(controller_pcmout_share_spdif_locked, "i"); +MODULE_PARM(controller_independent_spdif_locked, "i"); +#define ALI5455_MODULE_NAME "ali5455" +static struct pci_driver ali_pci_driver = { + name:ALI5455_MODULE_NAME, id_table:ali_pci_tbl, probe:ali_probe, + remove:__devexit_p(ali_remove), +#ifdef CONFIG_PM + suspend:ali_pm_suspend, resume:ali_pm_resume, +#endif /* CONFIG_PM */ +}; + +static int __init ali_init_module(void) +{ + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + printk(KERN_INFO "ALI 5455 + AC97 Audio, version " + DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + + if (codec_independent_spdif_locked > 0) { + if (codec_independent_spdif_locked == 32000 + || codec_independent_spdif_locked == 44100 + || codec_independent_spdif_locked == 48000) { + printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_independent_spdif_locked); + } else { + printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); + codec_independent_spdif_locked = 0; + } + } + if (controller_independent_spdif_locked > 0) { + if (controller_independent_spdif_locked == 32000 + || controller_independent_spdif_locked == 44100 + || controller_independent_spdif_locked == 48000) { + printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", controller_independent_spdif_locked); + } else { + printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); + controller_independent_spdif_locked = 0; + } + } + + if (codec_pcmout_share_spdif_locked > 0) { + if (codec_pcmout_share_spdif_locked == 32000 + || codec_pcmout_share_spdif_locked == 44100 + || codec_pcmout_share_spdif_locked == 48000) { + printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_pcmout_share_spdif_locked); + } else { + printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); + codec_pcmout_share_spdif_locked = 0; + } + } + if (controller_pcmout_share_spdif_locked > 0) { + if (controller_pcmout_share_spdif_locked == 32000 + || controller_pcmout_share_spdif_locked == 44100 + || controller_pcmout_share_spdif_locked == 48000) { + printk(KERN_INFO "ali_audio: Enabling controller S/PDIF at sample rate %dHz.\n", controller_pcmout_share_spdif_locked); + } else { + printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); + controller_pcmout_share_spdif_locked = 0; + } + } + if (!pci_register_driver(&ali_pci_driver)) { + pci_unregister_driver(&ali_pci_driver); + return -ENODEV; + } + return 0; +} + +static void __exit ali_cleanup_module(void) +{ + pci_unregister_driver(&ali_pci_driver); +} + +module_init(ali_init_module); +module_exit(ali_cleanup_module); +/* +Local Variables: +c-basic-offset: 8 +End: +*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/sound/Config.in linux.20pre2-ac1/drivers/sound/Config.in --- linux.20pre2/drivers/sound/Config.in 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/sound/Config.in 2002-08-13 15:21:11.000000000 +0100 @@ -6,6 +6,7 @@ # Prompt user for primary drivers. +dep_tristate ' ALi5455 audio support' CONFIG_SOUND_ALI5455 $CONFIG_SOUND $CONFIG_PCI dep_tristate ' BT878 audio dma' CONFIG_SOUND_BT878 $CONFIG_SOUND $CONFIG_PCI dep_tristate ' C-Media PCI (CMI8338/8738)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then @@ -42,7 +43,10 @@ dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND $CONFIG_PCI dep_tristate ' ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND $CONFIG_PCI dep_tristate ' ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL -dep_tristate ' Intel ICH (i8xx), SiS 7012, NVidia nForce Audio or AMD 768' CONFIG_SOUND_ICH $CONFIG_PCI +dep_tristate ' Intel ICH (i8xx), SiS 7012, NVidia nForce Audio or AMD 768/811x' CONFIG_SOUND_ICH $CONFIG_PCI +if [ "$CONFIG_GSC_LASI" = "y" ]; then + dep_tristate ' PA Harmony audio driver' CONFIG_SOUND_HARMONY $CONFIG_SOUND +fi if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then dep_tristate ' IT8172G Sound' CONFIG_SOUND_IT8172 $CONFIG_SOUND fi @@ -207,7 +211,7 @@ bool ' Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401 fi fi - + if [ "$CONFIG_ARM" = "y" ]; then if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/sound/i810_audio.c linux.20pre2-ac1/drivers/sound/i810_audio.c --- linux.20pre2/drivers/sound/i810_audio.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/sound/i810_audio.c 2002-08-12 10:38:59.000000000 +0100 @@ -121,11 +121,13 @@ static int strict_clocking=0; static unsigned int clocking=0; static int spdif_locked=0; +static int d845gbv_bug=0; //#define DEBUG //#define DEBUG2 //#define DEBUG_INTERRUPTS //#define DEBUG_MMAP +//#define DEBUG_MMIO #define ADC_RUNNING 1 #define DAC_RUNNING 2 @@ -168,6 +170,9 @@ * each dma engine has controlling registers. These goofy * names are from the datasheet, but make it easy to write * code while leafing through it. + * + * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2, + * mic in 2, s/pdif. */ #define ENUM_ENGINE(PRE,DIG) \ @@ -192,6 +197,14 @@ CAS = 0x34 /* Codec Write Semaphore Register */ }; +ENUM_ENGINE(MC2,4); /* Mic. 2 */ +ENUM_ENGINE(PI2,5); /* PCM In 2 */ +ENUM_ENGINE(SP,6); /* S/PDIF */ + +enum { + SDM = 0x80 /* SDATA_IN Map Register */ +}; + /* interrupts for a dma engine */ #define DMA_INT_FIFO (1<<4) /* fifo under/over flow */ #define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */ @@ -212,7 +225,7 @@ #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI) -#define DRIVER_VERSION "0.21" +#define DRIVER_VERSION "0.22" /* magic numbers to protect our data structures */ #define I810_CARD_MAGIC 0x5072696E /* "Prin" */ @@ -221,7 +234,7 @@ #define NR_HW_CH 3 /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ -#define NR_AC97 2 +#define NR_AC97 4 /* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */ /* stream at a minimum for this card to be happy */ @@ -353,7 +366,6 @@ struct i810_card { - struct i810_channel channel[3]; unsigned int magic; /* We keep i810 cards in a linked list */ @@ -377,15 +389,24 @@ /* structures for abstraction of hardware facilities, codecs, banks and channels*/ struct ac97_codec *ac97_codec[NR_AC97]; struct i810_state *states[NR_HW_CH]; + struct i810_channel *channel; /* 1:1 to states[] but diff. lifetime */ + dma_addr_t chandma; u16 ac97_features; u16 ac97_status; u16 channels; /* hardware resources */ - unsigned long iobase; unsigned long ac97base; + unsigned long iobase; u32 irq; + + unsigned long ac97base_mmio_phys; + unsigned long iobase_mmio_phys; + u_int8_t *ac97base_mmio; + u_int8_t *iobase_mmio; + + int use_mmio; /* Function support */ struct i810_channel *(*alloc_pcm_channel)(struct i810_card *); @@ -405,6 +426,10 @@ unsigned int cmd, unsigned long arg); static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg); static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data); +static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg); +static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data); +static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg); +static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data); static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card) { @@ -731,6 +756,8 @@ outb(0, card->iobase + PI_CR); // wait for the card to acknowledge shutdown while( inb(card->iobase + PI_CR) != 0 ) ; + // reset the dma engine now + outb(0x02, card->iobase + PI_CR); // now clear any latent interrupt bits (like the halt bit) if(card->pci_id == PCI_DEVICE_ID_SI_7012) outb( inb(card->iobase + PI_PICB), card->iobase + PI_PICB ); @@ -756,7 +783,8 @@ if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) { dmabuf->enable |= ADC_RUNNING; - outb((1<<4) | (1<<2) | 1, state->card->iobase + PI_CR); + // Interrupt enable, LVI enable, DMA enable + outb(0x10 | 0x04 | 0x01, state->card->iobase + PI_CR); } } @@ -780,6 +808,8 @@ outb(0, card->iobase + PO_CR); // wait for the card to acknowledge shutdown while( inb(card->iobase + PO_CR) != 0 ) ; + // reset the dma engine now + outb(0x02, card->iobase + PO_CR); // now clear any latent interrupt bits (like the halt bit) if(card->pci_id == PCI_DEVICE_ID_SI_7012) outb( inb(card->iobase + PO_PICB), card->iobase + PO_PICB ); @@ -805,7 +835,8 @@ if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { dmabuf->enable |= DAC_RUNNING; - outb((1<<4) | (1<<2) | 1, state->card->iobase + PO_CR); + // Interrupt enable, LVI enable, DMA enable + outb(0x10 | 0x04 | 0x01, state->card->iobase + PO_CR); } } static void start_dac(struct i810_state *state) @@ -957,7 +988,7 @@ for(i=0;inumfrag;i++) { - sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i); + sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i; // the card will always be doing 16bit stereo sg->control=dmabuf->fragsamples; if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) @@ -972,7 +1003,9 @@ } spin_lock_irqsave(&state->card->lock, flags); outb(2, state->card->iobase+c->port+OFF_CR); /* reset DMA machine */ - outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR); + outl((u32)state->card->chandma + + c->num*sizeof(struct i810_channel), + state->card->iobase+c->port+OFF_BDBAR); outb(0, state->card->iobase+c->port+OFF_CIV); outb(0, state->card->iobase+c->port+OFF_LVI); @@ -1294,7 +1327,6 @@ if (dmabuf->enable & ADC_RUNNING) __stop_adc(state); dmabuf->enable = 0; - wake_up(&dmabuf->wait); #ifdef DEBUG_INTERRUPTS printk(" STOP "); #endif @@ -1740,7 +1772,9 @@ } if (c != NULL) { outb(2, state->card->iobase+c->port+OFF_CR); /* reset DMA machine */ - outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR); + outl((u32)state->card->chandma + + c->num*sizeof(struct i810_channel), + state->card->iobase+c->port+OFF_BDBAR); outb(0, state->card->iobase+c->port+OFF_CIV); outb(0, state->card->iobase+c->port+OFF_LVI); } @@ -1883,12 +1917,14 @@ switch ( val ) { case 2: /* 2 channels is always supported */ - outl(state->card->iobase + GLOB_CNT, (i_glob_cnt & 0xcfffff)); + outl(i_glob_cnt & 0xcfffff, + state->card->iobase + GLOB_CNT); /* Do we need to change mixer settings???? */ break; case 4: /* Supported on some chipsets, better check first */ if ( state->card->channels >= 4 ) { - outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0100000)); + outl((i_glob_cnt & 0xcfffff) | 0x100000, + state->card->iobase + GLOB_CNT); /* Do we need to change mixer settings??? */ } else { val = ret; @@ -1896,7 +1932,8 @@ break; case 6: /* Supported on some chipsets, better check first */ if ( state->card->channels >= 6 ) { - outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0200000)); + outl((i_glob_cnt & 0xcfffff) | 0x200000, + state->card->iobase + GLOB_CNT); /* Do we need to change mixer settings??? */ } else { val = ret; @@ -2414,6 +2451,9 @@ i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked); } else { i810_set_dac_rate(state, 8000); + /* Put the ACLink in 2 channel mode by default */ + i = inl(card->iobase + GLOB_CNT); + outl(i & 0xffcfffff, card->iobase + GLOB_CNT); } } @@ -2478,27 +2518,88 @@ /* Write AC97 codec registers */ -static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg) +static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg) { struct i810_card *card = dev->private_data; int count = 100; - u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f)); + u16 reg_set = ((u16) reg) & 0x7f; + reg_set |= ((u16) dev->id) << 7; + + while(count-- && (readb(card->iobase_mmio + CAS) & 1)) + udelay(1); + +#ifdef DEBUG_MMIO + { + u16 ans = readw(card->ac97base_mmio + reg_set); + printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans); + return ans; + } +#else + return readw(card->ac97base_mmio + reg_set); +#endif +} +static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg) +{ + struct i810_card *card = dev->private_data; + int count = 100; + u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f)); + while(count-- && (inb(card->iobase + CAS) & 1)) udelay(1); return inw(card->ac97base + reg_set); } -static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data) +static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data) { struct i810_card *card = dev->private_data; int count = 100; - u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f)); + u16 reg_set = ((u16) reg) & 0x7f; + reg_set |= ((u16) dev->id) << 7; + + while(count-- && (readb(card->iobase_mmio + CAS) & 1)) + udelay(1); + + writew(data, card->ac97base_mmio + reg_set); +#ifdef DEBUG_MMIO + printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff); +#endif +} + +static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data) +{ + struct i810_card *card = dev->private_data; + int count = 100; + u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f)); + while(count-- && (inb(card->iobase + CAS) & 1)) udelay(1); - outw(data, card->ac97base + reg_set); + + outw(data, card->ac97base + reg_set); +} + +static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg) +{ + struct i810_card *card = dev->private_data; + if (card->use_mmio) { + return i810_ac97_get_mmio(dev, reg); + } + else { + return i810_ac97_get_io(dev, reg); + } +} + +static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data) +{ + struct i810_card *card = dev->private_data; + if (card->use_mmio) { + i810_ac97_set_mmio(dev, reg, data); + } + else { + i810_ac97_set_io(dev, reg, data); + } } @@ -2523,7 +2624,7 @@ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/20); } - for (i = 0; i < NR_AC97 && card && !card->initializing; i++) + for (i = 0; i < NR_AC97 && card && !card->initializing; i++) if (card->ac97_codec[i] != NULL && card->ac97_codec[i]->dev_mixer == minor) { file->private_data = card->ac97_codec[i]; @@ -2551,10 +2652,18 @@ /* AC97 codec initialisation. These small functions exist so we don't duplicate code between module init and apm resume */ -static inline int i810_ac97_exists(struct i810_card *card,int ac97_number) +static inline int i810_ac97_exists(struct i810_card *card, int ac97_number) { u32 reg = inl(card->iobase + GLOB_STA); - return (reg & (0x100 << ac97_number)); + switch (ac97_number) { + case 0: + return reg & (1<<8); + case 1: + return reg & (1<<9); + case 2: + return reg & (1<<28); + } + return 0; } static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec) @@ -2577,10 +2686,9 @@ /* power it all up */ i810_ac97_set(codec, AC97_POWER_CONTROL, i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); + /* wait for analog ready */ - for (i=10; - i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); - i--) + for (i=10; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/20); @@ -2588,8 +2696,14 @@ return i; } -/* if I knew what this did, I'd give it a better name */ -static int i810_ac97_random_init_stuff(struct i810_card *card) +/** + * i810_ac97_power_up_bus - bring up AC97 link + * @card : ICH audio device to power up + * + * Bring up the ACLink AC97 codec bus + */ + +static int i810_ac97_power_up_bus(struct i810_card *card) { u32 reg = inl(card->iobase + GLOB_CNT); int i; @@ -2600,8 +2714,13 @@ reg|=4; /* Warm */ reg&=~8; /* ACLink on */ - outl(reg , card->iobase + GLOB_CNT); + /* At this point we deassert AC_RESET # */ + outl(reg , card->iobase + GLOB_CNT); + + /* We must now allow time for the Codec initialisation. + 600mS is the specified time */ + for(i=0;i<10;i++) { if((inl(card->iobase+GLOB_CNT)&4)==0) @@ -2618,7 +2737,24 @@ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/2); + + /* + * See if the primary codec comes ready. This must happen + * before we start doing DMA stuff + */ + reg = inl(card->iobase + GLOB_STA); + if(!(reg & 0x100)) + { + printk(KERN_INFO "i810_audio: Codec not ready.. wait.. "); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); /* actually 600mS by the spec */ + reg = inl(card->iobase + GLOB_STA); + if(reg & 0x100) + printk("OK\n"); + else + printk("no response.\n"); + } inw(card->ac97base); return 1; } @@ -2627,11 +2763,12 @@ { int num_ac97 = 0; int total_channels = 0; + int ac97_count = 0; struct ac97_codec *codec; u16 eid; u32 reg; - if(!i810_ac97_random_init_stuff(card)) return 0; + if(!i810_ac97_power_up_bus(card)) return 0; /* Number of channels supported */ /* What about the codec? Just because the ICH supports */ @@ -2647,15 +2784,22 @@ card->channels = 6; else if ( reg & 0x0100000 ) card->channels = 4; - printk("i810_audio: Audio Controller supports %d channels.\n", card->channels); + printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels); + printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n"); + reg = inl(card->iobase + GLOB_CNT); + outl(reg & 0xffcfffff, card->iobase + GLOB_CNT); inw(card->ac97base); for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + + /* sigh, my mother board reports a tertiary codec (Intel D845GBV), + yet it's accessed as primary codec... (jsaw) */ + if (!d845gbv_bug) ac97_count = num_ac97; /* Assume codec isn't available until we go through the * gauntlet below */ - card->ac97_codec[num_ac97] = NULL; + card->ac97_codec[ac97_count] = NULL; /* The ICH programmer's reference says you should */ /* check the ready status before probing. So we chk */ @@ -2664,9 +2808,14 @@ if (!i810_ac97_exists(card,num_ac97)) { if(num_ac97 == 0) printk(KERN_ERR "i810_audio: Primary codec not ready.\n"); - break; /* I think this works, if not ready stop */ - } + /*@FIXME see comment about D845GBV */ + if (d845gbv_bug) + continue; + else + break; + } + if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) return -ENOMEM; memset(codec, 0, sizeof(struct ac97_codec)); @@ -2674,13 +2823,21 @@ /* initialize some basic codec information, other fields will be filled in ac97_probe_codec */ codec->private_data = card; - codec->id = num_ac97; - codec->codec_read = i810_ac97_get; - codec->codec_write = i810_ac97_set; + /*@FIXME see comment about D845GBV */ + codec->id = ac97_count; + + if (card->use_mmio) { + codec->codec_read = i810_ac97_get_mmio; + codec->codec_write = i810_ac97_set_mmio; + } + else { + codec->codec_read = i810_ac97_get_io; + codec->codec_write = i810_ac97_set_io; + } if(!i810_ac97_probe_and_powerup(card,codec)) { - printk("i810_audio: timed out waiting for codec %d analog ready.\n", num_ac97); + printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", num_ac97); kfree(codec); break; /* it didn't work */ } @@ -2689,7 +2846,7 @@ /* Don't attempt to get eid until powerup is complete */ eid = i810_ac97_get(codec, AC97_EXTENDED_ID); - + if(eid==0xFFFFFF) { printk(KERN_WARNING "i810_audio: no codec attached ?\n"); @@ -2702,11 +2859,13 @@ { printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", num_ac97); kfree(codec); + /*@FIXME see comment about D845GBV */ + if (d845gbv_bug) ac97_count++; continue; } card->ac97_features = eid; - + /* Now check the codec for useful features to make up for the dumbness of the 810 hardware engine */ @@ -2720,6 +2879,11 @@ } } + /* Turn on the amplifier */ + + codec->codec_write(codec, AC97_POWER_CONTROL, + codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000); + /* Determine how many channels the codec(s) support */ /* - The primary codec always supports 2 */ /* - If the codec supports AMAP, surround DACs will */ @@ -2783,13 +2947,15 @@ break; } - card->ac97_codec[num_ac97] = codec; + card->ac97_codec[ac97_count] = codec; + /*@FIXME see comment about D845GBV */ + if (d845gbv_bug) ac97_count++; } /* pick the minimum of channels supported by ICHx or codec(s) */ card->channels = (card->channels > total_channels)?total_channels:card->channels; - return num_ac97; + return ac97_count; } static void __init i810_configure_clocking (void) @@ -2823,6 +2989,8 @@ init_MUTEX(&state->open_sem); dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; dmabuf->trigger = PCM_ENABLE_OUTPUT; + i810_set_spdif_output(state, -1, 0); + i810_set_dac_channels(state, 2); i810_set_dac_rate(state, 48000); if(prog_dmabuf(state, 0) != 0) { goto config_out_nodmabuf; @@ -2831,6 +2999,8 @@ goto config_out; } dmabuf->count = dmabuf->dmasize; + stop_dac(state); + outb(0,card->iobase+dmabuf->write_channel->port+OFF_CIV); outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI); save_flags(flags); cli(); @@ -2839,10 +3009,9 @@ mdelay(50); new_offset = i810_get_dma_addr(state, 0); stop_dac(state); - outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); restore_flags(flags); i = new_offset - offset; -#ifdef DEBUG +#ifdef DEBUG_INTERRUPTS printk("i810_audio: %d bytes in 50 milliseconds\n", i); #endif if(i == 0) @@ -2884,10 +3053,29 @@ memset(card, 0, sizeof(*card)); card->initializing = 1; - card->iobase = pci_resource_start (pci_dev, 1); - card->ac97base = pci_resource_start (pci_dev, 0); card->pci_dev = pci_dev; card->pci_id = pci_id->device; + card->ac97base = pci_resource_start (pci_dev, 0); + card->iobase = pci_resource_start (pci_dev, 1); + + /* + ICH4 supports/needs direct memory access + to support more than 2 codecs + (jsaw) + */ + if ((pci_id->device == PCI_DEVICE_ID_INTEL_ICH4)) { + card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2); + card->iobase_mmio_phys = pci_resource_start (pci_dev, 3); + + if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) { + card->use_mmio = 1; + } + else { + card->ac97base_mmio_phys = 0; + card->iobase_mmio_phys = 0; + } + } + card->irq = pci_dev->irq; card->next = devs; card->magic = I810_CARD_MAGIC; @@ -2899,23 +3087,37 @@ pci_set_master(pci_dev); - printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n", - card_names[pci_id->driver_data], card->iobase, card->ac97base, + printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, " + "MEM 0x%04lx and 0x%04lx, IRQ %d\n", + card_names[pci_id->driver_data], + card->iobase, card->ac97base, + card->ac97base_mmio_phys, card->iobase_mmio_phys, card->irq); card->alloc_pcm_channel = i810_alloc_pcm_channel; card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel; card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel; card->free_pcm_channel = i810_free_pcm_channel; - card->channel[0].offset = 0; - card->channel[0].port = 0x00; - card->channel[0].num=0; - card->channel[1].offset = 0; - card->channel[1].port = 0x10; - card->channel[1].num=1; - card->channel[2].offset = 0; - card->channel[2].port = 0x20; - card->channel[2].num=2; + + if ((card->channel = pci_alloc_consistent(pci_dev, + sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) { + printk(KERN_ERR "i810: cannot allocate channel DMA memory\n"); + goto out_mem; + } + + { /* We may dispose of this altogether some time soon, so... */ + struct i810_channel *cp = card->channel; + + cp[0].offset = 0; + cp[0].port = 0x00; + cp[0].num = 0; + cp[1].offset = 0; + cp[1].port = 0x10; + cp[1].num = 1; + cp[2].offset = 0; + cp[2].port = 0x20; + cp[2].num = 2; + } /* claim our iospace and irq */ request_region(card->iobase, 64, card_names[pci_id->driver_data]); @@ -2924,19 +3126,42 @@ if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ, card_names[pci_id->driver_data], card)) { printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq); - release_region(card->iobase, 64); - release_region(card->ac97base, 256); - kfree(card); - return -ENODEV; + goto out_pio; + } + + if (card->use_mmio) { + if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) { + if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */ + if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) { + if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) { + printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n", + card_names[pci_id->driver_data], + (unsigned long) card->ac97base_mmio, + (unsigned long) card->iobase_mmio); + } + else { + iounmap(card->ac97base_mmio); + release_mem_region(card->ac97base_mmio_phys, 512); + release_mem_region(card->iobase_mmio_phys, 512); + card->use_mmio = 0; + } + } + else { + iounmap(card->ac97base_mmio); + release_mem_region(card->ac97base_mmio_phys, 512); + card->use_mmio = 0; + } + } + } + else { + card->use_mmio = 0; + } } /* initialize AC97 codec and register /dev/mixer */ if (i810_ac97_init(card) <= 0) { - release_region(card->iobase, 64); - release_region(card->ac97base, 256); free_irq(card->irq, card); - kfree(card); - return -ENODEV; + goto out_iospace; } pci_set_drvdata(pci_dev, card); @@ -2949,19 +3174,34 @@ if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) { int i; printk(KERN_ERR "i810_audio: couldn't register DSP device!\n"); - release_region(card->iobase, 64); - release_region(card->ac97base, 256); free_irq(card->irq, card); for (i = 0; i < NR_AC97; i++) if (card->ac97_codec[i] != NULL) { unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); kfree (card->ac97_codec[i]); } - kfree(card); - return -ENODEV; + goto out_iospace; } + card->initializing = 0; return 0; + +out_iospace: + if (card->use_mmio) { + iounmap(card->ac97base_mmio); + iounmap(card->iobase_mmio); + release_mem_region(card->ac97base_mmio_phys, 512); + release_mem_region(card->iobase_mmio_phys, 256); + } +out_pio: + release_region(card->iobase, 64); + release_region(card->ac97base, 256); +out_chan: + pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH, + card->channel, card->chandma); +out_mem: + kfree(card); + return -ENODEV; } static void __devexit i810_remove(struct pci_dev *pci_dev) @@ -2972,6 +3212,12 @@ free_irq(card->irq, devs); release_region(card->iobase, 64); release_region(card->ac97base, 256); + if (card->use_mmio) { + iounmap(card->ac97base_mmio); + iounmap(card->iobase_mmio); + release_mem_region(card->ac97base_mmio_phys, 512); + release_mem_region(card->iobase_mmio_phys, 256); + } /* unregister audio devices */ for (i = 0; i < NR_AC97; i++) @@ -3054,7 +3300,7 @@ hardware has to be more or less completely reinitialized from scratch after an apm suspend. Works For Me. -dan */ - i810_ac97_random_init_stuff(card); + i810_ac97_power_up_bus(card); for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { struct ac97_codec *codec = card->ac97_codec[num_ac97]; @@ -3117,6 +3363,7 @@ MODULE_PARM(clocking, "i"); MODULE_PARM(strict_clocking, "i"); MODULE_PARM(spdif_locked, "i"); +MODULE_PARM(d845gbv_bug, "i"); #define I810_MODULE_NAME "intel810_audio" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/sound/Makefile linux.20pre2-ac1/drivers/sound/Makefile --- linux.20pre2/drivers/sound/Makefile 2002-08-13 13:58:27.000000000 +0100 +++ linux.20pre2-ac1/drivers/sound/Makefile 2002-08-06 15:42:07.000000000 +0100 @@ -22,6 +22,7 @@ obj-$(CONFIG_SOUND_HAL2) += hal2.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o +obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o @@ -71,6 +72,7 @@ obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o +obj-$(CONFIG_SOUND_HARMONY) += harmony.o obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/devio.c linux.20pre2-ac1/drivers/usb/devio.c --- linux.20pre2/drivers/usb/devio.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/devio.c 2002-08-12 10:58:12.000000000 +0100 @@ -138,7 +138,7 @@ return ret; } -extern inline unsigned int ld2(unsigned int x) +static inline unsigned int ld2(unsigned int x) { unsigned int r = 0; @@ -188,7 +188,7 @@ kfree(as); } -extern __inline__ void async_newpending(struct async *as) +static inline void async_newpending(struct async *as) { struct dev_state *ps = as->ps; unsigned long flags; @@ -198,7 +198,7 @@ spin_unlock_irqrestore(&ps->lock, flags); } -extern __inline__ void async_removepending(struct async *as) +static inline void async_removepending(struct async *as) { struct dev_state *ps = as->ps; unsigned long flags; @@ -209,7 +209,7 @@ spin_unlock_irqrestore(&ps->lock, flags); } -extern __inline__ struct async *async_getcompleted(struct dev_state *ps) +static inline struct async *async_getcompleted(struct dev_state *ps) { unsigned long flags; struct async *as = NULL; @@ -224,7 +224,7 @@ return as; } -extern __inline__ struct async *async_getpending(struct dev_state *ps, void *userurb) +static inline struct async *async_getpending(struct dev_state *ps, void *userurb) { unsigned long flags; struct async *as; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/kaweth.c linux.20pre2-ac1/drivers/usb/kaweth.c --- linux.20pre2/drivers/usb/kaweth.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/kaweth.c 2002-08-12 10:58:12.000000000 +0100 @@ -143,6 +143,7 @@ { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */ { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */ { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */ + { USB_DEVICE(0x1485, 0x0001) }, /* Silicom USB-Ethernet Adapter */ { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/ov511.c linux.20pre2-ac1/drivers/usb/ov511.c --- linux.20pre2/drivers/usb/ov511.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/ov511.c 2002-08-06 15:42:11.000000000 +0100 @@ -377,55 +377,18 @@ * * Memory management * - * This is a shameless copy from the USB-cpia driver (linux kernel - * version 2.3.29 or so, I have no idea what this code actually does ;). - * Actually it seems to be a copy of a shameless copy of the bttv-driver. - * Or that is a copy of a shameless copy of ... (To the powers: is there - * no generic kernel-function to do this sort of stuff?) - * - * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says - * there will be one, but apparentely not yet -jerdfelt - * - * So I copied it again for the OV511 driver -claudio **********************************************************************/ -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long -uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) - page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - - return ret; -} - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -434,12 +397,9 @@ rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -447,13 +407,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -462,23 +418,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/ov511.h linux.20pre2-ac1/drivers/usb/ov511.h --- linux.20pre2/drivers/usb/ov511.h 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/ov511.h 2002-08-14 14:41:30.000000000 +0100 @@ -10,7 +10,8 @@ #ifdef OV511_DEBUG #define PDEBUG(level, fmt, args...) \ - if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\ + if (debug >= (level)) info("[%s:%d] " fmt,\ + __PRETTY_FUNCTION__, \ __LINE__ , ## args) #else #define PDEBUG(level, fmt, args...) do {} while(0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/printer.c linux.20pre2-ac1/drivers/usb/printer.c --- linux.20pre2/drivers/usb/printer.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/printer.c 2002-08-12 10:31:46.000000000 +0100 @@ -257,7 +257,7 @@ * Get and print printer errors. */ -static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" }; +static char *usblp_messages[] = { "ok", "out of paper", "off-line", "unknown error" }; static int usblp_check_status(struct usblp *usblp, int err) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/pwc-if.c linux.20pre2-ac1/drivers/usb/pwc-if.c --- linux.20pre2/drivers/usb/pwc-if.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/pwc-if.c 2002-08-06 15:42:11.000000000 +0100 @@ -179,60 +179,25 @@ /***************************************************************************/ /* Private functions */ -/* Memory management functions, nicked from cpia.c, which nicked them from - bttv.c. So far, I've counted duplication of this code 6 times - (bttv, cpia, ibmcam, ov511, pwc, ieee1394). - */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if(pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - - } - } - } - return ret; -} - - - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + 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(signed long size) +static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; + unsigned long adr; - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -240,8 +205,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -249,20 +213,16 @@ return mem; } -static void rvfree(void * mem, signed long size) +static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/scanner.c linux.20pre2-ac1/drivers/usb/scanner.c --- linux.20pre2/drivers/usb/scanner.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/scanner.c 2002-08-12 13:24:10.000000000 +0100 @@ -1,13 +1,13 @@ /* -*- linux-c -*- */ /* - * Driver for USB Scanners (linux-2.4.12) + * Driver for USB Scanners (linux-2.4.18) * - * Copyright (C) 1999, 2000, 2001 David E. Nelson + * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * * Portions may be copyright Brad Keryan and Michael Gee. * - * David E. Nelson (dnelson@jump.net) + * Brian Beattie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -300,11 +300,24 @@ * Frank Zago and * Oliver Neukum <520047054719-0001@t-online.de> for reviewing/testing. * + * 0.4.8 5/30/2002 + * - Added Mustek BearPaw 2400 TA. Thanks to Sergey + * Vlasov . + * - Added Mustek 1200UB Plus and Mustek BearPaw 1200 CU ID's. These use + * the Grandtech GT-6801 chip. Thanks to Henning + * Meier-Geinitz . + * - Increased Epson timeout to 60 secs as requested from + * Karl Heinz Kremer . + * - Changed maintainership from David E. Nelson to Brian + * Beattie . + * * TODO + * - Remove the 2/3 endpoint limitation * - Performance * - Select/poll methods * - More testing * - Proper registry/assignment for LM9830 ioctl's + * - More general usage ioctl's * * * Thanks to: @@ -320,6 +333,8 @@ * - All the folks who chimed in with reports and suggestions. * - All the developers that are working on USB SANE backends or other * applications to use USB scanners. + * - Thanks to Greg KH for setting up Brian Beattie + * to be the new USB Scanner maintainer. * * Performance: * @@ -756,7 +771,7 @@ if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) return -EFAULT; - nb = le16_to_cpup(&cmsg.req.wLength); + nb = cmsg.req.wLength; if (nb > sizeof(buf)) return -EINVAL; @@ -771,8 +786,8 @@ ret = usb_control_msg(dev, pipe, cmsg.req.bRequest, cmsg.req.bRequestType, - le16_to_cpup(&cmsg.req.wValue), - le16_to_cpup(&cmsg.req.wIndex), + cmsg.req.wValue, + cmsg.req.wIndex, buf, nb, HZ); if (ret < 0) { @@ -1017,7 +1032,7 @@ switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */ case 0x04b8: /* Seiko/Epson */ - scn->rd_nak_timeout = HZ * 40; + scn->rd_nak_timeout = HZ * 60; break; case 0x055f: /* Mustek */ case 0x0400: /* Another Mustek */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/scanner.h linux.20pre2-ac1/drivers/usb/scanner.h --- linux.20pre2/drivers/usb/scanner.h 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/scanner.h 2002-08-14 14:41:30.000000000 +0100 @@ -1,9 +1,9 @@ /* - * Driver for USB Scanners (linux-2.4.12) + * Driver for USB Scanners (linux-2.4.18) * - * Copyright (C) 1999, 2000, 2001 David E. Nelson + * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson * - * David E. Nelson (dnelson@jump.net) + * Brian Beattie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -48,7 +48,7 @@ static __s32 vendor=-1, product=-1, read_timeout=0; -MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson"); +MODULE_AUTHOR("Brian Beattie, beattie@beattie-home.net"); MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION); MODULE_LICENSE("GPL"); @@ -141,6 +141,8 @@ { USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */ { USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */ { USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */ + { USB_DEVICE(0x055f, 0x0218) }, /* BearPaw 2400 TA */ + { USB_DEVICE(0x05d8, 0x4002) }, /* 1200 CU and 1200 UB Plus */ /* Plustek */ { USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12 */ { USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro UT24 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/se401.c linux.20pre2-ac1/drivers/usb/se401.c --- linux.20pre2/drivers/usb/se401.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/se401.c 2002-08-12 10:57:56.000000000 +0100 @@ -80,54 +80,17 @@ * * Memory management * - * This is a shameless copy from the USB-cpia driver (linux kernel - * version 2.3.29 or so, I have no idea what this code actually does ;). - * Actually it seems to be a copy of a shameless copy of the bttv-driver. - * Or that is a copy of a shameless copy of ... (To the powers: is there - * no generic kernel-function to do this sort of stuff?) - * - * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says - * there will be one, but apparentely not yet -jerdfelt - * - * So I copied it again for the ov511 driver -claudio - * - * Same for the se401 driver -Jeroen **********************************************************************/ -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - - return ret; -} - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); return ret; } @@ -135,12 +98,9 @@ static void *rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -148,13 +108,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -162,23 +118,16 @@ static void rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } @@ -704,7 +653,7 @@ return 0; /* Check for a valid mode */ - if (!width || !height) + if (width <= 0 || height <= 0) return 1; if ((width & 1) || (height & 1)) return 1; @@ -738,7 +687,8 @@ static inline void enhance_picture(unsigned char *frame, int len) { while (len--) { - *frame++=(((*frame^255)*(*frame^255))/255)^255; + *frame=(((*frame^255)*(*frame^255))/255)^255; + frame++; } } @@ -972,7 +922,8 @@ /* Fix the top line */ framedata+=linelength; for (i=0; icheight; i++) { @@ -1425,7 +1376,13 @@ se401->sizes=cp[4]+cp[5]*256; se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); + if (!se401->width) + return 1; se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); + if (!se401->height) { + kfree(se401->width); + return 1; + } for (i=0; isizes; i++) { se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256; se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/belkin_sa.c linux.20pre2-ac1/drivers/usb/serial/belkin_sa.c --- linux.20pre2/drivers/usb/serial/belkin_sa.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/belkin_sa.c 2002-08-06 15:42:11.000000000 +0100 @@ -361,8 +361,6 @@ dbg(__FUNCTION__" port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -375,7 +373,6 @@ port->active = 0; } - up (&port->sem); MOD_DEC_USE_COUNT; } /* belkin_sa_close */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/cyberjack.c linux.20pre2-ac1/drivers/usb/serial/cyberjack.c --- linux.20pre2/drivers/usb/serial/cyberjack.c 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/cyberjack.c 2002-08-06 15:42:11.000000000 +0100 @@ -193,8 +193,6 @@ { dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -209,7 +207,6 @@ port->open_count = 0; } - up (&port->sem); MOD_DEC_USE_COUNT; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/empeg.c linux.20pre2-ac1/drivers/usb/serial/empeg.c --- linux.20pre2/drivers/usb/serial/empeg.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/empeg.c 2002-08-06 15:42:11.000000000 +0100 @@ -212,8 +212,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -225,8 +223,6 @@ port->open_count = 0; } - up (&port->sem); - /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/ftdi_sio.c linux.20pre2-ac1/drivers/usb/serial/ftdi_sio.c --- linux.20pre2/drivers/usb/serial/ftdi_sio.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/ftdi_sio.c 2002-08-06 15:42:11.000000000 +0100 @@ -382,7 +382,6 @@ dbg( __FUNCTION__); - down (&port->sem); --port->open_count; if (port->open_count <= 0) { @@ -421,7 +420,6 @@ } } - up (&port->sem); MOD_DEC_USE_COUNT; } /* ftdi_sio_close */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/ipaq.c linux.20pre2-ac1/drivers/usb/serial/ipaq.c --- linux.20pre2/drivers/usb/serial/ipaq.c 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/ipaq.c 2002-08-06 15:42:11.000000000 +0100 @@ -250,8 +250,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -269,7 +267,6 @@ port->open_count = 0; } - up (&port->sem); /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/ir-usb.c linux.20pre2-ac1/drivers/usb/serial/ir-usb.c --- linux.20pre2/drivers/usb/serial/ir-usb.c 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/ir-usb.c 2002-08-06 15:42:11.000000000 +0100 @@ -317,8 +317,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -330,7 +328,6 @@ port->open_count = 0; } - up (&port->sem); MOD_DEC_USE_COUNT; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/keyspan.c linux.20pre2-ac1/drivers/usb/serial/keyspan.c --- linux.20pre2/drivers/usb/serial/keyspan.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/keyspan.c 2002-08-12 10:57:56.000000000 +0100 @@ -945,8 +945,6 @@ p_priv->out_flip = 0; p_priv->in_flip = 0; - down (&port->sem); - if (--port->open_count <= 0) { if (port->active) { if (serial->dev) { @@ -963,7 +961,6 @@ port->open_count = 0; port->tty = 0; } - up (&port->sem); MOD_DEC_USE_COUNT; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/keyspan_pda.c linux.20pre2-ac1/drivers/usb/serial/keyspan_pda.c --- linux.20pre2/drivers/usb/serial/keyspan_pda.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/keyspan_pda.c 2002-08-06 15:42:11.000000000 +0100 @@ -738,8 +738,6 @@ { struct usb_serial *serial = port->serial; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -756,7 +754,6 @@ port->open_count = 0; } - up (&port->sem); MOD_DEC_USE_COUNT; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/kl5kusb105.c linux.20pre2-ac1/drivers/usb/serial/kl5kusb105.c --- linux.20pre2/drivers/usb/serial/kl5kusb105.c 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/kl5kusb105.c 2002-08-06 15:42:11.000000000 +0100 @@ -499,8 +499,6 @@ if(!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -527,7 +525,6 @@ info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out); } - up (&port->sem); MOD_DEC_USE_COUNT; } /* klsi_105_close */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/mct_u232.c linux.20pre2-ac1/drivers/usb/serial/mct_u232.c --- linux.20pre2/drivers/usb/serial/mct_u232.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/mct_u232.c 2002-08-06 15:42:11.000000000 +0100 @@ -479,8 +479,6 @@ { dbg(__FUNCTION__" port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -493,7 +491,6 @@ port->active = 0; } - up (&port->sem); MOD_DEC_USE_COUNT; } /* mct_u232_close */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/omninet.c linux.20pre2-ac1/drivers/usb/serial/omninet.c --- linux.20pre2/drivers/usb/serial/omninet.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/omninet.c 2002-08-06 15:42:11.000000000 +0100 @@ -211,8 +211,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -229,7 +227,6 @@ kfree(od); } - up (&port->sem); MOD_DEC_USE_COUNT; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/pl2303.c linux.20pre2-ac1/drivers/usb/serial/pl2303.c --- linux.20pre2/drivers/usb/serial/pl2303.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/pl2303.c 2002-08-12 10:55:15.000000000 +0100 @@ -452,8 +452,6 @@ dbg (__FUNCTION__ " - port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { if (serial->dev) { @@ -491,7 +489,6 @@ port->open_count = 0; } - up (&port->sem); MOD_DEC_USE_COUNT; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/usbserial.c linux.20pre2-ac1/drivers/usb/serial/usbserial.c --- linux.20pre2/drivers/usb/serial/usbserial.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/usbserial.c 2002-08-12 10:59:44.000000000 +0100 @@ -553,12 +553,21 @@ return; } + down (&port->sem); + + if (tty->driver_data == NULL) { + /* disconnect beat us to the punch here, so handle it gracefully */ + goto exit; + } + /* pass on to the driver specific version of this function if it is available */ if (serial->type->close) { serial->type->close(port, filp); } else { generic_close(port, filp); } +exit: + up (&port->sem); } @@ -826,8 +835,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -843,8 +850,6 @@ port->open_count = 0; } - up (&port->sem); - /* only decrement our usage count, if this device is _really_ a generic device */ if_generic_do(MOD_DEC_USE_COUNT); } @@ -1341,8 +1346,10 @@ if (serial) { /* fail all future close/read/write/ioctl/etc calls */ for (i = 0; i < serial->num_ports; ++i) { + down (&serial->port[i].sem); if (serial->port[i].tty != NULL) serial->port[i].tty->driver_data = NULL; + up (&serial->port[i].sem); } serial->dev = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/visor.c linux.20pre2-ac1/drivers/usb/serial/visor.c --- linux.20pre2/drivers/usb/serial/visor.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/visor.c 2002-08-06 15:42:11.000000000 +0100 @@ -391,8 +391,6 @@ if (!serial) return; - down (&port->sem); - --port->open_count; if (port->open_count <= 0) { @@ -417,7 +415,6 @@ port->active = 0; port->open_count = 0; } - up (&port->sem); /* Uncomment the following line if you want to see some statistics in your syslog */ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/serial/whiteheat.c linux.20pre2-ac1/drivers/usb/serial/whiteheat.c --- linux.20pre2/drivers/usb/serial/whiteheat.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/serial/whiteheat.c 2002-08-06 15:42:11.000000000 +0100 @@ -382,7 +382,6 @@ dbg(__FUNCTION__ " - port %d", port->number); - down (&port->sem); --port->open_count; if (port->open_count <= 0) { @@ -400,7 +399,6 @@ port->active = 0; } MOD_DEC_USE_COUNT; - up (&port->sem); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/storage/unusual_devs.h linux.20pre2-ac1/drivers/usb/storage/unusual_devs.h --- linux.20pre2/drivers/usb/storage/unusual_devs.h 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/storage/unusual_devs.h 2002-08-06 15:42:11.000000000 +0100 @@ -480,6 +480,12 @@ US_SC_SCSI, US_PR_CB, NULL, US_FL_MODE_XLATE ), +UNUSUAL_DEV( 0x0a16, 0x8888, 0x0100, 0x0100, + "IBM", + "IBM USB Memory Key", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, "ATI", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/stv680.c linux.20pre2-ac1/drivers/usb/stv680.c --- linux.20pre2/drivers/usb/stv680.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/stv680.c 2002-08-12 10:57:56.000000000 +0100 @@ -86,7 +86,7 @@ #define PDEBUG(level, fmt, args...) \ do { \ if (debug >= level) \ - info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args); \ + info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args); \ } while (0) @@ -111,67 +111,27 @@ * * Memory management * - * This is a shameless copy from the USB-cpia driver (linux kernel - * version 2.3.29 or so, I have no idea what this code actually does ;). - * Actually it seems to be a copy of a shameless copy of the bttv-driver. - * Or that is a copy of a shameless copy of ... (To the powers: is there - * no generic kernel-function to do this sort of stuff?) - * - * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says - * there will be one, but apparentely not yet -jerdfelt - * - * So I copied it again for the ov511 driver -claudio - * - * Same for the se401 driver -Jeroen - * - * And the STV0680 driver - Kevin ********************************************************************/ -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva (pgd_t * pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none (*pgd)) { - pmd = pmd_offset (pgd, adr); - if (!pmd_none (*pmd)) { - ptep = pte_offset (pmd, adr); - pte = *ptep; - if (pte_present (pte)) { - ret = (unsigned long) page_address (pte_page (pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } - } - return ret; -} - -/* Here we want the physical address of the memory. This is used when - * initializing the contents of the area and marking the pages as reserved. +/* 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 va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR (adr); - kva = uvirt_to_kva (pgd_offset_k (va), va); - ret = __pa (kva); + 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, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32 (size); if (!mem) return NULL; @@ -179,36 +139,25 @@ memset (mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = kvirt_to_pa (adr); - mem_map_reserve (virt_to_page (__va (page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; } static void rvfree (void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - adr = (unsigned long) mem; - while (size > 0) { - page = kvirt_to_pa (adr); - mem_map_unreserve (virt_to_page (__va (page))); + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree (mem); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/usb-ohci.c linux.20pre2-ac1/drivers/usb/usb-ohci.c --- linux.20pre2/drivers/usb/usb-ohci.c 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/usb-ohci.c 2002-08-12 10:58:12.000000000 +0100 @@ -2144,6 +2144,8 @@ int timeout = 30; int smm_timeout = 50; /* 0,5 sec */ +#ifndef __hppa__ + /* PA-RISC doesn't have SMM, but PDC might leave IR set */ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */ dbg("USB HC TakeOver from SMM"); @@ -2154,7 +2156,8 @@ return -1; } } - } + } +#endif /* Disable HC interrupts */ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); @@ -2218,9 +2221,19 @@ writel (mask, &ohci->regs->intrstatus); #ifdef OHCI_USE_NPS - /* required for AMD-756 and some Mac platforms */ - writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM, - &ohci->regs->roothub.a); + if(ohci->flags & OHCI_QUIRK_SUCKYIO) + { + /* NSC 87560 at least requires different setup .. */ + writel ((roothub_a (ohci) | RH_A_NOCP) & + ~(RH_A_OCPM | RH_A_POTPGT | RH_A_PSM | RH_A_NPS), + &ohci->regs->roothub.a); + } + else + { + /* required for AMD-756 and some Mac platforms */ + writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM, + &ohci->regs->roothub.a); + } writel (RH_HS_LPSC, &ohci->regs->roothub.status); #endif /* OHCI_USE_NPS */ @@ -2470,6 +2483,21 @@ return ret; } ohci->flags = id->driver_data; + + /* Check for NSC87560. We have to look at the bridge (fn1) to identify + the USB (fn2). This quirk might apply to more or even all NSC stuff + I don't know.. */ + + if(dev->vendor == PCI_VENDOR_ID_NS) + { + struct pci_dev *fn1 = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1)); + if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO) + ohci->flags |= OHCI_QUIRK_SUCKYIO; + + } + + if (ohci->flags & OHCI_QUIRK_SUCKYIO) + printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n"); if (ohci->flags & OHCI_QUIRK_AMD756) printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/usb-ohci.h linux.20pre2-ac1/drivers/usb/usb-ohci.h --- linux.20pre2/drivers/usb/usb-ohci.h 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/usb-ohci.h 2002-08-12 10:57:56.000000000 +0100 @@ -381,6 +381,7 @@ atomic_t resume_count; /* defending against multiple resumes */ unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ +#define OHCI_QUIRK_SUCKYIO 0x02 /* NSC superio */ struct ohci_regs * regs; /* OHCI controller's memory */ struct list_head ohci_hcd_list; /* list of all ohci_hcd */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/usbvideo.c linux.20pre2-ac1/drivers/usb/usbvideo.c --- linux.20pre2/drivers/usb/usbvideo.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/usbvideo.c 2002-08-12 10:57:56.000000000 +0100 @@ -58,57 +58,26 @@ /* Memory management functions */ /*******************************/ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -unsigned long usbvideo_uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE-1)); - } - } - } - MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); - return ret; -} - /* * Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ unsigned long usbvideo_kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = usbvideo_uvirt_to_kva(pgd_offset_k(va), va); + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); return ret; } void *usbvideo_rvmalloc(unsigned long size) { void *mem; - unsigned long adr, page; - - /* Round it off to PAGE_SIZE */ - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); + unsigned long adr; + size = PAGE_ALIGN(size); mem = vmalloc_32(size); if (!mem) return NULL; @@ -116,13 +85,9 @@ memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { - page = usbvideo_kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return mem; @@ -130,23 +95,16 @@ void usbvideo_rvfree(void *mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (!mem) return; - size += (PAGE_SIZE - 1); - size &= ~(PAGE_SIZE - 1); - - adr=(unsigned long) mem; - while (size > 0) { - page = usbvideo_kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } vfree(mem); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/vicam.c linux.20pre2-ac1/drivers/usb/vicam.c --- linux.20pre2/drivers/usb/vicam.c 2002-08-13 13:58:32.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/vicam.c 2002-08-06 15:42:11.000000000 +0100 @@ -91,80 +91,25 @@ * ******************************************************************************/ -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if(pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - - } - } - } - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - return ret; -} - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = virt_to_bus((void *)kva); - return ret; -} - /* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. + * This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) { - unsigned long va, kva, ret; + unsigned long kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); + 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(signed long size) +static void * rvmalloc(unsigned long size) { void * mem; - unsigned long adr, page; + unsigned long adr; + size=PAGE_ALIGN(size); mem=vmalloc_32(size); if (mem) { @@ -172,8 +117,7 @@ adr=(unsigned long) mem; while (size > 0) { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); + mem_map_reserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } @@ -181,17 +125,16 @@ return mem; } -static void rvfree(void * mem, signed long size) +static void rvfree(void * mem, unsigned long size) { - unsigned long adr, page; + unsigned long adr; if (mem) { adr=(unsigned long) mem; - while (size > 0) + while ((long) size > 0) { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); + mem_map_unreserve(vmalloc_to_page((void *)adr)); adr+=PAGE_SIZE; size-=PAGE_SIZE; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/usb/wacom.c linux.20pre2-ac1/drivers/usb/wacom.c --- linux.20pre2/drivers/usb/wacom.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/usb/wacom.c 2002-08-06 15:42:11.000000000 +0100 @@ -111,7 +111,6 @@ struct wacom_features *features; int tool[2]; int open; - int x, y; __u32 serial[2]; }; @@ -209,16 +208,16 @@ input_report_abs(dev, ABS_DISTANCE, data[7]); input_report_rel(dev, REL_WHEEL, (signed char) data[6]); - input_report_abs(dev, ABS_X, wacom->x = x); - input_report_abs(dev, ABS_Y, wacom->y = y); + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01); return; } if (data[1] & 0x80) { - input_report_abs(dev, ABS_X, wacom->x = x); - input_report_abs(dev, ABS_Y, wacom->y = y); + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); } input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8)); @@ -236,7 +235,6 @@ struct input_dev *dev = &wacom->dev; unsigned int t; int idx; - int x, y; if (urb->status) return; @@ -285,11 +283,8 @@ return; } - x = ((__u32)data[2] << 8) | data[3]; - y = ((__u32)data[4] << 8) | data[5]; - - input_report_abs(dev, ABS_X, wacom->x); - input_report_abs(dev, ABS_Y, wacom->y); + input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]); + input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]); input_report_abs(dev, ABS_DISTANCE, data[9] >> 4); if ((data[1] & 0xb8) == 0xa0) { /* general pen packet */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/aty/atyfb_base.c linux.20pre2-ac1/drivers/video/aty/atyfb_base.c --- linux.20pre2/drivers/video/aty/atyfb_base.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/aty/atyfb_base.c 2002-08-06 15:42:11.000000000 +0100 @@ -360,6 +360,7 @@ /* 3D RAGE Mobility */ { 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p, 230, 50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS }, + { 0x4c52, 0x4c52, 0x00, 0x00, m64n_mob_p, 230, 40, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS | M64F_MAGIC_POSTDIV | M64F_SDRAM_MAGIC_PLL | M64F_XL_DLL }, { 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a, 230, 50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS }, #endif /* CONFIG_FB_ATY_CT */ }; @@ -438,7 +439,7 @@ #endif /* defined(CONFIG_PPC) */ -#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT) +#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_CT_VAIO_LCD) static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info) { unsigned long temp; @@ -460,7 +461,7 @@ /* read the register value */ return aty_ld_le32(LCD_DATA, info); } -#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */ +#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT || CONFIG_FB_ATY_CT_VAIO_LCD */ /* ------------------------------------------------------------------------- */ @@ -1772,6 +1773,9 @@ #if defined(CONFIG_PPC) int sense; #endif +#if defined(CONFIG_FB_ATY_CT_VAIO_LCD) + u32 pm, hs; +#endif u8 pll_ref_div; info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); @@ -2089,6 +2093,35 @@ var = default_var; #endif /* !__sparc__ */ #endif /* !CONFIG_PPC */ +#if defined(CONFIG_FB_ATY_CT_VAIO_LCD) + /* Power Management */ + pm=aty_ld_lcd(POWER_MANAGEMENT, info); + pm=(pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_PCI; + pm|=PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, info); + udelay(10); + + /* OVR_WID_LEFT_RIGHT */ + hs=aty_ld_le32(OVR_WID_LEFT_RIGHT,info); + hs= 0x00000000; + aty_st_le32(OVR_WID_LEFT_RIGHT, hs, info); + udelay(10); + + /* CONFIG_PANEL */ + hs=aty_ld_lcd(CONFIG_PANEL,info); + hs|=DONT_SHADOW_HEND ; + aty_st_lcd(CONFIG_PANEL, hs, info); + udelay(10); + +#if defined(DEBUG) + printk("LCD_INDEX CONFIG_PANEL LCD_GEN_CTRL POWER_MANAGEMENT\n" + "%08x %08x %08x %08x\n", + aty_ld_le32(LCD_INDEX, info), + aty_ld_lcd(CONFIG_PANEL, info), + aty_ld_lcd(LCD_GEN_CTRL, info), + aty_ld_lcd(POWER_MANAGEMENT, info), +#endif /* DEBUG */ +#endif /* CONFIG_FB_ATY_CT_VAIO_LCD */ #endif /* !MODULE */ if (noaccel) var.accel_flags &= ~FB_ACCELF_TEXT; @@ -2712,6 +2745,23 @@ /* * Blank the display. */ +#if defined(CONFIG_FB_ATY_CT_VAIO_LCD) +static int set_backlight_enable(int on, struct fb_info_aty *info) +{ + unsigned int reg = aty_ld_lcd(POWER_MANAGEMENT, info); + if(on) { + reg=(reg & ~SUSPEND_NOW) | PWR_BLON; + } else { + reg=(reg & ~PWR_BLON) | SUSPEND_NOW; + } + aty_st_lcd(POWER_MANAGEMENT, reg, info); + udelay(10); +#ifdef DEBUG + printk(KERN_INFO "set_backlight_enable(%i): %08x\n", on, aty_ld_lcd(POWER_MANAGEMENT, info) ); +#endif + return 0; +} +#endif /* CONFIG_FB_ATY_CT_VAIO_LCD */ static void atyfbcon_blank(int blank, struct fb_info *fb) { @@ -2723,6 +2773,9 @@ set_backlight_enable(0); #endif /* CONFIG_PMAC_BACKLIGHT */ +#if defined(CONFIG_FB_ATY_CT_VAIO_LCD) + set_backlight_enable(!blank, info); +#endif /* CONFIG_FB_ATY_CT_VAIO_LCD */ gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info); if (blank > 0) switch (blank-1) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/aty/mach64_ct.c linux.20pre2-ac1/drivers/video/aty/mach64_ct.c --- linux.20pre2/drivers/video/aty/mach64_ct.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/aty/mach64_ct.c 2002-08-06 15:42:11.000000000 +0100 @@ -178,11 +178,14 @@ } pll->pll_gen_cntl |= mpostdiv<<4; /* mclk */ - if (M64_HAS(MAGIC_POSTDIV)) - pll->pll_ext_cntl = 0; - else +#if defined(CONFIG_FB_ATY_CT_VAIO_LCD) pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */ - +#else + if ( M64_HAS(MAGIC_POSTDIV) ) + pll->pll_ext_cntl = 0; + else + pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */ +#endif switch (pll->vclk_post_div_real) { case 2: vpostdiv = 1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/aty/mach64.h linux.20pre2-ac1/drivers/video/aty/mach64.h --- linux.20pre2/drivers/video/aty/mach64.h 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/aty/mach64.h 2002-08-06 15:42:11.000000000 +0100 @@ -1148,6 +1148,8 @@ #define APC_LUT_MN 0x39 #define APC_LUT_OP 0x3A +/* Values in CONFIG_PANEL */ +#define DONT_SHADOW_HEND 0x00004000 /* Values in LCD_MISC_CNTL */ #define BIAS_MOD_LEVEL_MASK 0x0000ff00 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/clgenfb.c linux.20pre2-ac1/drivers/video/clgenfb.c --- linux.20pre2/drivers/video/clgenfb.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/clgenfb.c 2002-08-06 15:42:11.000000000 +0100 @@ -3089,7 +3089,7 @@ *********************************************************************/ /* FIXME: use interrupts instead */ -extern inline void clgen_WaitBLT (caddr_t regbase) +static inline void clgen_WaitBLT (caddr_t regbase) { /* now busy-wait until we're done */ while (vga_rgfx (regbase, CL_GR31) & 0x08) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/Config.in linux.20pre2-ac1/drivers/video/Config.in --- linux.20pre2/drivers/video/Config.in 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/Config.in 2002-08-13 15:22:12.000000000 +0100 @@ -132,14 +132,21 @@ fi fi dep_tristate ' G450/G550 second head support (mandatory for G550)' CONFIG_FB_MATROX_G450 $CONFIG_FB_MATROX_G100 + dep_tristate ' Matrox /proc interface' CONFIG_FB_MATROX_PROC $CONFIG_FB_MATROX bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD fi tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY if [ "$CONFIG_FB_ATY" != "n" ]; then bool ' Mach64 GX support (EXPERIMENTAL)' CONFIG_FB_ATY_GX bool ' Mach64 CT/VT/GT/LT (incl. 3D RAGE) support' CONFIG_FB_ATY_CT + if [ "$CONFIG_FB_ATY_CT" = "y" ]; then + bool ' Sony Vaio C1VE 1024x480 LCD support' CONFIG_FB_ATY_CT_VAIO_LCD + fi fi tristate ' ATI Radeon display support (EXPERIMENTAL)' CONFIG_FB_RADEON + if [ "$CONFIG_FB_RADEON" = "y" ]; then + bool ' Sony Vaio C1MV 1280x600 LCD support' CONFIG_FB_RADEON_VAIO_LCD + fi tristate ' ATI Rage128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128 tristate ' SIS acceleration (EXPERIMENTAL)' CONFIG_FB_SIS if [ "$CONFIG_FB_SIS" != "n" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/matrox/Makefile linux.20pre2-ac1/drivers/video/matrox/Makefile --- linux.20pre2/drivers/video/matrox/Makefile 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/matrox/Makefile 2002-08-06 15:42:11.000000000 +0100 @@ -17,6 +17,7 @@ obj-$(CONFIG_FB_MATROX_I2C) += i2c-matroxfb.o obj-$(CONFIG_FB_MATROX_MAVEN) += matroxfb_maven.o matroxfb_crtc2.o obj-$(CONFIG_FB_MATROX_G450) += matroxfb_g450.o matroxfb_crtc2.o +obj-$(CONFIG_FB_MATROX_PROC) += matroxfb_proc.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/matrox/matroxfb_proc.c linux.20pre2-ac1/drivers/video/matrox/matroxfb_proc.c --- linux.20pre2/drivers/video/matrox/matroxfb_proc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/matrox/matroxfb_proc.c 2002-08-06 15:42:11.000000000 +0100 @@ -0,0 +1,151 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2001 Petr Vandrovec + * + * Version: 1.62 2001/11/29 + * + */ + +#include "matroxfb_base.h" +#include + +static struct proc_dir_entry* mga_pde; + +struct procinfo { + struct matrox_fb_info* info; + struct proc_dir_entry* pde; +}; + +static inline void remove_pde(struct proc_dir_entry* pde) { + if (pde) { + remove_proc_entry(pde->name, pde->parent); + } +} + +#ifndef CONFIG_PROC_FS +static int bios_read_proc(char* buffer, char** start, off_t offset, + int size, int *eof, void *data) { + return 0; +} + +static int pins_read_proc(char* buffer, char** start, off_t offset, + int size, int *eof, void *data) { + return 0; +} +#else +/* This macro frees the machine specific function from bounds checking and + * this like that... */ +#define PRINT_PROC(fmt,args...) \ + do { \ + len += sprintf(buffer+len, fmt, ##args ); \ + if (begin + len > offset + size) \ + break; \ + if (begin + len < offset) { \ + begin += len; \ + len = 0; \ + } \ + } while(0) + +static int bios_read_proc(char* buffer, char** start, off_t offset, + int size, int *eof, void *data) { + int len = 0; + off_t begin = 0; + struct matrox_bios* bd = data; + + do { + *eof = 0; + if (bd->bios_valid) { + PRINT_PROC("BIOS: %u.%u.%u\n", bd->version.vMaj, bd->version.vMin, bd->version.vRev); + PRINT_PROC("Output: 0x%02X\n", bd->output.state); + PRINT_PROC("TVOut: %s\n", bd->output.tvout?"yes":"no"); + PRINT_PROC("PINS: %s\n", bd->pins_len ? "found" : "not found"); + PRINT_PROC("Info: %p\n", bd); + } else { + PRINT_PROC("BIOS: Invalid\n"); + } + *eof = 1; + } while (0); + if (offset >= begin + len) + return 0; + *start = buffer + (offset - begin); + return size < begin + len - offset ? size : begin + len - offset; +} + +static int pins_read_proc(char* buffer, char** start, off_t offset, + int size, int *eof, void *data) { + struct matrox_bios* bd = data; + + if (offset >= bd->pins_len) { + *eof = 1; + return 0; + } + if (offset + size >= bd->pins_len) { + size = bd->pins_len - offset; + *eof = 1; + } + memcpy(buffer, bd->pins + offset, size); + *start = buffer; + return size; +} +#endif /* CONFIG_PROC_FS */ + +static void* matroxfb_proc_probe(struct matrox_fb_info* minfo) { + struct procinfo* binfo; + char b[10]; + + binfo = (struct procinfo*)kmalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + printk(KERN_ERR "matroxfb_proc: Not enough memory for /proc control structs\n"); + return NULL; + } + binfo->info = minfo; + sprintf(b, "fb%u", GET_FB_IDX(minfo->fbcon.node)); + binfo->pde = proc_mkdir(b, mga_pde); + if (binfo->pde) { + create_proc_read_entry("bios", 0, binfo->pde, bios_read_proc, &minfo->bios); + if (minfo->bios.pins_len) { + struct proc_dir_entry* p = create_proc_read_entry("pins", 0, binfo->pde, pins_read_proc, &minfo->bios); + if (p) { + p->size = minfo->bios.pins_len; + } + } + } + return binfo; +} + +static void matroxfb_proc_remove(struct matrox_fb_info* minfo, void* binfoI) { + struct procinfo* binfo = binfoI; + + if (binfo->pde) { + remove_proc_entry("pins", binfo->pde); + remove_proc_entry("bios", binfo->pde); + remove_pde(binfo->pde); + } + kfree(binfo); +} + +static struct matroxfb_driver procfn = { + name: "Matrox /proc driver", + probe: matroxfb_proc_probe, + remove: matroxfb_proc_remove +}; + +static int matroxfb_proc_init(void) { + mga_pde = proc_mkdir("driver/mga", NULL); + matroxfb_register_driver(&procfn); + return 0; +} + +static void matroxfb_proc_exit(void) { + matroxfb_unregister_driver(&procfn); + remove_pde(mga_pde); +} + +MODULE_AUTHOR("(c) 2001 Petr Vandrovec "); +MODULE_DESCRIPTION("Matrox /proc driver"); +MODULE_LICENSE("GPL"); +module_init(matroxfb_proc_init); +module_exit(matroxfb_proc_exit); +/* we do not have __setup() */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/modedb.c linux.20pre2-ac1/drivers/video/modedb.c --- linux.20pre2/drivers/video/modedb.c 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/modedb.c 2002-08-06 15:42:11.000000000 +0100 @@ -42,6 +42,20 @@ #define DEFAULT_MODEDB_INDEX 0 static struct fb_videomode modedb[] __initdata = { +#if defined(CONFIG_FB_ATY_CT_VAIO_LCD) + { + /* 1024x480 @ 65 Hz */ + NULL, 65, 1024, 480, 25203, 24, 24, 1, 17, 144, 4, + 0, FB_VMODE_NONINTERLACED + }, +#endif /* CONFIG_FB_ATY_CT_VAIO_LCD */ +#if defined(CONFIG_FB_RADEON_VAIO_LCD) + { + /* 1280x600 @ 72 Hz, 45.288 kHz hsync */ + NULL, 72, 1280, 600, 13940, 24, 24, 23, 1, 256, 5, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + }, +#endif /* CONFIG_FB_RADEON_VAIO_LCD */ { /* 640x400 @ 70 Hz, 31.5 kHz hsync */ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/radeonfb.c linux.20pre2-ac1/drivers/video/radeonfb.c --- linux.20pre2/drivers/video/radeonfb.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/radeonfb.c 2002-08-06 17:58:23.000000000 +0100 @@ -45,6 +45,10 @@ #include #include +#ifdef CONFIG_MTRR +#include +#endif + #include #if defined(__powerpc__) #include @@ -261,6 +265,8 @@ unsigned long mmio_base; unsigned long fb_base; + int mtrr_hdl; + struct pci_dev *pdev; unsigned char *EDID; @@ -484,7 +490,7 @@ static void _radeon_engine_reset(struct radeonfb_info *rinfo) { - u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset; + u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset, host_path_cntl; radeon_engine_flush (rinfo); @@ -498,6 +504,9 @@ FORCEON_YCLKB | FORCEON_MC | FORCEON_AIC)); + + host_path_cntl = INREG(HOST_PATH_CNTL); + rbbm_soft_reset = INREG(RBBM_SOFT_RESET); OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset | @@ -507,8 +516,7 @@ SOFT_RESET_RE | SOFT_RESET_PP | SOFT_RESET_E2 | - SOFT_RESET_RB | - SOFT_RESET_HDP); + SOFT_RESET_RB); INREG(RBBM_SOFT_RESET); OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32) ~(SOFT_RESET_CP | @@ -517,13 +525,16 @@ SOFT_RESET_RE | SOFT_RESET_PP | SOFT_RESET_E2 | - SOFT_RESET_RB | - SOFT_RESET_HDP)); + SOFT_RESET_RB)); INREG(RBBM_SOFT_RESET); - OUTPLL(MCLK_CNTL, mclk_cntl); - OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); + OUTREG(HOST_PATH_CNTL, host_path_cntl | HDP_SOFT_RESET); + INREG(HOST_PATH_CNTL); + OUTREG(HOST_PATH_CNTL, host_path_cntl); + OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset); + OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); + OUTPLL(MCLK_CNTL, mclk_cntl); return; } @@ -595,6 +606,7 @@ static char fontname[40] __initdata; static char *mode_option __initdata; static char noaccel __initdata = 0; +static char nomtrr __initdata = 0; static int panel_yres __initdata = 0; static char force_dfp __initdata = 0; static struct radeonfb_info *board_list = NULL; @@ -731,6 +743,8 @@ force_dfp = 1; } else if (!strncmp(this_opt, "panel_yres:", 11)) { panel_yres = simple_strtoul((this_opt+11), NULL, 0); + } else if (!strncmp(this_opt, "nomtrr", 6)) { + nomtrr = 1; } else mode_option = this_opt; } @@ -866,6 +880,14 @@ /* mem size is bits [28:0], mask off the rest */ rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK; + /* According to XFree86 4.2.0, some production M6's return 0 + for 8MB. */ + if (rinfo->video_ram == 0 && + (pdev->device == PCI_DEVICE_ID_RADEON_LY || + pdev->device == PCI_DEVICE_ID_RADEON_LZ)) { + rinfo->video_ram = 8192 * 1024; + } + /* ram type */ tmp = INREG(MEM_SDRAM_MODE_REG); switch ((MEM_CFG_TYPE & tmp) >> 30) { @@ -960,9 +982,6 @@ return -ENODEV; } - /* XXX turn off accel for now, blts aren't working right */ - noaccel = 1; - /* currcon not yet configured, will be set by first switch */ rinfo->currcon = -1; @@ -998,6 +1017,10 @@ return -ENODEV; } +#ifdef CONFIG_MTRR + rinfo->mtrr_hdl = nomtrr ? -1 : mtrr_add(rinfo->fb_base_phys, rinfo->video_ram, MTRR_TYPE_WRCOMB, 1); +#endif + if (!noaccel) { /* initialize the engine */ radeon_engine_init (rinfo); @@ -1046,6 +1069,11 @@ /* restore original state */ radeon_write_mode (rinfo, &rinfo->init_state); +#ifdef CONFIG_MTRR + if(rinfo->mtrr_hdl >= 0) + mtrr_del(rinfo->mtrr_hdl, 0, 0); +#endif + unregister_framebuffer ((struct fb_info *) rinfo); iounmap ((void*)rinfo->mmio_base); @@ -1540,7 +1568,7 @@ radeon_engine_reset (); radeon_fifo_wait (1); - OUTREG(DSTCACHE_MODE, 0); + OUTREG(RB2D_DSTCACHE_MODE, 0); /* XXX */ rinfo->pitch = ((rinfo->xres * (rinfo->bpp / 8) + 0x3f)) >> 6; @@ -1703,7 +1731,7 @@ switch (disp->var.bits_per_pixel) { #ifdef FBCON_HAS_CFB8 case 8: - disp->dispsw = &fbcon_cfb8; + disp->dispsw = accel ? &fbcon_radeon8 : &fbcon_cfb8; disp->visual = FB_VISUAL_PSEUDOCOLOR; disp->line_length = disp->var.xres_virtual; break; @@ -2035,6 +2063,8 @@ do_install_cmap(con, info); + if(accel) + radeon_engine_init(rinfo); return 0; } @@ -2957,7 +2987,7 @@ int dsty, int dstx, int height, int width) { struct radeonfb_info *rinfo = (struct radeonfb_info *)(p->fb_info); - u32 dp_cntl = DST_LAST_PEL; + u32 dp_cntl; srcx *= fontwidth(p); srcy *= fontheight(p); @@ -2966,6 +2996,8 @@ width *= fontwidth(p); height *= fontheight(p); + dp_cntl = 0; + if (srcy < dsty) { srcy += height - 1; dsty += height - 1; @@ -2989,6 +3021,8 @@ OUTREG(SRC_Y_X, (srcy << 16) | srcx); OUTREG(DST_Y_X, (dsty << 16) | dstx); OUTREG(DST_HEIGHT_WIDTH, (height << 16) | width); + + radeon_engine_idle(); } @@ -3018,6 +3052,8 @@ OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); OUTREG(DST_Y_X, (srcy << 16) | srcx); OUTREG(DST_WIDTH_HEIGHT, (width << 16) | height); + + radeon_engine_idle(); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/drivers/video/radeon.h linux.20pre2-ac1/drivers/video/radeon.h --- linux.20pre2/drivers/video/radeon.h 2002-08-13 13:58:29.000000000 +0100 +++ linux.20pre2-ac1/drivers/video/radeon.h 2002-08-06 15:42:11.000000000 +0100 @@ -379,6 +379,7 @@ #define SC_TOP_LEFT 0x16EC #define SC_BOTTOM_RIGHT 0x16F0 #define SRC_SC_BOTTOM_RIGHT 0x16F4 +#define RB2D_DSTCACHE_MODE 0x3428 #define RB2D_DSTCACHE_CTLSTAT 0x342C #define LVDS_GEN_CNTL 0x02d0 #define LVDS_PLL_CNTL 0x02d4 @@ -395,6 +396,7 @@ #define RADEON_BIOS_6_SCRATCH 0x0028 #define RADEON_BIOS_7_SCRATCH 0x002c +#define HDP_SOFT_RESET (1 << 26) #define CLK_PIN_CNTL 0x0001 #define PPLL_CNTL 0x0002 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/binfmt_elf.c linux.20pre2-ac1/fs/binfmt_elf.c --- linux.20pre2/fs/binfmt_elf.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/binfmt_elf.c 2002-08-06 15:41:51.000000000 +0100 @@ -1143,7 +1143,7 @@ psinfo.pr_state = i; psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; - psinfo.pr_nice = current->nice; + psinfo.pr_nice = task_nice(current); psinfo.pr_flag = current->flags; psinfo.pr_uid = NEW_TO_OLD_UID(current->uid); psinfo.pr_gid = NEW_TO_OLD_GID(current->gid); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/buffer.c linux.20pre2-ac1/fs/buffer.c --- linux.20pre2/fs/buffer.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/buffer.c 2002-08-13 15:22:54.000000000 +0100 @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -323,7 +324,7 @@ lock_kernel(); sync_inodes_sb(sb); - DQUOT_SYNC(dev); + DQUOT_SYNC_SB(sb); lock_super(sb); if (sb->s_dirt && sb->s_op && sb->s_op->write_super) sb->s_op->write_super(sb); @@ -345,7 +346,7 @@ lock_kernel(); sync_inodes(dev); - DQUOT_SYNC(dev); + DQUOT_SYNC_DEV(dev); sync_supers(dev); unlock_kernel(); @@ -586,9 +587,10 @@ void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode) { spin_lock(&lru_list_lock); - if (bh->b_inode) + if (buffer_inode(bh)) list_del(&bh->b_inode_buffers); - bh->b_inode = inode; + else + set_buffer_inode(bh); list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers); spin_unlock(&lru_list_lock); } @@ -596,9 +598,10 @@ void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode) { spin_lock(&lru_list_lock); - if (bh->b_inode) + if (buffer_inode(bh)) list_del(&bh->b_inode_buffers); - bh->b_inode = inode; + else + set_buffer_inode(bh); list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers); spin_unlock(&lru_list_lock); } @@ -607,13 +610,13 @@ remove_inode_queue functions. */ static void __remove_inode_queue(struct buffer_head *bh) { - bh->b_inode = NULL; + clear_buffer_inode(bh); list_del(&bh->b_inode_buffers); } static inline void remove_inode_queue(struct buffer_head *bh) { - if (bh->b_inode) + if (buffer_inode(bh)) __remove_inode_queue(bh); } @@ -731,8 +734,9 @@ { balance_dirty(); wakeup_bdflush(); - try_to_free_pages_nozone(GFP_NOIO); + try_to_free_pages(GFP_NOFS); run_task_queue(&tq_disk); + __set_current_state(TASK_RUNNING); yield(); } @@ -741,6 +745,7 @@ bh->b_list = BUF_CLEAN; bh->b_end_io = handler; bh->b_private = private; + bh->b_journal_head = NULL; } static void end_buffer_io_async(struct buffer_head * bh, int uptodate) @@ -838,9 +843,9 @@ bh = BH_ENTRY(list->next); list_del(&bh->b_inode_buffers); if (!buffer_dirty(bh) && !buffer_locked(bh)) - bh->b_inode = NULL; + clear_buffer_inode(bh); else { - bh->b_inode = &tmp; + set_buffer_inode(bh); list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers); if (buffer_dirty(bh)) { get_bh(bh); @@ -953,10 +958,8 @@ struct buffer_head * bh; bh = get_hash_table(dev, block, size); - if (bh) { - touch_buffer(bh); + if (bh) return bh; - } if (!grow_buffers(dev, block, size)) free_more_memory(); @@ -1119,6 +1122,7 @@ struct buffer_head * bh; bh = getblk(dev, block, size); + touch_buffer(bh); if (buffer_uptodate(bh)) return bh; ll_rw_block(READ, 1, &bh); @@ -1134,7 +1138,7 @@ */ static void __put_unused_buffer_head(struct buffer_head * bh) { - if (bh->b_inode) + if (buffer_inode(bh)) BUG(); if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) { kmem_cache_free(bh_cachep, bh); @@ -1748,9 +1752,14 @@ } /* Stage 3: start the IO */ - for (i = 0; i < nr; i++) - submit_bh(READ, arr[i]); - + for (i = 0; i < nr; i++) { + struct buffer_head * bh = arr[i]; + if (buffer_uptodate(bh)) + end_buffer_io_async(bh, 1); + else + submit_bh(READ, bh); + } + return 0; } @@ -2165,11 +2174,10 @@ err = 0; for (i = nr; --i >= 0; ) { - iosize += size; tmp = bh[i]; - if (buffer_locked(tmp)) { + if (buffer_locked(tmp)) wait_on_buffer(tmp); - } + iosize += tmp->b_size; if (!buffer_uptodate(tmp)) { /* We are traversing bh'es in reverse order so @@ -2211,6 +2219,7 @@ struct kiobuf * iobuf = NULL; struct page * map; struct buffer_head *tmp, **bhs = NULL; + int iosize = size; if (!nr) return 0; @@ -2247,7 +2256,7 @@ } while (length > 0) { - blocknr = b[bufind++]; + blocknr = b[bufind]; if (blocknr == -1UL) { if (rw == READ) { /* there was an hole in the filesystem */ @@ -2260,9 +2269,15 @@ } else BUG(); } + if (iobuf->dovary && (offset == 0)) { + iosize = RAWIO_BLOCKSIZE; + if (iosize > length) + iosize = length; + } + bufind += (iosize/size); tmp = bhs[bhind++]; - tmp->b_size = size; + tmp->b_size = iosize; set_bh_page(tmp, map, offset); tmp->b_this_page = tmp; @@ -2278,7 +2293,10 @@ set_bit(BH_Uptodate, &tmp->b_state); atomic_inc(&iobuf->io_count); - submit_bh(rw, tmp); + if (iobuf->dovary) + submit_bh_blknr(rw, tmp); + else + submit_bh(rw, tmp); /* * Wait for IO if we have got too much */ @@ -2293,8 +2311,8 @@ } skip_block: - length -= size; - offset += size; + length -= iosize; + offset += iosize; if (offset >= PAGE_SIZE) { offset = 0; @@ -2525,63 +2543,23 @@ return 1; } -/* - * The first time the VM inspects a page which has locked buffers, it - * will just mark it as needing waiting upon on the scan of the page LRU. - * BH_Wait_IO is used for this. - * - * The second time the VM visits the page, if it still has locked - * buffers, it is time to start writing them out. (BH_Wait_IO was set). - * - * The third time the VM visits the page, if the I/O hasn't completed - * then it's time to wait upon writeout. BH_Lock and BH_Launder are - * used for this. - * - * There is also the case of buffers which were locked by someone else - * - write(2) callers, bdflush, etc. There can be a huge number of these - * and we don't want to just skip them all and fail the page allocation. - * We want to be able to wait on these buffers as well. - * - * The BH_Launder bit is set in submit_bh() to indicate that I/O is - * underway against the buffer, doesn't matter who started it - we know - * that the buffer will eventually come unlocked, and so it's safe to - * wait on it. - * - * The caller holds the page lock and the caller will free this page - * into current->local_page, so by waiting on the page's buffers the - * caller is guaranteed to obtain this page. - * - * sync_page_buffers() will sort-of return true if all the buffers - * against this page are freeable, so try_to_free_buffers() should - * try to free the page's buffers a second time. This is a bit - * broken for blocksize < PAGE_CACHE_SIZE, but not very importantly. - */ -static int sync_page_buffers(struct buffer_head *head) +static void sync_page_buffers(struct buffer_head *head) { struct buffer_head * bh = head; - int tryagain = 1; do { if (!buffer_dirty(bh) && !buffer_locked(bh)) continue; /* Don't start IO first time around.. */ - if (!test_and_set_bit(BH_Wait_IO, &bh->b_state)) { - tryagain = 0; + if (!test_and_set_bit(BH_Wait_IO, &bh->b_state)) continue; - } - /* Second time through we start actively writing out.. */ - if (test_and_set_bit(BH_Lock, &bh->b_state)) { - if (unlikely(!buffer_launder(bh))) { - tryagain = 0; - continue; - } - wait_on_buffer(bh); - tryagain = 1; + /* If we cannot lock the buffer just skip it. */ + if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; - } + /* Second time through we start actively writing out.. */ if (!atomic_set_buffer_clean(bh)) { unlock_buffer(bh); continue; @@ -2591,10 +2569,9 @@ get_bh(bh); bh->b_end_io = end_buffer_io_sync; submit_bh(WRITE, bh); - tryagain = 0; } while ((bh = bh->b_this_page) != head); - return tryagain; + return; } /* @@ -2618,7 +2595,6 @@ { struct buffer_head * tmp, * bh = page->buffers; -cleaned_buffers_try_again: spin_lock(&lru_list_lock); write_lock(&hash_table_lock); tmp = bh; @@ -2661,15 +2637,9 @@ write_unlock(&hash_table_lock); spin_unlock(&lru_list_lock); gfp_mask = pf_gfp_mask(gfp_mask); - if (gfp_mask & __GFP_IO) { - if ((gfp_mask & __GFP_HIGHIO) || !PageHighMem(page)) { - if (sync_page_buffers(bh)) { - /* no IO or waiting next time */ - gfp_mask = 0; - goto cleaned_buffers_try_again; - } - } - } + if ((gfp_mask & __GFP_IO) && + ((gfp_mask & __GFP_HIGHIO) || !PageHighMem(page))) + sync_page_buffers(bh); if (balance_dirty_state() >= 0) wakeup_bdflush(); return 0; @@ -2765,7 +2735,7 @@ hash_table = (struct buffer_head **) __get_free_pages(GFP_ATOMIC, order); } while (hash_table == NULL && --order > 0); - printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n", + printk(KERN_INFO "Buffer cache hash table entries: %d (order: %d, %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order)); if (!hash_table) @@ -2934,8 +2904,10 @@ break; ndirty -= NRSYNC; } - if (ndirty > 0 || bdflush_stop()) + if (ndirty > 0 || bdflush_stop()) { + run_task_queue(&tq_disk); interruptible_sleep_on(&bdflush_wait); + } } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/Config.in linux.20pre2-ac1/fs/Config.in --- linux.20pre2/fs/Config.in 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/Config.in 2002-08-13 15:23:38.000000000 +0100 @@ -5,6 +5,14 @@ comment 'File systems' bool 'Quota support' CONFIG_QUOTA +dep_tristate ' Old quota format support' CONFIG_QFMT_V1 $CONFIG_QUOTA +dep_tristate ' VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA +dep_mbool ' Compatible quota interfaces' CONFIG_QIFACE_COMPAT $CONFIG_QUOTA +if [ "$CONFIG_QUOTA" = "y" -a "$CONFIG_QIFACE_COMPAT" = "y" ]; then + choice ' Compatible quota interfaces' \ + "Original CONFIG_QIFACE_V1 \ + VFSv0 CONFIG_QIFACE_V2" Original +fi tristate 'Kernel automounter support' CONFIG_AUTOFS_FS tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS @@ -19,6 +27,9 @@ dep_tristate 'Apple Macintosh file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL +dep_tristate 'BeOS file systemv(BeFS) support (read only) (EXPERIMENTAL)' CONFIG_BEFS_FS $CONFIG_EXPERIMENTAL +dep_mbool ' Debug Befs' CONFIG_BEFS_DEBUG $CONFIG_BEFS_FS + dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL tristate 'Ext3 journalling file system support' CONFIG_EXT3_FS @@ -51,6 +62,10 @@ dep_mbool ' Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS dep_mbool ' Transparent decompression extension' CONFIG_ZISOFS $CONFIG_ISO9660_FS +tristate 'JFS filesystem support' CONFIG_JFS_FS +dep_mbool ' JFS debugging' CONFIG_JFS_DEBUG $CONFIG_JFS_FS +dep_mbool ' JFS statistics' CONFIG_JFS_STATISTICS $CONFIG_JFS_FS + tristate 'Minix fs support' CONFIG_MINIX_FS tristate 'FreeVxFS file system support (VERITAS VxFS(TM) compatible)' CONFIG_VXFS_FS @@ -99,6 +114,7 @@ dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET dep_mbool ' Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD + dep_mbool ' Provide NFS server over TCP support (EXPERIMENTAL)' CONFIG_NFSD_TCP $CONFIG_NFSD $CONFIG_EXPERIMENTAL if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then define_tristate CONFIG_SUNRPC y diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/dcache.c linux.20pre2-ac1/fs/dcache.c --- linux.20pre2/fs/dcache.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/dcache.c 2002-08-13 14:38:40.000000000 +0100 @@ -1283,6 +1283,7 @@ dcache_init(mempages); inode_init(mempages); + files_init(mempages); mnt_init(mempages); bdev_cache_init(); cdev_cache_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/dnotify.c linux.20pre2-ac1/fs/dnotify.c --- linux.20pre2/fs/dnotify.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/dnotify.c 2002-08-06 15:41:51.000000000 +0100 @@ -140,7 +140,7 @@ static int __init dnotify_init(void) { - dn_cache = kmem_cache_create("dnotify cache", + dn_cache = kmem_cache_create("dnotify_cache", sizeof(struct dnotify_struct), 0, 0, NULL, NULL); if (!dn_cache) panic("cannot create dnotify slab cache"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/dquot.c linux.20pre2-ac1/fs/dquot.c --- linux.20pre2/fs/dquot.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/dquot.c 2002-08-06 15:41:51.000000000 +0100 @@ -35,7 +35,7 @@ * Jan Kara, , sponsored by SuSE CR, 10-11/99 * * Used struct list_head instead of own list struct - * Invalidation of dquots with dq_count > 0 no longer possible + * Invalidation of referenced dquots is no longer possible * Improved free_dquots list management * Quota and i_blocks are now updated in one place to avoid races * Warnings are now delayed so we won't block in critical section @@ -45,6 +45,10 @@ * Added dynamic quota structure allocation * Jan Kara 12/2000 * + * Rewritten quota interface. Implemented new quota format and + * formats registering. + * Jan Kara, , 2001,2002 + * * (C) Copyright 1994 - 1997 Marco van Wieringen */ @@ -59,20 +63,53 @@ #include #include #include +#include #include #include +#include +#include #include -#define __DQUOT_VERSION__ "dquot_6.4.0" +static char *quotatypes[] = INITQFNAMES; +static struct quota_format_type *quota_formats; /* List of registered formats */ -int nr_dquots, nr_free_dquots; +int register_quota_format(struct quota_format_type *fmt) +{ + lock_kernel(); + fmt->qf_next = quota_formats; + quota_formats = fmt; + unlock_kernel(); + return 0; +} -static char *quotatypes[] = INITQFNAMES; +void unregister_quota_format(struct quota_format_type *fmt) +{ + struct quota_format_type **actqf; -static inline struct quota_mount_options *sb_dqopt(struct super_block *sb) + lock_kernel(); + for (actqf = "a_formats; *actqf && *actqf != fmt; actqf = &(*actqf)->qf_next); + if (*actqf) + *actqf = (*actqf)->qf_next; + unlock_kernel(); +} + +static struct quota_format_type *find_quota_format(int id) { - return &sb->s_dquot; + struct quota_format_type *actqf; + + lock_kernel(); + for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); + if (actqf && !try_inc_mod_count(actqf->qf_owner)) + actqf = NULL; + unlock_kernel(); + return actqf; +} + +static void put_quota_format(struct quota_format_type *fmt) +{ + if (fmt->qf_owner) + __MOD_DEC_USE_COUNT(fmt->qf_owner); } /* @@ -85,11 +122,11 @@ * list is used for the sync and invalidate operations, which must look * at every dquot. * - * Unused dquots (dq_count == 0) are added to the free_dquots list when - * freed, and this list is searched whenever we need an available dquot. - * Dquots are removed from the list as soon as they are used again, and - * nr_free_dquots gives the number of dquots on the list. When dquot is - * invalidated it's completely released from memory. + * Unused dquots (dq_count == 0) are added to the free_dquots list when freed, + * and this list is searched whenever we need an available dquot. Dquots are + * removed from the list as soon as they are used again, and + * dqstats.free_dquots gives the number of dquots on the list. When + * dquot is invalidated it's completely released from memory. * * Dquots with a specific identity (device, type and id) are placed on * one of the dquot_hash[] hash chains. The provides an efficient search @@ -115,35 +152,39 @@ static LIST_HEAD(free_dquots); static struct list_head dquot_hash[NR_DQHASH]; -static struct dqstats dqstats; +struct dqstats dqstats; static void dqput(struct dquot *); static struct dquot *dqduplicate(struct dquot *); -static inline char is_enabled(struct quota_mount_options *dqopt, short type) +static inline void get_dquot_ref(struct dquot *dquot) { - switch (type) { - case USRQUOTA: - return((dqopt->flags & DQUOT_USR_ENABLED) != 0); - case GRPQUOTA: - return((dqopt->flags & DQUOT_GRP_ENABLED) != 0); - } - return(0); + dquot->dq_count++; +} + +static inline void put_dquot_ref(struct dquot *dquot) +{ + dquot->dq_count--; +} + +static inline void get_dquot_dup_ref(struct dquot *dquot) +{ + dquot->dq_dup_ref++; } -static inline char sb_has_quota_enabled(struct super_block *sb, short type) +static inline void put_dquot_dup_ref(struct dquot *dquot) { - return is_enabled(sb_dqopt(sb), type); + dquot->dq_dup_ref--; } -static inline int const hashfn(kdev_t dev, unsigned int id, short type) +static inline int const hashfn(struct super_block *sb, unsigned int id, int type) { - return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; + return((((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; } static inline void insert_dquot_hash(struct dquot *dquot) { - struct list_head *head = dquot_hash + hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type); + struct list_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); list_add(&dquot->dq_hash, head); } @@ -153,14 +194,14 @@ INIT_LIST_HEAD(&dquot->dq_hash); } -static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigned int id, short type) +static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type) { struct list_head *head; struct dquot *dquot; for (head = dquot_hash[hashent].next; head != dquot_hash+hashent; head = head->next) { dquot = list_entry(head, struct dquot, dq_hash); - if (dquot->dq_dev == dev && dquot->dq_id == id && dquot->dq_type == type) + if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type) return dquot; } return NODQUOT; @@ -170,14 +211,14 @@ static inline void put_dquot_head(struct dquot *dquot) { list_add(&dquot->dq_free, &free_dquots); - nr_free_dquots++; + dqstats.free_dquots++; } /* Add a dquot to the tail of the free list */ static inline void put_dquot_last(struct dquot *dquot) { list_add(&dquot->dq_free, free_dquots.prev); - nr_free_dquots++; + dqstats.free_dquots++; } /* Move dquot to the head of free list (it must be already on it) */ @@ -193,7 +234,7 @@ return; list_del(&dquot->dq_free); INIT_LIST_HEAD(&dquot->dq_free); - nr_free_dquots--; + dqstats.free_dquots--; } static inline void put_inuse(struct dquot *dquot) @@ -201,12 +242,12 @@ /* We add to the back of inuse list so we don't have to restart * when traversing this list and we block */ list_add(&dquot->dq_inuse, inuse_list.prev); - nr_dquots++; + dqstats.allocated_dquots++; } static inline void remove_inuse(struct dquot *dquot) { - nr_dquots--; + dqstats.allocated_dquots--; list_del(&dquot->dq_inuse); } @@ -243,6 +284,7 @@ wake_up(&dquot->dq_wait_lock); } +/* Wait for dquot to be unused */ static void __wait_dquot_unused(struct dquot *dquot) { DECLARE_WAITQUEUE(wait, current); @@ -258,85 +300,56 @@ current->state = TASK_RUNNING; } -/* - * We don't have to be afraid of deadlocks as we never have quotas on quota files... - */ -static void write_dquot(struct dquot *dquot) +/* Wait for all duplicated dquot references to be dropped */ +static void __wait_dup_drop(struct dquot *dquot) { - short type = dquot->dq_type; - struct file *filp; - mm_segment_t fs; - loff_t offset; - ssize_t ret; - struct semaphore *sem = &dquot->dq_sb->s_dquot.dqio_sem; - struct dqblk dqbuf; - - down(sem); - filp = dquot->dq_sb->s_dquot.files[type]; - offset = dqoff(dquot->dq_id); - fs = get_fs(); - set_fs(KERNEL_DS); + DECLARE_WAITQUEUE(wait, current); - /* - * Note: clear the DQ_MOD flag unconditionally, - * so we don't loop forever on failure. - */ - memcpy(&dqbuf, &dquot->dq_dqb, sizeof(struct dqblk)); - dquot->dq_flags &= ~DQ_MOD; - ret = 0; - if (filp) - ret = filp->f_op->write(filp, (char *)&dqbuf, - sizeof(struct dqblk), &offset); - if (ret != sizeof(struct dqblk)) - printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", - kdevname(dquot->dq_dev)); - - set_fs(fs); - up(sem); - dqstats.writes++; -} - -static void read_dquot(struct dquot *dquot) -{ - short type = dquot->dq_type; - struct file *filp; - mm_segment_t fs; - loff_t offset; + add_wait_queue(&dquot->dq_wait_free, &wait); +repeat: + set_current_state(TASK_UNINTERRUPTIBLE); + if (dquot->dq_dup_ref) { + schedule(); + goto repeat; + } + remove_wait_queue(&dquot->dq_wait_free, &wait); + current->state = TASK_RUNNING; +} - filp = dquot->dq_sb->s_dquot.files[type]; - if (filp == (struct file *)NULL) - return; +static int read_dqblk(struct dquot *dquot) +{ + int ret; + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); lock_dquot(dquot); - if (!dquot->dq_sb) /* Invalidated quota? */ - goto out_lock; - /* Now we are sure filp is valid - the dquot isn't invalidated */ - down(&dquot->dq_sb->s_dquot.dqio_sem); - offset = dqoff(dquot->dq_id); - fs = get_fs(); - set_fs(KERNEL_DS); - filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset); - up(&dquot->dq_sb->s_dquot.dqio_sem); - set_fs(fs); - - if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 && - dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0) - dquot->dq_flags |= DQ_FAKE; - dqstats.reads++; -out_lock: + down(&dqopt->dqio_sem); + ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot); + up(&dqopt->dqio_sem); unlock_dquot(dquot); + return ret; +} + +static int commit_dqblk(struct dquot *dquot) +{ + int ret; + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + + down(&dqopt->dqio_sem); + ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); + up(&dqopt->dqio_sem); + return ret; } /* Invalidate all dquots on the list, wait for all users. Note that this function is called * after quota is disabled so no new quota might be created. As we only insert to the end of * inuse list, we don't have to restart searching... */ -static void invalidate_dquots(struct super_block *sb, short type) +static void invalidate_dquots(struct super_block *sb, int type) { struct dquot *dquot; struct list_head *head; restart: - for (head = inuse_list.next; head != &inuse_list; head = head->next) { + list_for_each(head, &inuse_list) { dquot = list_entry(head, struct dquot, dq_inuse); if (dquot->dq_sb != sb) continue; @@ -359,37 +372,107 @@ } } -int sync_dquots(kdev_t dev, short type) +static int vfs_quota_sync(struct super_block *sb, int type) { struct list_head *head; struct dquot *dquot; + struct quota_info *dqopt = sb_dqopt(sb); + int cnt; - lock_kernel(); restart: - for (head = inuse_list.next; head != &inuse_list; head = head->next) { + list_for_each(head, &inuse_list) { dquot = list_entry(head, struct dquot, dq_inuse); - if (dev && dquot->dq_dev != dev) + if (sb && dquot->dq_sb != sb) continue; if (type != -1 && dquot->dq_type != type) continue; if (!dquot->dq_sb) /* Invalidated? */ continue; - if (!(dquot->dq_flags & (DQ_MOD | DQ_LOCKED))) + if (!dquot_dirty(dquot) && !(dquot->dq_flags & DQ_LOCKED)) continue; - /* Raise use count so quota won't be invalidated. We can't use dqduplicate() as it does too many tests */ - dquot->dq_count++; + /* Get reference to quota so it won't be invalidated. get_dquot_ref() + * is enough since if dquot is locked/modified it can't be + * on the free list */ + get_dquot_ref(dquot); if (dquot->dq_flags & DQ_LOCKED) wait_on_dquot(dquot); - if (dquot->dq_flags & DQ_MOD) - write_dquot(dquot); + if (dquot_dirty(dquot)) + commit_dqblk(dquot); dqput(dquot); goto restart; } + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt)) + dqopt->info[cnt].dqi_flags &= ~DQF_ANY_DQUOT_DIRTY; + for (cnt = 0; cnt < MAXQUOTAS; cnt++) + if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt])) + dqopt->ops[cnt]->write_file_info(sb, cnt); dqstats.syncs++; - unlock_kernel(); + return 0; } +static struct super_block *get_super_to_sync(int type) +{ + struct list_head *head; + int cnt, dirty; + +restart: + spin_lock(&sb_lock); + list_for_each(head, &super_blocks) { + struct super_block *sb = list_entry(head, struct super_block, s_list); + + for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) + if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) + && sb_dqopt(sb)->info[cnt].dqi_flags & DQF_ANY_DQUOT_DIRTY) + dirty = 1; + if (!dirty) + continue; + sb->s_count++; + spin_unlock(&sb_lock); + down_read(&sb->s_umount); + if (!sb->s_root) { + drop_super(sb); + goto restart; + } + return sb; + } + spin_unlock(&sb_lock); + return NULL; +} + +void sync_dquots_dev(kdev_t dev, int type) +{ + struct super_block *sb; + + if (dev) { + if ((sb = get_super(dev))) { + lock_kernel(); + if (sb->s_qcop->quota_sync) + sb->s_qcop->quota_sync(sb, type); + unlock_kernel(); + drop_super(sb); + } + } + else { + while ((sb = get_super_to_sync(type))) { + lock_kernel(); + if (sb->s_qcop->quota_sync) + sb->s_qcop->quota_sync(sb, type); + unlock_kernel(); + drop_super(sb); + } + } +} + +void sync_dquots_sb(struct super_block *sb, int type) +{ + lock_kernel(); + if (sb->s_qcop->quota_sync) + sb->s_qcop->quota_sync(sb, type); + unlock_kernel(); +} + /* Free unused dquots from cache */ static void prune_dqcache(int count) { @@ -408,19 +491,38 @@ } } +/* + * This is called from kswapd when we think we need some + * more memory, but aren't really sure how much. So we + * carefully try to free a _bit_ of our dqcache, but not + * too much. + * + * Priority: + * 1 - very urgent: shrink everything + * ... + * 6 - base-level: try to shrink a bit. + */ + int shrink_dqcache_memory(int priority, unsigned int gfp_mask) { + int count = 0; + lock_kernel(); - prune_dqcache(nr_free_dquots / (priority + 1)); + count = dqstats.free_dquots / priority; + prune_dqcache(count); unlock_kernel(); return kmem_cache_shrink(dquot_cachep); } -/* NOTE: If you change this function please check whether dqput_blocks() works right... */ +/* + * Put reference to dquot + * NOTE: If you change this function please check whether dqput_blocks() works right... + */ static void dqput(struct dquot *dquot) { if (!dquot) return; +#ifdef __DQUOT_PARANOIA if (!dquot->dq_count) { printk("VFS: dqput: trying to free free dquot\n"); printk("VFS: device %s, dquot of %s %d\n", @@ -428,33 +530,38 @@ dquot->dq_id); return; } +#endif dqstats.drops++; we_slept: + if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) { /* Last unduplicated reference? */ + __wait_dup_drop(dquot); + goto we_slept; + } if (dquot->dq_count > 1) { /* We have more than one user... We can simply decrement use count */ - dquot->dq_count--; + put_dquot_ref(dquot); return; } - if (dquot->dq_flags & DQ_MOD) { - write_dquot(dquot); + if (dquot_dirty(dquot)) { + commit_dqblk(dquot); goto we_slept; } /* sanity check */ if (!list_empty(&dquot->dq_free)) { printk(KERN_ERR "dqput: dquot already on free list??\n"); - dquot->dq_count--; /* J.K. Just decrementing use count seems safer... */ + put_dquot_ref(dquot); return; } - dquot->dq_count--; + put_dquot_ref(dquot); /* If dquot is going to be invalidated invalidate_dquots() is going to free it so */ if (!(dquot->dq_flags & DQ_INVAL)) put_dquot_last(dquot); /* Place at end of LRU free queue */ wake_up(&dquot->dq_wait_free); } -static struct dquot *get_empty_dquot(void) +static struct dquot *get_empty_dquot(struct super_block *sb, int type) { struct dquot *dquot; @@ -468,6 +575,9 @@ INIT_LIST_HEAD(&dquot->dq_free); INIT_LIST_HEAD(&dquot->dq_inuse); INIT_LIST_HEAD(&dquot->dq_hash); + dquot->dq_sb = sb; + dquot->dq_dev = sb->s_dev; + dquot->dq_type = type; dquot->dq_count = 1; /* all dquots go on the inuse_list */ put_inuse(dquot); @@ -475,11 +585,11 @@ return dquot; } -static struct dquot *dqget(struct super_block *sb, unsigned int id, short type) +static struct dquot *dqget(struct super_block *sb, unsigned int id, int type) { - unsigned int hashent = hashfn(sb->s_dev, id, type); + unsigned int hashent = hashfn(sb, id, type); struct dquot *dquot, *empty = NODQUOT; - struct quota_mount_options *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = sb_dqopt(sb); we_slept: if (!is_enabled(dqopt, type)) { @@ -488,23 +598,21 @@ return NODQUOT; } - if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NODQUOT) { + if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { if (empty == NODQUOT) { - if ((empty = get_empty_dquot()) == NODQUOT) + if ((empty = get_empty_dquot(sb, type)) == NODQUOT) schedule(); /* Try to wait for a moment... */ goto we_slept; } dquot = empty; - dquot->dq_id = id; - dquot->dq_type = type; - dquot->dq_dev = sb->s_dev; - dquot->dq_sb = sb; + dquot->dq_id = id; /* hash it first so it can be found */ insert_dquot_hash(dquot); - read_dquot(dquot); + read_dqblk(dquot); } else { - if (!dquot->dq_count++) + if (!dquot->dq_count) remove_free_dquot(dquot); + get_dquot_ref(dquot); dqstats.cache_hits++; wait_on_dquot(dquot); if (empty) @@ -516,30 +624,47 @@ dqput(dquot); return NODQUOT; } - dquot->dq_referenced++; + ++dquot->dq_referenced; dqstats.lookups++; return dquot; } +/* Duplicate reference to dquot got from inode */ static struct dquot *dqduplicate(struct dquot *dquot) { if (dquot == NODQUOT) return NODQUOT; - dquot->dq_count++; + get_dquot_ref(dquot); if (!dquot->dq_sb) { printk(KERN_ERR "VFS: dqduplicate(): Invalidated quota to be duplicated!\n"); - dquot->dq_count--; + put_dquot_ref(dquot); return NODQUOT; } if (dquot->dq_flags & DQ_LOCKED) printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n"); + get_dquot_dup_ref(dquot); dquot->dq_referenced++; dqstats.lookups++; + return dquot; } -static int dqinit_needed(struct inode *inode, short type) +/* Put duplicated reference */ +static void dqputduplicate(struct dquot *dquot) +{ + if (!dquot->dq_dup_ref) { + printk(KERN_ERR "VFS: dqputduplicate(): Duplicated dquot put without duplicate reference.\n"); + return; + } + put_dquot_dup_ref(dquot); + if (!dquot->dq_dup_ref) + wake_up(&dquot->dq_wait_free); + put_dquot_ref(dquot); + dqstats.drops++; +} + +static int dqinit_needed(struct inode *inode, int type) { int cnt; @@ -553,16 +678,13 @@ return 0; } -static void add_dquot_ref(struct super_block *sb, short type) +static void add_dquot_ref(struct super_block *sb, int type) { struct list_head *p; - if (!sb->dq_op) - return; /* nothing to do */ - restart: file_list_lock(); - for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + list_for_each(p, &sb->s_files) { struct file *filp = list_entry(p, struct file, f_list); struct inode *inode = filp->f_dentry->d_inode; if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) { @@ -582,13 +704,15 @@ /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ static inline int dqput_blocks(struct dquot *dquot) { - if (dquot->dq_count == 1) + if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) + return 1; + if (dquot->dq_count <= 1 && dquot->dq_flags & DQ_MOD) return 1; return 0; } /* Remove references to dquots from inode - add dquot to list for freeing if needed */ -int remove_inode_dquot_ref(struct inode *inode, short type, struct list_head *tofree_head) +int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head) { struct dquot *dquot = inode->i_dquot[type]; int cnt; @@ -635,38 +759,38 @@ static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) { - dquot->dq_curinodes += number; - dquot->dq_flags |= DQ_MOD; + dquot->dq_dqb.dqb_curinodes += number; + mark_dquot_dirty(dquot); } -static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number) +static inline void dquot_incr_space(struct dquot *dquot, qsize_t number) { - dquot->dq_curblocks += number; - dquot->dq_flags |= DQ_MOD; + dquot->dq_dqb.dqb_curspace += number; + mark_dquot_dirty(dquot); } static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number) { - if (dquot->dq_curinodes > number) - dquot->dq_curinodes -= number; + if (dquot->dq_dqb.dqb_curinodes > number) + dquot->dq_dqb.dqb_curinodes -= number; else - dquot->dq_curinodes = 0; - if (dquot->dq_curinodes < dquot->dq_isoftlimit) - dquot->dq_itime = (time_t) 0; + dquot->dq_dqb.dqb_curinodes = 0; + if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit) + dquot->dq_dqb.dqb_itime = (time_t) 0; dquot->dq_flags &= ~DQ_INODES; - dquot->dq_flags |= DQ_MOD; + mark_dquot_dirty(dquot); } -static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number) +static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) { - if (dquot->dq_curblocks > number) - dquot->dq_curblocks -= number; + if (dquot->dq_dqb.dqb_curspace > number) + dquot->dq_dqb.dqb_curspace -= number; else - dquot->dq_curblocks = 0; - if (dquot->dq_curblocks < dquot->dq_bsoftlimit) - dquot->dq_btime = (time_t) 0; + dquot->dq_dqb.dqb_curspace = 0; + if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit) + dquot->dq_dqb.dqb_btime = (time_t) 0; dquot->dq_flags &= ~DQ_BLKS; - dquot->dq_flags |= DQ_MOD; + mark_dquot_dirty(dquot); } static inline int need_print_warning(struct dquot *dquot, int flag) @@ -739,7 +863,10 @@ static inline char ignore_hardlimit(struct dquot *dquot) { - return capable(CAP_SYS_RESOURCE) && !dquot->dq_sb->s_dquot.rsquash[dquot->dq_type]; + struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type]; + + return capable(CAP_SYS_RESOURCE) && + (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & V1_DQF_RSQUASH)); } static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) @@ -748,60 +875,60 @@ if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) return QUOTA_OK; - if (dquot->dq_ihardlimit && - (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && + if (dquot->dq_dqb.dqb_ihardlimit && + (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit && !ignore_hardlimit(dquot)) { *warntype = IHARDWARN; return NO_QUOTA; } - if (dquot->dq_isoftlimit && - (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && - dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && + if (dquot->dq_dqb.dqb_isoftlimit && + (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && + dquot->dq_dqb.dqb_itime && CURRENT_TIME >= dquot->dq_dqb.dqb_itime && !ignore_hardlimit(dquot)) { *warntype = ISOFTLONGWARN; return NO_QUOTA; } - if (dquot->dq_isoftlimit && - (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && - dquot->dq_itime == 0) { + if (dquot->dq_dqb.dqb_isoftlimit && + (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && + dquot->dq_dqb.dqb_itime == 0) { *warntype = ISOFTWARN; - dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[dquot->dq_type]; + dquot->dq_dqb.dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; } return QUOTA_OK; } -static int check_bdq(struct dquot *dquot, ulong blocks, char prealloc, char *warntype) +static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) { *warntype = 0; - if (blocks <= 0 || dquot->dq_flags & DQ_FAKE) + if (space <= 0 || dquot->dq_flags & DQ_FAKE) return QUOTA_OK; - if (dquot->dq_bhardlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && + if (dquot->dq_dqb.dqb_bhardlimit && + toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit && !ignore_hardlimit(dquot)) { if (!prealloc) *warntype = BHARDWARN; return NO_QUOTA; } - if (dquot->dq_bsoftlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && - dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && + if (dquot->dq_dqb.dqb_bsoftlimit && + toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_btime && CURRENT_TIME >= dquot->dq_dqb.dqb_btime && !ignore_hardlimit(dquot)) { if (!prealloc) *warntype = BSOFTLONGWARN; return NO_QUOTA; } - if (dquot->dq_bsoftlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && - dquot->dq_btime == 0) { + if (dquot->dq_dqb.dqb_bsoftlimit && + toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_btime == 0) { if (!prealloc) { *warntype = BSOFTWARN; - dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[dquot->dq_type]; + dquot->dq_dqb.dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; } else /* @@ -815,148 +942,15 @@ } /* - * Initialize a dquot-struct with new quota info. This is used by the - * system call interface functions. - */ -static int set_dqblk(struct super_block *sb, int id, short type, int flags, struct dqblk *dqblk) -{ - struct dquot *dquot; - int error = -EFAULT; - struct dqblk dq_dqblk; - - if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk))) - return error; - - if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) { - /* We can't block while changing quota structure... */ - if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) { - dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit; - dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit; - dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit; - dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit; - } - - if ((flags & SET_QUOTA) || (flags & SET_USE)) { - if (dquot->dq_isoftlimit && - dquot->dq_curinodes < dquot->dq_isoftlimit && - dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit) - dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[type]; - dquot->dq_curinodes = dq_dqblk.dqb_curinodes; - if (dquot->dq_curinodes < dquot->dq_isoftlimit) - dquot->dq_flags &= ~DQ_INODES; - if (dquot->dq_bsoftlimit && - dquot->dq_curblocks < dquot->dq_bsoftlimit && - dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit) - dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[type]; - dquot->dq_curblocks = dq_dqblk.dqb_curblocks; - if (dquot->dq_curblocks < dquot->dq_bsoftlimit) - dquot->dq_flags &= ~DQ_BLKS; - } - - if (id == 0) { - dquot->dq_sb->s_dquot.block_expire[type] = dquot->dq_btime = dq_dqblk.dqb_btime; - dquot->dq_sb->s_dquot.inode_expire[type] = dquot->dq_itime = dq_dqblk.dqb_itime; - } - - if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 && - dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0) - dquot->dq_flags |= DQ_FAKE; - else - dquot->dq_flags &= ~DQ_FAKE; - - dquot->dq_flags |= DQ_MOD; - dqput(dquot); - } - return 0; -} - -static int get_quota(struct super_block *sb, int id, short type, struct dqblk *dqblk) -{ - struct dquot *dquot; - struct dqblk data; - int error = -ESRCH; - - if (!sb || !sb_has_quota_enabled(sb, type)) - goto out; - dquot = dqget(sb, id, type); - if (dquot == NODQUOT) - goto out; - - memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk)); /* We copy data to preserve them from changing */ - dqput(dquot); - error = -EFAULT; - if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct dqblk))) - error = 0; -out: - return error; -} - -static int get_stats(caddr_t addr) -{ - int error = -EFAULT; - struct dqstats stats; - - dqstats.allocated_dquots = nr_dquots; - dqstats.free_dquots = nr_free_dquots; - - /* make a copy, in case we page-fault in user space */ - memcpy(&stats, &dqstats, sizeof(struct dqstats)); - if (!copy_to_user(addr, &stats, sizeof(struct dqstats))) - error = 0; - return error; -} - -static int quota_root_squash(struct super_block *sb, short type, int *addr) -{ - int new_value, error; - - if (!sb) - return(-ENODEV); - - error = -EFAULT; - if (!copy_from_user(&new_value, addr, sizeof(int))) { - sb_dqopt(sb)->rsquash[type] = new_value; - error = 0; - } - return error; -} - -#if 0 /* We are not going to support filesystems without i_blocks... */ -/* - * This is a simple algorithm that calculates the size of a file in blocks. - * This is only used on filesystems that do not have an i_blocks count. - */ -static u_long isize_to_blocks(loff_t isize, size_t blksize_bits) -{ - u_long blocks; - u_long indirect; - - if (!blksize_bits) - blksize_bits = BLOCK_SIZE_BITS; - blocks = (isize >> blksize_bits) + ((isize & ~((1 << blksize_bits)-1)) ? 1 : 0); - if (blocks > 10) { - indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */ - if (blocks > (10 + 256)) { - indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */ - if (blocks > (10 + 256 + (256 << 8))) - indirect++; /* triple indirect blocks */ - } - blocks += indirect; - } - return blocks; -} -#endif - -/* * Externally referenced functions through dquot_operations in inode. * * Note: this is a blocking operation. */ -void dquot_initialize(struct inode *inode, short type) +void dquot_initialize(struct inode *inode, int type) { struct dquot *dquot[MAXQUOTAS]; unsigned int id = 0; - short cnt; + int cnt; if (IS_NOQUOTA(inode)) return; @@ -1002,7 +996,7 @@ void dquot_drop(struct inode *inode) { struct dquot *dquot; - short cnt; + int cnt; inode->i_flags &= ~S_QUOTA; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { @@ -1017,7 +1011,7 @@ /* * This operation can block, but only after everything is updated */ -int dquot_alloc_block(struct inode *inode, unsigned long number, char warn) +int dquot_alloc_space(struct inode *inode, qsize_t number, int warn) { int cnt, ret = NO_QUOTA; struct dquot *dquot[MAXQUOTAS]; @@ -1038,16 +1032,16 @@ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (dquot[cnt] == NODQUOT) continue; - dquot_incr_blocks(dquot[cnt], number); + dquot_incr_space(dquot[cnt], number); } - inode->i_blocks += number << (BLOCK_SIZE_BITS - 9); + inode_add_bytes(inode, number); /* NOBLOCK End */ ret = QUOTA_OK; warn_put_all: flush_warnings(dquot, warntype); for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (dquot[cnt] != NODQUOT) - dqput(dquot[cnt]); + dqputduplicate(dquot[cnt]); return ret; } @@ -1084,16 +1078,16 @@ flush_warnings(dquot, warntype); for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (dquot[cnt] != NODQUOT) - dqput(dquot[cnt]); + dqputduplicate(dquot[cnt]); return ret; } /* * This is a non-blocking operation. */ -void dquot_free_block(struct inode *inode, unsigned long number) +void dquot_free_space(struct inode *inode, qsize_t number) { - unsigned short cnt; + unsigned int cnt; struct dquot *dquot; /* NOBLOCK Start */ @@ -1101,10 +1095,10 @@ dquot = dqduplicate(inode->i_dquot[cnt]); if (dquot == NODQUOT) continue; - dquot_decr_blocks(dquot, number); - dqput(dquot); + dquot_decr_space(dquot, number); + dqputduplicate(dquot); } - inode->i_blocks -= number << (BLOCK_SIZE_BITS - 9); + inode_sub_bytes(inode, number); /* NOBLOCK End */ } @@ -1113,7 +1107,7 @@ */ void dquot_free_inode(const struct inode *inode, unsigned long number) { - unsigned short cnt; + unsigned int cnt; struct dquot *dquot; /* NOBLOCK Start */ @@ -1122,7 +1116,7 @@ if (dquot == NODQUOT) continue; dquot_decr_inodes(dquot, number); - dqput(dquot); + dqputduplicate(dquot); } /* NOBLOCK End */ } @@ -1134,7 +1128,7 @@ */ int dquot_transfer(struct inode *inode, struct iattr *iattr) { - unsigned long blocks; + qsize_t space; struct dquot *transfer_from[MAXQUOTAS]; struct dquot *transfer_to[MAXQUOTAS]; int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid, @@ -1164,7 +1158,7 @@ } } /* NOBLOCK START: From now on we shouldn't block */ - blocks = (inode->i_blocks >> 1); + space = inode_get_bytes(inode); /* Build the transfer_from list and check the limits */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { /* The second test can fail when quotaoff is in progress... */ @@ -1174,7 +1168,7 @@ if (transfer_from[cnt] == NODQUOT) /* Can happen on quotafiles (quota isn't initialized on them)... */ continue; if (check_idq(transfer_to[cnt], 1, warntype+cnt) == NO_QUOTA || - check_bdq(transfer_to[cnt], blocks, 0, warntype+cnt) == NO_QUOTA) + check_bdq(transfer_to[cnt], space, 0, warntype+cnt) == NO_QUOTA) goto warn_put_all; } @@ -1189,10 +1183,10 @@ continue; dquot_decr_inodes(transfer_from[cnt], 1); - dquot_decr_blocks(transfer_from[cnt], blocks); + dquot_decr_space(transfer_from[cnt], space); dquot_incr_inodes(transfer_to[cnt], 1); - dquot_incr_blocks(transfer_to[cnt], blocks); + dquot_incr_space(transfer_to[cnt], space); if (inode->i_dquot[cnt] == NODQUOT) BUG(); @@ -1208,39 +1202,29 @@ warn_put_all: flush_warnings(transfer_to, warntype); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + /* First we must put duplicate - otherwise we might deadlock */ if (transfer_to[cnt] != NODQUOT) - dqput(transfer_to[cnt]); + dqputduplicate(transfer_to[cnt]); if (transfer_from[cnt] != NODQUOT) dqput(transfer_from[cnt]); } return ret; } -static int __init dquot_init(void) -{ - int i; - - for (i = 0; i < NR_DQHASH; i++) - INIT_LIST_HEAD(dquot_hash + i); - printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__); - return 0; -} -__initcall(dquot_init); - /* * Definitions of diskquota operations. */ struct dquot_operations dquot_operations = { - dquot_initialize, /* mandatory */ - dquot_drop, /* mandatory */ - dquot_alloc_block, - dquot_alloc_inode, - dquot_free_block, - dquot_free_inode, - dquot_transfer + initialize: dquot_initialize, /* mandatory */ + drop: dquot_drop, /* mandatory */ + alloc_space: dquot_alloc_space, + alloc_inode: dquot_alloc_inode, + free_space: dquot_free_space, + free_inode: dquot_free_inode, + transfer: dquot_transfer }; -static inline void set_enable_flags(struct quota_mount_options *dqopt, short type) +static inline void set_enable_flags(struct quota_info *dqopt, int type) { switch (type) { case USRQUOTA: @@ -1252,7 +1236,7 @@ } } -static inline void reset_enable_flags(struct quota_mount_options *dqopt, short type) +static inline void reset_enable_flags(struct quota_info *dqopt, int type) { switch (type) { case USRQUOTA: @@ -1265,16 +1249,15 @@ } /* Function in inode.c - remove pointers to dquots in icache */ -extern void remove_dquot_ref(struct super_block *, short); +extern void remove_dquot_ref(struct super_block *, int); /* * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) */ -int quota_off(struct super_block *sb, short type) +int vfs_quota_off(struct super_block *sb, int type) { - struct file *filp; - short cnt; - struct quota_mount_options *dqopt = sb_dqopt(sb); + int cnt; + struct quota_info *dqopt = sb_dqopt(sb); lock_kernel(); if (!sb) @@ -1292,51 +1275,48 @@ /* Note: these are blocking operations */ remove_dquot_ref(sb, cnt); invalidate_dquots(sb, cnt); + if (info_dirty(&dqopt->info[cnt])) + dqopt->ops[cnt]->write_file_info(sb, cnt); + if (dqopt->ops[cnt]->free_file_info) + dqopt->ops[cnt]->free_file_info(sb, cnt); + put_quota_format(dqopt->info[cnt].dqi_format); - filp = dqopt->files[cnt]; + fput(dqopt->files[cnt]); dqopt->files[cnt] = (struct file *)NULL; - dqopt->inode_expire[cnt] = 0; - dqopt->block_expire[cnt] = 0; - fput(filp); - } + dqopt->info[cnt].dqi_flags = 0; + dqopt->info[cnt].dqi_igrace = 0; + dqopt->info[cnt].dqi_bgrace = 0; + dqopt->ops[cnt] = NULL; + } up(&dqopt->dqoff_sem); out: unlock_kernel(); return 0; } -static inline int check_quotafile_size(loff_t size) -{ - ulong blocks = size >> BLOCK_SIZE_BITS; - size_t off = size & (BLOCK_SIZE - 1); - - return !(((blocks % sizeof(struct dqblk)) * BLOCK_SIZE + off % sizeof(struct dqblk)) % sizeof(struct dqblk)); -} - -static int quota_on(struct super_block *sb, short type, char *path) +int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) { - struct file *f; + struct file *f = NULL; struct inode *inode; - struct dquot *dquot; - struct quota_mount_options *dqopt = sb_dqopt(sb); - char *tmp; + struct quota_info *dqopt = sb_dqopt(sb); + struct quota_format_type *fmt = find_quota_format(format_id); int error; - if (is_enabled(dqopt, type)) - return -EBUSY; + if (!fmt) + return -ESRCH; + if (is_enabled(dqopt, type)) { + error = -EBUSY; + goto out_fmt; + } down(&dqopt->dqoff_sem); - tmp = getname(path); - error = PTR_ERR(tmp); - if (IS_ERR(tmp)) - goto out_lock; - f = filp_open(tmp, O_RDWR, 0600); - putname(tmp); + f = filp_open(path, O_RDWR, 0600); error = PTR_ERR(f); if (IS_ERR(f)) goto out_lock; + dqopt->files[type] = f; error = -EIO; if (!f->f_op || !f->f_op->read || !f->f_op->write) goto out_f; @@ -1345,134 +1325,197 @@ if (!S_ISREG(inode->i_mode)) goto out_f; error = -EINVAL; - if (inode->i_size == 0 || !check_quotafile_size(inode->i_size)) + if (!fmt->qf_ops->check_quota_file(sb, type)) goto out_f; /* We don't want quota on quota files */ dquot_drop(inode); inode->i_flags |= S_NOQUOTA; - dqopt->files[type] = f; - sb->dq_op = &dquot_operations; + dqopt->ops[type] = fmt->qf_ops; + dqopt->info[type].dqi_format = fmt; + if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) + goto out_f; set_enable_flags(dqopt, type); - dquot = dqget(sb, 0, type); - dqopt->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME; - dqopt->block_expire[type] = (dquot != NODQUOT) ? dquot->dq_btime : MAX_DQ_TIME; - dqput(dquot); - add_dquot_ref(sb, type); up(&dqopt->dqoff_sem); return 0; out_f: - filp_close(f, NULL); + if (f) + filp_close(f, NULL); + dqopt->files[type] = NULL; out_lock: up(&dqopt->dqoff_sem); +out_fmt: + put_quota_format(fmt); return error; } -/* - * This is the system call interface. This communicates with - * the user-level programs. Currently this only supports diskquota - * calls. Maybe we need to add the process quotas etc. in the future, - * but we probably should use rlimits for that. - */ -asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) +/* Generic routine for getting common part of quota structure */ +static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) { - int cmds = 0, type = 0, flags = 0; - kdev_t dev; - struct super_block *sb = NULL; - int ret = -EINVAL; + struct mem_dqblk *dm = &dquot->dq_dqb; - lock_kernel(); - cmds = cmd >> SUBCMDSHIFT; - type = cmd & SUBCMDMASK; + di->dqb_bhardlimit = dm->dqb_bhardlimit; + di->dqb_bsoftlimit = dm->dqb_bsoftlimit; + di->dqb_curspace = dm->dqb_curspace; + di->dqb_ihardlimit = dm->dqb_ihardlimit; + di->dqb_isoftlimit = dm->dqb_isoftlimit; + di->dqb_curinodes = dm->dqb_curinodes; + di->dqb_btime = dm->dqb_btime; + di->dqb_itime = dm->dqb_itime; + di->dqb_valid = QIF_ALL; +} - if ((u_int) type >= MAXQUOTAS) - goto out; - if (id & ~0xFFFF) - goto out; +int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +{ + struct dquot *dquot = dqget(sb, id, type); - ret = -EPERM; - switch (cmds) { - case Q_SYNC: - case Q_GETSTATS: - break; - case Q_GETQUOTA: - if (((type == USRQUOTA && current->euid != id) || - (type == GRPQUOTA && !in_egroup_p(id))) && - !capable(CAP_SYS_ADMIN)) - goto out; - break; - default: - if (!capable(CAP_SYS_ADMIN)) - goto out; - } - - ret = -EINVAL; - dev = NODEV; - if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) { - mode_t mode; - struct nameidata nd; - - ret = user_path_walk(special, &nd); - if (ret) - goto out; - - dev = nd.dentry->d_inode->i_rdev; - mode = nd.dentry->d_inode->i_mode; - path_release(&nd); - - ret = -ENOTBLK; - if (!S_ISBLK(mode)) - goto out; - ret = -ENODEV; - sb = get_super(dev); - if (!sb) - goto out; - } - - ret = -EINVAL; - switch (cmds) { - case Q_QUOTAON: - ret = quota_on(sb, type, (char *) addr); - goto out; - case Q_QUOTAOFF: - ret = quota_off(sb, type); - goto out; - case Q_GETQUOTA: - ret = get_quota(sb, id, type, (struct dqblk *) addr); - goto out; - case Q_SETQUOTA: - flags |= SET_QUOTA; - break; - case Q_SETUSE: - flags |= SET_USE; - break; - case Q_SETQLIM: - flags |= SET_QLIMIT; - break; - case Q_SYNC: - ret = sync_dquots(dev, type); - goto out; - case Q_GETSTATS: - ret = get_stats(addr); - goto out; - case Q_RSQUASH: - ret = quota_root_squash(sb, type, (int *) addr); - goto out; - default: - goto out; - } - - ret = -NODEV; - if (sb && sb_has_quota_enabled(sb, type)) - ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr); -out: - if (sb) - drop_super(sb); - unlock_kernel(); - return ret; + if (!dquot) + return -EINVAL; + do_get_dqblk(dquot, di); + dqput(dquot); + return 0; +} + +/* Generic routine for setting common part of quota structure */ +static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) +{ + struct mem_dqblk *dm = &dquot->dq_dqb; + int check_blim = 0, check_ilim = 0; + + if (di->dqb_valid & QIF_SPACE) { + dm->dqb_curspace = di->dqb_curspace; + check_blim = 1; + } + if (di->dqb_valid & QIF_BLIMITS) { + dm->dqb_bsoftlimit = di->dqb_bsoftlimit; + dm->dqb_bhardlimit = di->dqb_bhardlimit; + check_blim = 1; + } + if (di->dqb_valid & QIF_INODES) { + dm->dqb_curinodes = di->dqb_curinodes; + check_ilim = 1; + } + if (di->dqb_valid & QIF_ILIMITS) { + dm->dqb_isoftlimit = di->dqb_isoftlimit; + dm->dqb_ihardlimit = di->dqb_ihardlimit; + check_ilim = 1; + } + if (di->dqb_valid & QIF_BTIME) + dm->dqb_btime = di->dqb_btime; + if (di->dqb_valid & QIF_ITIME) + dm->dqb_itime = di->dqb_itime; + + if (check_blim) { + if (!dm->dqb_bsoftlimit || toqb(dm->dqb_curspace) < dm->dqb_bsoftlimit) { + dm->dqb_btime = 0; + dquot->dq_flags &= ~DQ_BLKS; + } + else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */ + dm->dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; + } + if (check_ilim) { + if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) { + dm->dqb_itime = 0; + dquot->dq_flags &= ~DQ_INODES; + } + else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */ + dm->dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; + } + if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit) + dquot->dq_flags &= ~DQ_FAKE; + else + dquot->dq_flags |= DQ_FAKE; + dquot->dq_flags |= DQ_MOD; +} + +int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +{ + struct dquot *dquot = dqget(sb, id, type); + + if (!dquot) + return -EINVAL; + do_set_dqblk(dquot, di); + dqput(dquot); + return 0; +} + +/* Generic routine for getting common part of quota file information */ +int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +{ + struct mem_dqinfo *mi = sb_dqopt(sb)->info + type; + + ii->dqi_bgrace = mi->dqi_bgrace; + ii->dqi_igrace = mi->dqi_igrace; + ii->dqi_flags = mi->dqi_flags & DQF_MASK; + ii->dqi_valid = IIF_ALL; + return 0; +} + +/* Generic routine for setting common part of quota file information */ +int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +{ + struct mem_dqinfo *mi = sb_dqopt(sb)->info + type; + + if (ii->dqi_valid & IIF_BGRACE) + mi->dqi_bgrace = ii->dqi_bgrace; + if (ii->dqi_valid & IIF_IGRACE) + mi->dqi_igrace = ii->dqi_igrace; + if (ii->dqi_valid & IIF_FLAGS) + mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK); + mark_info_dirty(mi); + return 0; +} + +struct quotactl_ops vfs_quotactl_ops = { + quota_on: vfs_quota_on, + quota_off: vfs_quota_off, + quota_sync: vfs_quota_sync, + get_info: vfs_get_dqinfo, + set_info: vfs_set_dqinfo, + get_dqblk: vfs_get_dqblk, + set_dqblk: vfs_set_dqblk +}; + +static ctl_table fs_dqstats_table[] = { + {FS_DQ_LOOKUPS, "lookups", &dqstats.lookups, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_DROPS, "drops", &dqstats.drops, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_READS, "reads", &dqstats.reads, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_WRITES, "writes", &dqstats.writes, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_CACHE_HITS, "cache_hits", &dqstats.cache_hits, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_ALLOCATED, "allocated_dquots", &dqstats.allocated_dquots, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_FREE, "free_dquots", &dqstats.free_dquots, sizeof(int), 0444, NULL, &proc_dointvec}, + {FS_DQ_SYNCS, "syncs", &dqstats.syncs, sizeof(int), 0444, NULL, &proc_dointvec}, + {}, +}; + +static ctl_table fs_table[] = { + {FS_DQSTATS, "quota", NULL, 0, 0555, fs_dqstats_table}, + {}, +}; + +static ctl_table sys_table[] = { + {CTL_FS, "fs", NULL, 0, 0555, fs_table}, + {}, +}; + +static int __init dquot_init(void) +{ + int i; + + register_sysctl_table(sys_table, 0); + for (i = 0; i < NR_DQHASH; i++) + INIT_LIST_HEAD(dquot_hash + i); + printk(KERN_NOTICE "VFS: Disk quotas v%s\n", __DQUOT_VERSION__); + + return 0; } +__initcall(dquot_init); + +EXPORT_SYMBOL(register_quota_format); +EXPORT_SYMBOL(unregister_quota_format); +EXPORT_SYMBOL(dqstats); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/exec.c linux.20pre2-ac1/fs/exec.c --- linux.20pre2/fs/exec.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/exec.c 2002-08-06 15:41:51.000000000 +0100 @@ -35,6 +35,7 @@ #include #include #include +#include #define __NO_VERSION__ #include @@ -279,6 +280,7 @@ flush_dcache_page(page); flush_page_to_ram(page); set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY)))); + page_add_rmap(page, pte); tsk->mm->rss++; spin_unlock(&tsk->mm->page_table_lock); @@ -308,6 +310,12 @@ if (!mpnt) return -ENOMEM; + if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) + { + kmem_cache_free(vm_area_cachep, mpnt); + return -ENOMEM; + } + down_write(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; @@ -343,8 +351,7 @@ struct file *file; int err = 0; - if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) - err = path_walk(name, &nd); + err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd); file = ERR_PTR(err); if (!err) { inode = nd.dentry->d_inode; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ext2/balloc.c linux.20pre2-ac1/fs/ext2/balloc.c --- linux.20pre2/fs/ext2/balloc.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/ext2/balloc.c 2002-08-06 15:41:51.000000000 +0100 @@ -269,7 +269,8 @@ } lock_super (sb); es = sb->u.ext2_sb.s_es; - if (block < le32_to_cpu(es->s_first_data_block) || + if (block < le32_to_cpu(es->s_first_data_block) || + block + count < block || (block + count) > le32_to_cpu(es->s_blocks_count)) { ext2_error (sb, "ext2_free_blocks", "Freeing blocks not in datazone - " @@ -302,22 +303,20 @@ if (!gdp) goto error_return; - if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) || - in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) || - in_range (block, le32_to_cpu(gdp->bg_inode_table), - sb->u.ext2_sb.s_itb_per_group) || - in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table), - sb->u.ext2_sb.s_itb_per_group)) - ext2_error (sb, "ext2_free_blocks", - "Freeing blocks in system zones - " - "Block = %lu, count = %lu", - block, count); + for (i = 0; i < count; i++, block++) { + if (block == le32_to_cpu(gdp->bg_block_bitmap) || + block == le32_to_cpu(gdp->bg_inode_bitmap) || + in_range(block, le32_to_cpu(gdp->bg_inode_table), + EXT2_SB(sb)->s_itb_per_group)) { + ext2_error(sb, __FUNCTION__, + "Freeing block in system zone - block = %lu", + block); + continue; + } - for (i = 0; i < count; i++) { if (!ext2_clear_bit (bit + i, bh->b_data)) - ext2_error (sb, "ext2_free_blocks", - "bit already cleared for block %lu", - block + i); + ext2_error(sb, __FUNCTION__, + "bit already cleared for block %lu", block); else { DQUOT_FREE_BLOCK(inode, 1); gdp->bg_free_blocks_count = @@ -336,7 +335,6 @@ wait_on_buffer (bh); } if (overflow) { - block += count; count = overflow; goto do_more; } @@ -521,9 +519,14 @@ tmp == le32_to_cpu(gdp->bg_inode_bitmap) || in_range (tmp, le32_to_cpu(gdp->bg_inode_table), sb->u.ext2_sb.s_itb_per_group)) + { ext2_error (sb, "ext2_new_block", - "Allocating block in system zone - " - "block = %u", tmp); + "Allocating block in system zone - block = %u", + tmp); + ext2_set_bit(j, bh->b_data); + DQUOT_FREE_BLOCK(inode, 1); + goto repeat; + } if (ext2_set_bit (j, bh->b_data)) { ext2_warning (sb, "ext2_new_block", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ext2/super.c linux.20pre2-ac1/fs/ext2/super.c --- linux.20pre2/fs/ext2/super.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/ext2/super.c 2002-08-06 15:41:51.000000000 +0100 @@ -486,6 +486,9 @@ bdevname(dev), i); goto failed_mount; } + if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + ext2_warning(sb, __FUNCTION__, + "mounting ext3 filesystem as ext2\n"); sb->s_blocksize_bits = le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size) + 10; sb->s_blocksize = 1 << sb->s_blocksize_bits; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ext3/balloc.c linux.20pre2-ac1/fs/ext3/balloc.c --- linux.20pre2/fs/ext3/balloc.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/fs/ext3/balloc.c 2002-08-06 15:41:51.000000000 +0100 @@ -276,7 +276,8 @@ } lock_super (sb); es = sb->u.ext3_sb.s_es; - if (block < le32_to_cpu(es->s_first_data_block) || + if (block < le32_to_cpu(es->s_first_data_block) || + block + count < block || (block + count) > le32_to_cpu(es->s_blocks_count)) { ext3_error (sb, "ext3_free_blocks", "Freeing blocks not in datazone - " @@ -309,17 +310,6 @@ if (!gdp) goto error_return; - if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) || - in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) || - in_range (block, le32_to_cpu(gdp->bg_inode_table), - sb->u.ext3_sb.s_itb_per_group) || - in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table), - sb->u.ext3_sb.s_itb_per_group)) - ext3_error (sb, "ext3_free_blocks", - "Freeing blocks in system zones - " - "Block = %lu, count = %lu", - block, count); - /* * We are about to start releasing blocks in the bitmap, * so we need undo access. @@ -345,14 +335,24 @@ if (err) goto error_return; - for (i = 0; i < count; i++) { + for (i = 0; i < count; i++, block++) { + if (block == le32_to_cpu(gdp->bg_block_bitmap) || + block == le32_to_cpu(gdp->bg_inode_bitmap) || + in_range(block, le32_to_cpu(gdp->bg_inode_table), + sb->u.ext2_sb.s_itb_per_group)) { + ext3_error(sb, __FUNCTION__, + "Freeing block in system zone - block = %lu", + block); + continue; + } + /* * An HJ special. This is expensive... */ #ifdef CONFIG_JBD_DEBUG { struct buffer_head *debug_bh; - debug_bh = sb_get_hash_table(sb, block + i); + debug_bh = sb_get_hash_table(sb, block); if (debug_bh) { BUFFER_TRACE(debug_bh, "Deleted!"); if (!bh2jh(bitmap_bh)->b_committed_data) @@ -365,9 +365,8 @@ #endif BUFFER_TRACE(bitmap_bh, "clear bit"); if (!ext3_clear_bit (bit + i, bitmap_bh->b_data)) { - ext3_error (sb, __FUNCTION__, - "bit already cleared for block %lu", - block + i); + ext3_error(sb, __FUNCTION__, + "bit already cleared for block %lu", block); BUFFER_TRACE(bitmap_bh, "bit already cleared"); } else { dquot_freed_blocks++; @@ -415,7 +414,6 @@ if (!err) err = ret; if (overflow && !err) { - block += count; count = overflow; goto do_more; } @@ -576,6 +574,7 @@ ext3_debug ("goal=%lu.\n", goal); +repeat: /* * First, test whether the goal block is free. */ @@ -684,10 +683,21 @@ if (tmp == le32_to_cpu(gdp->bg_block_bitmap) || tmp == le32_to_cpu(gdp->bg_inode_bitmap) || in_range (tmp, le32_to_cpu(gdp->bg_inode_table), - sb->u.ext3_sb.s_itb_per_group)) - ext3_error (sb, "ext3_new_block", - "Allocating block in system zone - " - "block = %u", tmp); + EXT3_SB(sb)->s_itb_per_group)) { + ext3_error(sb, __FUNCTION__, + "Allocating block in system zone - block = %u", tmp); + + /* Note: This will potentially use up one of the handle's + * buffer credits. Normally we have way too many credits, + * so that is OK. In _very_ rare cases it might not be OK. + * We will trigger an assertion if we run out of credits, + * and we will have to do a full fsck of the filesystem - + * better than randomly corrupting filesystem metadata. + */ + ext3_set_bit(j, bh->b_data); + goto repeat; + } + /* The superblock lock should guard against anybody else beating * us to this point! */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ext3/file.c linux.20pre2-ac1/fs/ext3/file.c --- linux.20pre2/fs/ext3/file.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/fs/ext3/file.c 2002-08-06 15:41:51.000000000 +0100 @@ -61,19 +61,52 @@ static ssize_t ext3_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { + int ret, err; struct inode *inode = file->f_dentry->d_inode; - /* - * Nasty: if the file is subject to synchronous writes then we need - * to force generic_osync_inode() to call ext3_write_inode(). - * We do that by marking the inode dirty. This adds much more - * computational expense than we need, but we're going to sync - * anyway. - */ - if (IS_SYNC(inode) || (file->f_flags & O_SYNC)) - mark_inode_dirty(inode); + ret = generic_file_write(file, buf, count, ppos); - return generic_file_write(file, buf, count, ppos); + /* Skip file flushing code if there was an error, or if nothing + was written. */ + if (ret <= 0) + return ret; + + /* If the inode is IS_SYNC, or is O_SYNC and we are doing + data-journaling, then we need to make sure that we force the + transaction to disk to keep all metadata uptodate + synchronously. */ + + if (file->f_flags & O_SYNC) { + /* If we are non-data-journaled, then the dirty data has + already been flushed to backing store by + generic_osync_inode, and the inode has been flushed + too if there have been any modifications other than + mere timestamp updates. + + Open question --- do we care about flushing + timestamps too if the inode is IS_SYNC? */ + if (!ext3_should_journal_data(inode)) + return ret; + + goto force_commit; + } + + /* So we know that there has been no forced data flush. If the + inode is marked IS_SYNC, we need to force one ourselves. */ + if (!IS_SYNC(inode)) + return ret; + + /* Open question #2 --- should we force data to disk here too? + If we don't, the only impact is that data=writeback + filesystems won't flush data to disk automatically on + IS_SYNC, only metadata (but historically, that is what ext2 + has done.) */ + +force_commit: + err = ext3_force_commit(inode->i_sb); + if (err) + return err; + return ret; } struct file_operations ext3_file_operations = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ext3/fsync.c linux.20pre2-ac1/fs/ext3/fsync.c --- linux.20pre2/fs/ext3/fsync.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/fs/ext3/fsync.c 2002-08-06 15:41:51.000000000 +0100 @@ -62,7 +62,12 @@ * we'll end up waiting on them in commit. */ ret = fsync_inode_buffers(inode); - ret |= fsync_inode_data_buffers(inode); + + /* In writeback node, we need to force out data buffers too. In + * the other modes, ext3_force_commit takes care of forcing out + * just the right data blocks. */ + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) + ret |= fsync_inode_data_buffers(inode); ext3_force_commit(inode->i_sb); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ext3/ialloc.c linux.20pre2-ac1/fs/ext3/ialloc.c --- linux.20pre2/fs/ext3/ialloc.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/fs/ext3/ialloc.c 2002-08-06 15:41:51.000000000 +0100 @@ -392,7 +392,7 @@ err = -ENOSPC; if (!gdp) - goto fail; + goto out; err = -EIO; bitmap_nr = load_inode_bitmap (sb, i); @@ -523,9 +523,10 @@ return inode; fail: + ext3_std_error(sb, err); +out: unlock_super(sb); iput(inode); - ext3_std_error(sb, err); return ERR_PTR(err); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ext3/inode.c linux.20pre2-ac1/fs/ext3/inode.c --- linux.20pre2/fs/ext3/inode.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/ext3/inode.c 2002-08-13 17:22:20.000000000 +0100 @@ -412,6 +412,7 @@ return NULL; changed: + brelse(bh); *err = -EAGAIN; goto no_block; failure: @@ -948,11 +949,13 @@ } static int walk_page_buffers( handle_t *handle, + struct inode *inode, struct buffer_head *head, unsigned from, unsigned to, int *partial, int (*fn)( handle_t *handle, + struct inode *inode, struct buffer_head *bh)) { struct buffer_head *bh; @@ -970,7 +973,7 @@ *partial = 1; continue; } - err = (*fn)(handle, bh); + err = (*fn)(handle, inode, bh); if (!ret) ret = err; } @@ -1003,7 +1006,7 @@ * write. */ -static int do_journal_get_write_access(handle_t *handle, +static int do_journal_get_write_access(handle_t *handle, struct inode *inode, struct buffer_head *bh) { return ext3_journal_get_write_access(handle, bh); @@ -1029,7 +1032,7 @@ goto prepare_write_failed; if (ext3_should_journal_data(inode)) { - ret = walk_page_buffers(handle, page->buffers, + ret = walk_page_buffers(handle, inode, page->buffers, from, to, NULL, do_journal_get_write_access); if (ret) { /* @@ -1050,24 +1053,32 @@ return ret; } -static int journal_dirty_sync_data(handle_t *handle, struct buffer_head *bh) +static int journal_dirty_sync_data(handle_t *handle, struct inode *inode, + struct buffer_head *bh) { - return ext3_journal_dirty_data(handle, bh, 0); + int ret = ext3_journal_dirty_data(handle, bh, 0); + if (!buffer_inode(bh)) + buffer_insert_inode_data_queue(bh, inode); + return ret; } /* * For ext3_writepage(). We also brelse() the buffer to account for * the bget() which ext3_writepage() performs. */ -static int journal_dirty_async_data(handle_t *handle, struct buffer_head *bh) +static int journal_dirty_async_data(handle_t *handle, struct inode *inode, + struct buffer_head *bh) { int ret = ext3_journal_dirty_data(handle, bh, 1); + if (!buffer_inode(bh)) + buffer_insert_inode_data_queue(bh, inode); __brelse(bh); return ret; } /* For commit_write() in data=journal mode */ -static int commit_write_fn(handle_t *handle, struct buffer_head *bh) +static int commit_write_fn(handle_t *handle, struct inode *inode, + struct buffer_head *bh) { set_bit(BH_Uptodate, &bh->b_state); return ext3_journal_dirty_metadata(handle, bh); @@ -1102,7 +1113,7 @@ int partial = 0; loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - ret = walk_page_buffers(handle, page->buffers, + ret = walk_page_buffers(handle, inode, page->buffers, from, to, &partial, commit_write_fn); if (!partial) SetPageUptodate(page); @@ -1112,7 +1123,7 @@ EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; } else { if (ext3_should_order_data(inode)) { - ret = walk_page_buffers(handle, page->buffers, + ret = walk_page_buffers(handle, inode, page->buffers, from, to, NULL, journal_dirty_sync_data); } /* Be careful here if generic_commit_write becomes a @@ -1194,7 +1205,8 @@ return generic_block_bmap(mapping,block,ext3_get_block); } -static int bget_one(handle_t *handle, struct buffer_head *bh) +static int bget_one(handle_t *handle, struct inode *inode, + struct buffer_head *bh) { atomic_inc(&bh->b_count); return 0; @@ -1293,7 +1305,7 @@ create_empty_buffers(page, inode->i_dev, inode->i_sb->s_blocksize); page_buffers = page->buffers; - walk_page_buffers(handle, page_buffers, 0, + walk_page_buffers(handle, inode, page_buffers, 0, PAGE_CACHE_SIZE, NULL, bget_one); } @@ -1311,7 +1323,7 @@ /* And attach them to the current transaction */ if (order_data) { - err = walk_page_buffers(handle, page_buffers, + err = walk_page_buffers(handle, inode, page_buffers, 0, PAGE_CACHE_SIZE, NULL, journal_dirty_async_data); if (!ret) ret = err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ext3/super.c linux.20pre2-ac1/fs/ext3/super.c --- linux.20pre2/fs/ext3/super.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/ext3/super.c 2002-08-13 17:21:26.000000000 +0100 @@ -1588,8 +1588,10 @@ journal_t *journal = EXT3_SB(sb)->s_journal; /* Now we set up the journal barrier. */ + unlock_super(sb); journal_lock_updates(journal); journal_flush(journal); + lock_super(sb); /* Journal blocked and flushed, clear needs_recovery flag. */ EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/fcntl.c linux.20pre2-ac1/fs/fcntl.c --- linux.20pre2/fs/fcntl.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/fcntl.c 2002-08-06 15:41:51.000000000 +0100 @@ -529,7 +529,7 @@ static int __init fasync_init(void) { - fasync_cache = kmem_cache_create("fasync cache", + fasync_cache = kmem_cache_create("fasync_cache", sizeof(struct fasync_struct), 0, 0, NULL, NULL); if (!fasync_cache) panic("cannot create fasync slab cache"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/file_table.c linux.20pre2-ac1/fs/file_table.c --- linux.20pre2/fs/file_table.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/file_table.c 2002-08-06 15:41:51.000000000 +0100 @@ -186,3 +186,17 @@ file_list_unlock(); return 0; } + +void __init files_init(unsigned long mempages) +{ + int n; + /* One file with associated inode and dcache is very roughly 1K. + * Per default don't use more than 10% of our memory for files. + */ + + n = (mempages * (PAGE_SIZE / 1024)) / 10; + files_stat.max_files = n; + if (files_stat.max_files < NR_FILE) + files_stat.max_files = NR_FILE; +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/inode.c linux.20pre2-ac1/fs/inode.c --- linux.20pre2/fs/inode.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/inode.c 2002-08-06 15:41:51.000000000 +0100 @@ -777,6 +777,7 @@ atomic_set(&inode->i_writecount, 0); inode->i_size = 0; inode->i_blocks = 0; + inode->i_bytes = 0; inode->i_generation = 0; memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); inode->i_pipe = NULL; @@ -1203,9 +1204,9 @@ /* Functions back in dquot.c */ void put_dquot_list(struct list_head *); -int remove_inode_dquot_ref(struct inode *, short, struct list_head *); +int remove_inode_dquot_ref(struct inode *, int, struct list_head *); -void remove_dquot_ref(struct super_block *sb, short type) +void remove_dquot_ref(struct super_block *sb, int type) { struct inode *inode; struct list_head *act_head; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ioctl.c linux.20pre2-ac1/fs/ioctl.c --- linux.20pre2/fs/ioctl.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/ioctl.c 2002-08-06 15:41:51.000000000 +0100 @@ -101,6 +101,16 @@ filp->f_flags &= ~FASYNC; break; + case FIOQSIZE: + if (S_ISDIR(filp->f_dentry->d_inode->i_mode) || + S_ISREG(filp->f_dentry->d_inode->i_mode) || + S_ISLNK(filp->f_dentry->d_inode->i_mode)) { + loff_t res = inode_get_bytes(filp->f_dentry->d_inode); + error = copy_to_user((loff_t *)arg, &res, sizeof(res)) ? -EFAULT : 0; + } + else + error = -ENOTTY; + break; default: error = -ENOTTY; if (S_ISREG(filp->f_dentry->d_inode->i_mode)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jbd/journal.c linux.20pre2-ac1/fs/jbd/journal.c --- linux.20pre2/fs/jbd/journal.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/jbd/journal.c 2002-08-13 17:24:22.000000000 +0100 @@ -459,11 +459,9 @@ do { new_bh = get_unused_buffer_head(0); if (!new_bh) { - printk (KERN_NOTICE "%s: ENOMEM at " - "get_unused_buffer_head, trying again.\n", - __FUNCTION__); - current->policy |= SCHED_YIELD; - schedule(); + printk (KERN_NOTICE "%s: ENOMEM at get_unused_buffer_head, " + "trying again.\n", __FUNCTION__); + yield(); } } while (!new_bh); /* keep subsequent assertions sane */ @@ -1486,6 +1484,49 @@ unlock_journal(journal); } + +/* + * Report any unexpected dirty buffers which turn up. Normally those + * indicate an error, but they can occur if the user is running (say) + * tune2fs to modify the live filesystem, so we need the option of + * continuing as gracefully as possible. # + * + * The caller should already hold the journal lock and + * journal_datalist_lock spinlock: most callers will need those anyway + * in order to probe the buffer's journaling state safely. + */ +void __jbd_unexpected_dirty_buffer(char *function, int line, + struct journal_head *jh) +{ + struct buffer_head *bh = jh2bh(jh); + int jlist; + + if (buffer_dirty(bh)) { + printk ("%sUnexpected dirty buffer encountered at " + "%s:%d (%s blocknr %lu)\n", + KERN_WARNING, function, line, + kdevname(bh->b_dev), bh->b_blocknr); +#ifdef JBD_PARANOID_WRITES + J_ASSERT (!buffer_dirty(bh)); +#endif + + /* If this buffer is one which might reasonably be dirty + * --- ie. data, or not part of this journal --- then + * we're OK to leave it alone, but otherwise we need to + * move the dirty bit to the journal's own internal + * JBDDirty bit. */ + jlist = jh->b_jlist; + + if (jlist == BJ_Metadata || jlist == BJ_Reserved || + jlist == BJ_Shadow || jlist == BJ_Forget) { + if (atomic_set_buffer_clean(jh2bh(jh))) { + set_bit(BH_JBDDirty, &jh2bh(jh)->b_state); + } + } + } +} + + int journal_blocks_per_page(struct inode *inode) { return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); @@ -1541,8 +1582,7 @@ last_warning = jiffies; } - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } @@ -1600,8 +1640,7 @@ last_warning = jiffies; } while (ret == 0) { - current->policy |= SCHED_YIELD; - schedule(); + yield(); ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); } } @@ -1623,8 +1662,8 @@ * * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit * is set. This bit is tested in core kernel code where we need to take - * JBD-specific actions. Testing the zeroness of ->b_private is not reliable - * there. + * JBD-specific actions. Testing the zeroness of ->b_journal_head is not + * reliable there. * * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one. * @@ -1679,9 +1718,9 @@ if (buffer_jbd(bh)) { /* Someone did it for us! */ - J_ASSERT_BH(bh, bh->b_private != NULL); + J_ASSERT_BH(bh, bh->b_journal_head != NULL); journal_free_journal_head(jh); - jh = bh->b_private; + jh = bh->b_journal_head; } else { /* * We actually don't need jh_splice_lock when @@ -1689,7 +1728,7 @@ */ spin_lock(&jh_splice_lock); set_bit(BH_JBD, &bh->b_state); - bh->b_private = jh; + bh->b_journal_head = jh; jh->b_bh = bh; atomic_inc(&bh->b_count); spin_unlock(&jh_splice_lock); @@ -1698,7 +1737,7 @@ } jh->b_jcount++; spin_unlock(&journal_datalist_lock); - return bh->b_private; + return bh->b_journal_head; } /* @@ -1731,7 +1770,7 @@ J_ASSERT_BH(bh, jh2bh(jh) == bh); BUFFER_TRACE(bh, "remove journal_head"); spin_lock(&jh_splice_lock); - bh->b_private = NULL; + bh->b_journal_head = NULL; jh->b_bh = NULL; /* debug, really */ clear_bit(BH_JBD, &bh->b_state); __brelse(bh); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jbd/revoke.c linux.20pre2-ac1/fs/jbd/revoke.c --- linux.20pre2/fs/jbd/revoke.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/fs/jbd/revoke.c 2002-08-06 15:41:51.000000000 +0100 @@ -137,8 +137,7 @@ if (!journal_oom_retry) return -ENOMEM; jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n"); - current->policy |= SCHED_YIELD; - schedule(); + yield(); goto repeat; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jbd/transaction.c linux.20pre2-ac1/fs/jbd/transaction.c --- linux.20pre2/fs/jbd/transaction.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/jbd/transaction.c 2002-08-06 15:41:51.000000000 +0100 @@ -539,76 +539,67 @@ static int do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) { + struct buffer_head *bh; transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int error; char *frozen_buffer = NULL; int need_copy = 0; - + int locked; + jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy); JBUFFER_TRACE(jh, "entry"); repeat: + bh = jh2bh(jh); + /* @@@ Need to check for errors here at some point. */ /* - * AKPM: neither bdflush nor kupdate run with the BKL. There's - * nothing we can do to prevent them from starting writeout of a - * BUF_DIRTY buffer at any time. And checkpointing buffers are on - * BUF_DIRTY. So. We no longer assert that the buffer is unlocked. - * - * However. It is very wrong for us to allow ext3 to start directly - * altering the ->b_data of buffers which may at that very time be - * undergoing writeout to the client filesystem. This can leave - * the filesystem in an inconsistent, transient state if we crash. - * So what we do is to steal the buffer if it is in checkpoint - * mode and dirty. The journal lock will keep out checkpoint-mode - * state transitions within journal_remove_checkpoint() and the buffer - * is locked to keep bdflush/kupdate/whoever away from it as well. - * * AKPM: we have replaced all the lock_journal_bh_wait() stuff with a * simple lock_journal(). This code here will care for locked buffers. */ - /* - * The buffer_locked() || buffer_dirty() tests here are simply an - * optimisation tweak. If anyone else in the system decides to - * lock this buffer later on, we'll blow up. There doesn't seem - * to be a good reason why they should do this. - */ - if (jh->b_cp_transaction && - (buffer_locked(jh2bh(jh)) || buffer_dirty(jh2bh(jh)))) { + locked = test_and_set_bit(BH_Lock, &bh->b_state); + if (locked) { + /* We can't reliably test the buffer state if we found + * it already locked, so just wait for the lock and + * retry. */ unlock_journal(journal); - lock_buffer(jh2bh(jh)); - spin_lock(&journal_datalist_lock); - if (jh->b_cp_transaction && buffer_dirty(jh2bh(jh))) { - /* OK, we need to steal it */ - JBUFFER_TRACE(jh, "stealing from checkpoint mode"); - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - J_ASSERT_JH(jh, jh->b_frozen_data == NULL); - - J_ASSERT(handle->h_buffer_credits > 0); - handle->h_buffer_credits--; - - /* This will clear BH_Dirty and set BH_JBDDirty. */ - JBUFFER_TRACE(jh, "file as BJ_Reserved"); - __journal_file_buffer(jh, transaction, BJ_Reserved); - - /* And pull it off BUF_DIRTY, onto BUF_CLEAN */ - refile_buffer(jh2bh(jh)); + __wait_on_buffer(bh); + lock_journal(journal); + goto repeat; + } + + /* We now hold the buffer lock so it is safe to query the buffer + * state. Is the buffer dirty? + * + * If so, there are two possibilities. The buffer may be + * non-journaled, and undergoing a quite legitimate writeback. + * Otherwise, it is journaled, and we don't expect dirty buffers + * in that state (the buffers should be marked JBD_Dirty + * instead.) So either the IO is being done under our own + * control and this is a bug, or it's a third party IO such as + * dump(8) (which may leave the buffer scheduled for read --- + * ie. locked but not dirty) or tune2fs (which may actually have + * the buffer dirtied, ugh.) */ - /* - * The buffer is now hidden from bdflush. It is - * metadata against the current transaction. - */ - JBUFFER_TRACE(jh, "steal from cp mode is complete"); + if (buffer_dirty(bh)) { + spin_lock(&journal_datalist_lock); + /* First question: is this buffer already part of the + * current transaction or the existing committing + * transaction? */ + if (jh->b_transaction) { + J_ASSERT_JH(jh, jh->b_transaction == transaction || + jh->b_transaction == journal->j_committing_transaction); + if (jh->b_next_transaction) + J_ASSERT_JH(jh, jh->b_next_transaction == transaction); + JBUFFER_TRACE(jh, "Unexpected dirty buffer"); + jbd_unexpected_dirty_buffer(jh); } spin_unlock(&journal_datalist_lock); - unlock_buffer(jh2bh(jh)); - lock_journal(journal); - goto repeat; } - J_ASSERT_JH(jh, !buffer_locked(jh2bh(jh))); + unlock_buffer(bh); error = -EROFS; if (is_handle_aborted(handle)) @@ -688,8 +679,7 @@ GFP_NOFS); lock_journal(journal); if (!frozen_buffer) { - printk(KERN_EMERG - "%s: OOM for frozen_buffer\n", + printk(KERN_EMERG "%s: OOM for frozen_buffer\n", __FUNCTION__); JBUFFER_TRACE(jh, "oom!"); error = -ENOMEM; @@ -888,8 +878,7 @@ jh->b_committed_data = jbd_kmalloc(jh2bh(jh)->b_size, GFP_NOFS); if (!jh->b_committed_data) { - printk(KERN_EMERG "%s: No memory for committed data!\n", - __FUNCTION__); + printk(KERN_EMERG "%s: No memory for committed data!\n", __FUNCTION__); err = -ENOMEM; goto out; } @@ -1380,8 +1369,7 @@ do { old_handle_count = transaction->t_handle_count; set_current_state(TASK_RUNNING); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } while (old_handle_count != transaction->t_handle_count); } @@ -1927,6 +1915,7 @@ transaction_t *transaction, int jlist) { struct journal_head **list = 0; + int was_dirty = 0; assert_spin_locked(&journal_datalist_lock); @@ -1937,13 +1926,24 @@ J_ASSERT_JH(jh, jh->b_transaction == transaction || jh->b_transaction == 0); - if (jh->b_transaction) { - if (jh->b_jlist == jlist) - return; + if (jh->b_transaction && jh->b_jlist == jlist) + return; + + /* The following list of buffer states needs to be consistent + * with __jbd_unexpected_dirty_buffer()'s handling of dirty + * state. */ + + if (jlist == BJ_Metadata || jlist == BJ_Reserved || + jlist == BJ_Shadow || jlist == BJ_Forget) { + if (atomic_set_buffer_clean(jh2bh(jh)) || + test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state)) + was_dirty = 1; + } + + if (jh->b_transaction) __journal_unfile_buffer(jh); - } else { + else jh->b_transaction = transaction; - } switch (jlist) { case BJ_None: @@ -1980,12 +1980,8 @@ __blist_add_buffer(list, jh); jh->b_jlist = jlist; - if (jlist == BJ_Metadata || jlist == BJ_Reserved || - jlist == BJ_Shadow || jlist == BJ_Forget) { - if (atomic_set_buffer_clean(jh2bh(jh))) { - set_bit(BH_JBDDirty, &jh2bh(jh)->b_state); - } - } + if (was_dirty) + set_bit(BH_JBDDirty, &jh2bh(jh)->b_state); } void journal_file_buffer(struct journal_head *jh, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jffs2/background.c linux.20pre2-ac1/fs/jffs2/background.c --- linux.20pre2/fs/jffs2/background.c 2002-08-13 13:58:15.000000000 +0100 +++ linux.20pre2-ac1/fs/jffs2/background.c 2002-08-06 15:41:51.000000000 +0100 @@ -106,9 +106,6 @@ sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index); - /* FIXME in the 2.2 backport */ - current->nice = 10; - for (;;) { spin_lock_irq(¤t->sigmask_lock); siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jffs2/super.c linux.20pre2-ac1/fs/jffs2/super.c --- linux.20pre2/fs/jffs2/super.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/jffs2/super.c 2002-08-06 15:41:51.000000000 +0100 @@ -31,7 +31,7 @@ * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * - * $Id: super.c,v 1.48.2.2 2002/03/12 15:36:43 dwmw2 Exp $ + * $Id: super.c,v 1.48.2.1 2002/02/23 14:13:34 dwmw2 Exp $ * + zlib_init calls from v1.56 * */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/endian24.h linux.20pre2-ac1/fs/jfs/endian24.h --- linux.20pre2/fs/jfs/endian24.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/endian24.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) International Business Machines Corp., 2001 + * + * 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 _H_ENDIAN24 +#define _H_ENDIAN24 + +/* + * endian24.h: + * + * Endian conversion for 24-byte data + * + */ +#define __swab24(x) \ +({ \ + __u32 __x = (x); \ + ((__u32)( \ + ((__x & (__u32)0x000000ffUL) << 16) | \ + (__x & (__u32)0x0000ff00UL) | \ + ((__x & (__u32)0x00ff0000UL) >> 16) )); \ +}) + +#if (defined(__KERNEL__) && defined(__LITTLE_ENDIAN)) || (defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)) + #define __cpu_to_le24(x) ((__u32)(x)) + #define __le24_to_cpu(x) ((__u32)(x)) +#else + #define __cpu_to_le24(x) __swab24(x) + #define __le24_to_cpu(x) __swab24(x) +#endif + +#ifdef __KERNEL__ + #define cpu_to_le24 __cpu_to_le24 + #define le24_to_cpu __le24_to_cpu +#endif + +#endif /* !_H_ENDIAN24 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/file.c linux.20pre2-ac1/fs/jfs/file.c --- linux.20pre2/fs/jfs/file.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/file.c 2002-08-06 17:59:43.000000000 +0100 @@ -0,0 +1,110 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 "jfs_incore.h" +#include "jfs_txnmgr.h" +#include "jfs_debug.h" + + +extern int jfs_commit_inode(struct inode *, int); + +int jfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + struct inode *inode = dentry->d_inode; + int rc = 0; + + rc = fsync_inode_data_buffers(inode); + + if (!(inode->i_state & I_DIRTY)) + return rc; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + return rc; + + rc |= jfs_commit_inode(inode, 1); + + return rc ? -EIO : 0; +} + +struct file_operations jfs_file_operations = { + open: generic_file_open, + llseek: generic_file_llseek, + write: generic_file_write, + read: generic_file_read, + mmap: generic_file_mmap, + fsync: jfs_fsync, +}; + +/* + * Guts of jfs_truncate. Called with locks already held. Can be called + * with directory for truncating directory index table. + */ +void jfs_truncate_nolock(struct inode *ip, loff_t length) +{ + loff_t newsize; + tid_t tid; + + ASSERT(length >= 0); + + if (test_cflag(COMMIT_Nolink, ip)) { + xtTruncate(0, ip, length, COMMIT_WMAP); + return; + } + + do { + tid = txBegin(ip->i_sb, 0); + + /* + * The commit_sem cannot be taken before txBegin. + * txBegin may block and there is a chance the inode + * could be marked dirty and need to be committed + * before txBegin unblocks + */ + down(&JFS_IP(ip)->commit_sem); + + newsize = xtTruncate(tid, ip, length, + COMMIT_TRUNCATE | COMMIT_PWMAP); + if (newsize < 0) { + txEnd(tid); + up(&JFS_IP(ip)->commit_sem); + break; + } + + ip->i_mtime = ip->i_ctime = CURRENT_TIME; + mark_inode_dirty(ip); + + txCommit(tid, 1, &ip, 0); + txEnd(tid); + up(&JFS_IP(ip)->commit_sem); + } while (newsize > length); /* Truncate isn't always atomic */ +} + +static void jfs_truncate(struct inode *ip) +{ + jFYI(1, ("jfs_truncate: size = 0x%lx\n", (ulong) ip->i_size)); + + IWRITE_LOCK(ip); + jfs_truncate_nolock(ip, ip->i_size); + IWRITE_UNLOCK(ip); +} + +struct inode_operations jfs_file_inode_operations = { + truncate: jfs_truncate, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/inode.c linux.20pre2-ac1/fs/jfs/inode.c --- linux.20pre2/fs/jfs/inode.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/inode.c 2002-08-06 17:59:43.000000000 +0100 @@ -0,0 +1,333 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_imap.h" +#include "jfs_extent.h" +#include "jfs_unicode.h" +#include "jfs_debug.h" + + +extern struct inode_operations jfs_dir_inode_operations; +extern struct inode_operations jfs_file_inode_operations; +extern struct inode_operations jfs_symlink_inode_operations; +extern struct file_operations jfs_dir_operations; +extern struct file_operations jfs_file_operations; +struct address_space_operations jfs_aops; +extern int freeZeroLink(struct inode *); + +void jfs_clear_inode(struct inode *inode) +{ + struct jfs_inode_info *ji = JFS_IP(inode); + + jFYI(1, ("jfs_clear_inode called ip = 0x%p\n", inode)); + + ASSERT(list_empty(&ji->mp_list)); + ASSERT(list_empty(&ji->anon_inode_list)); + + if (ji->atlhead) { + jERROR(1, ("jfs_clear_inode: inode %p has anonymous tlocks\n", + inode)); + jERROR(1, ("i_state = 0x%lx, cflag = 0x%lx\n", + inode->i_state, ji->cflag)); + } + + free_jfs_inode(inode); +} + +void jfs_read_inode(struct inode *inode) +{ + int rc; + + rc = alloc_jfs_inode(inode); + if (rc) { + jFYI(1, ("In jfs_read_inode, alloc_jfs_inode failed")); + goto bad_inode; + } + jFYI(1, ("In jfs_read_inode, inode = 0x%p\n", inode)); + + if (diRead(inode)) + goto bad_inode_free; + + if (S_ISREG(inode->i_mode)) { + inode->i_op = &jfs_file_inode_operations; + inode->i_fop = &jfs_file_operations; + inode->i_mapping->a_ops = &jfs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &jfs_dir_inode_operations; + inode->i_fop = &jfs_dir_operations; + inode->i_mapping->a_ops = &jfs_aops; + inode->i_mapping->gfp_mask = GFP_NOFS; + } else if (S_ISLNK(inode->i_mode)) { + if (inode->i_size > IDATASIZE) { + inode->i_op = &page_symlink_inode_operations; + inode->i_mapping->a_ops = &jfs_aops; + } else + inode->i_op = &jfs_symlink_inode_operations; + } else { + init_special_inode(inode, inode->i_mode, + kdev_t_to_nr(inode->i_rdev)); + } + + return; + + bad_inode_free: + free_jfs_inode(inode); + bad_inode: + make_bad_inode(inode); +} + +/* This define is from fs/open.c */ +#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) + +/* + * Workhorse of both fsync & write_inode + */ +int jfs_commit_inode(struct inode *inode, int wait) +{ + int rc = 0; + tid_t tid; + static int noisy = 5; + + jFYI(1, ("In jfs_commit_inode, inode = 0x%p\n", inode)); + + /* + * Don't commit if inode has been committed since last being + * marked dirty, or if it has been deleted. + */ + if (test_cflag(COMMIT_Nolink, inode) || + !test_cflag(COMMIT_Dirty, inode)) + return 0; + + if (isReadOnly(inode)) { + /* kernel allows writes to devices on read-only + * partitions and may think inode is dirty + */ + if (!special_file(inode->i_mode) && noisy) { + jERROR(1, ("jfs_commit_inode(0x%p) called on " + "read-only volume\n", inode)); + jERROR(1, ("Is remount racy?\n")); + noisy--; + } + return 0; + } + + tid = txBegin(inode->i_sb, COMMIT_INODE); + down(&JFS_IP(inode)->commit_sem); + rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0); + txEnd(tid); + up(&JFS_IP(inode)->commit_sem); + return -rc; +} + +void jfs_write_inode(struct inode *inode, int wait) +{ + /* + * If COMMIT_DIRTY is not set, the inode isn't really dirty. + * It has been committed since the last change, but was still + * on the dirty inode list + */ + if (test_cflag(COMMIT_Nolink, inode) || + !test_cflag(COMMIT_Dirty, inode)) + return; + + if (jfs_commit_inode(inode, wait)) { + jERROR(1, ("jfs_write_inode: jfs_commit_inode failed!\n")); + } +} + +void jfs_delete_inode(struct inode *inode) +{ + jFYI(1, ("In jfs_delete_inode, inode = 0x%p\n", inode)); + + if (test_cflag(COMMIT_Freewmap, inode)) + freeZeroLink(inode); + + diFree(inode); + + clear_inode(inode); +} + +void jfs_dirty_inode(struct inode *inode) +{ + static int noisy = 5; + + if (isReadOnly(inode)) { + if (!special_file(inode->i_mode) && noisy) { + /* kernel allows writes to devices on read-only + * partitions and may try to mark inode dirty + */ + jERROR(1, ("jfs_dirty_inode called on " + "read-only volume\n")); + jERROR(1, ("Is remount racy?\n")); + noisy--; + } + return; + } + + set_cflag(COMMIT_Dirty, inode); +} + +static int jfs_get_block(struct inode *ip, long lblock, + struct buffer_head *bh_result, int create) +{ + s64 lblock64 = lblock; + int no_size_check = 0; + int rc = 0; + int take_locks; + xad_t xad; + s64 xaddr; + int xflag; + s32 xlen; + + /* + * If this is a special inode (imap, dmap) or directory, + * the lock should already be taken + */ + take_locks = ((JFS_IP(ip)->fileset != AGGREGATE_I) && + !S_ISDIR(ip->i_mode)); + /* + * Take appropriate lock on inode + */ + if (take_locks) { + if (create) + IWRITE_LOCK(ip); + else + IREAD_LOCK(ip); + } + + /* + * A directory's "data" is the inode index table, but i_size is the + * size of the d-tree, so don't check the offset against i_size + */ + if (S_ISDIR(ip->i_mode)) + no_size_check = 1; + + if ((no_size_check || + ((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size)) && + (xtLookup(ip, lblock64, 1, &xflag, &xaddr, &xlen, no_size_check) + == 0) && xlen) { + if (xflag & XAD_NOTRECORDED) { + if (!create) + /* + * Allocated but not recorded, read treats + * this as a hole + */ + goto unlock; +#ifdef _JFS_4K + XADoffset(&xad, lblock64); + XADlength(&xad, xlen); + XADaddress(&xad, xaddr); +#else /* _JFS_4K */ + /* + * As long as block size = 4K, this isn't a problem. + * We should mark the whole page not ABNR, but how + * will we know to mark the other blocks BH_New? + */ + BUG(); +#endif /* _JFS_4K */ + rc = extRecord(ip, &xad); + if (rc) + goto unlock; + bh_result->b_state |= (1UL << BH_New); + } + + bh_result->b_dev = ip->i_dev; + bh_result->b_blocknr = xaddr; + bh_result->b_state |= (1UL << BH_Mapped); + goto unlock; + } + if (!create) + goto unlock; + + /* + * Allocate a new block + */ +#ifdef _JFS_4K + if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad))) + goto unlock; + rc = extAlloc(ip, 1, lblock64, &xad, FALSE); + if (rc) + goto unlock; + + bh_result->b_dev = ip->i_dev; + bh_result->b_blocknr = addressXAD(&xad); + bh_result->b_state |= ((1UL << BH_Mapped) | (1UL << BH_New)); + +#else /* _JFS_4K */ + /* + * We need to do whatever it takes to keep all but the last buffers + * in 4K pages - see jfs_write.c + */ + BUG(); +#endif /* _JFS_4K */ + + unlock: + /* + * Release lock on inode + */ + if (take_locks) { + if (create) + IWRITE_UNLOCK(ip); + else + IREAD_UNLOCK(ip); + } + return -rc; +} + +static int jfs_writepage(struct page *page) +{ + return block_write_full_page(page, jfs_get_block); +} + +static int jfs_readpage(struct file *file, struct page *page) +{ + return block_read_full_page(page, jfs_get_block); +} + +static int jfs_prepare_write(struct file *file, + struct page *page, unsigned from, unsigned to) +{ + return block_prepare_write(page, from, to, jfs_get_block); +} + +static int jfs_bmap(struct address_space *mapping, long block) +{ + return generic_block_bmap(mapping, block, jfs_get_block); +} + +static int jfs_direct_IO(int rw, struct inode *inode, struct kiobuf *iobuf, + unsigned long blocknr, int blocksize) +{ + return generic_direct_IO(rw, inode, iobuf, blocknr, + blocksize, jfs_get_block); +} + +struct address_space_operations jfs_aops = { + readpage: jfs_readpage, + writepage: jfs_writepage, + sync_page: block_sync_page, + prepare_write: jfs_prepare_write, + commit_write: generic_commit_write, + bmap: jfs_bmap, + direct_IO: jfs_direct_IO, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_btree.h linux.20pre2-ac1/fs/jfs/jfs_btree.h --- linux.20pre2/fs/jfs/jfs_btree.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_btree.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,163 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2001 + * + * 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 _H_JFS_BTREE +#define _H_JFS_BTREE + +/* + * jfs_btree.h: B+-tree + * + * JFS B+-tree (dtree and xtree) common definitions + */ + +/* + * basic btree page - btpage_t + */ +typedef struct { + s64 next; /* 8: right sibling bn */ + s64 prev; /* 8: left sibling bn */ + + u8 flag; /* 1: */ + u8 rsrvd[7]; /* 7: type specific */ + s64 self; /* 8: self address */ + + u8 entry[4064]; /* 4064: */ +} btpage_t; /* (4096) */ + +/* btpaget_t flag */ +#define BT_TYPE 0x07 /* B+-tree index */ +#define BT_ROOT 0x01 /* root page */ +#define BT_LEAF 0x02 /* leaf page */ +#define BT_INTERNAL 0x04 /* internal page */ +#define BT_RIGHTMOST 0x10 /* rightmost page */ +#define BT_LEFTMOST 0x20 /* leftmost page */ +#define BT_SWAPPED 0x80 /* used by fsck for endian swapping */ + +/* btorder (in inode) */ +#define BT_RANDOM 0x0000 +#define BT_SEQUENTIAL 0x0001 +#define BT_LOOKUP 0x0010 +#define BT_INSERT 0x0020 +#define BT_DELETE 0x0040 + +/* + * btree page buffer cache access + */ +#define BT_IS_ROOT(MP) (((MP)->xflag & COMMIT_PAGE) == 0) + +/* get page from buffer page */ +#define BT_PAGE(IP, MP, TYPE, ROOT)\ + (BT_IS_ROOT(MP) ? (TYPE *)&JFS_IP(IP)->ROOT : (TYPE *)(MP)->data) + +/* get the page buffer and the page for specified block address */ +#define BT_GETPAGE(IP, BN, MP, TYPE, SIZE, P, RC, ROOT)\ +{\ + if ((BN) == 0)\ + {\ + MP = (metapage_t *)&JFS_IP(IP)->bxflag;\ + P = (TYPE *)&JFS_IP(IP)->ROOT;\ + RC = 0;\ + jEVENT(0,("%d BT_GETPAGE returning root\n", __LINE__));\ + }\ + else\ + {\ + jEVENT(0,("%d BT_GETPAGE reading block %d\n", __LINE__,\ + (int)BN));\ + MP = read_metapage((IP), BN, SIZE, 1);\ + if (MP) {\ + RC = 0;\ + P = (MP)->data;\ + } else {\ + P = NULL;\ + jERROR(1,("bread failed!\n"));\ + RC = EIO;\ + }\ + }\ +} + +#define BT_MARK_DIRTY(MP, IP)\ +{\ + if (BT_IS_ROOT(MP))\ + mark_inode_dirty(IP);\ + else\ + mark_metapage_dirty(MP);\ +} + +/* put the page buffer */ +#define BT_PUTPAGE(MP)\ +{\ + if (! BT_IS_ROOT(MP)) \ + release_metapage(MP); \ +} + + +/* + * btree traversal stack + * + * record the path traversed during the search; + * top frame record the leaf page/entry selected. + */ +#define MAXTREEHEIGHT 8 +typedef struct btframe { /* stack frame */ + s64 bn; /* 8: */ + s16 index; /* 2: */ + s16 lastindex; /* 2: */ + struct metapage *mp; /* 4: */ +} btframe_t; /* (16) */ + +typedef struct btstack { + btframe_t *top; /* 4: */ + int nsplit; /* 4: */ + btframe_t stack[MAXTREEHEIGHT]; +} btstack_t; + +#define BT_CLR(btstack)\ + (btstack)->top = (btstack)->stack + +#define BT_PUSH(BTSTACK, BN, INDEX)\ +{\ + (BTSTACK)->top->bn = BN;\ + (BTSTACK)->top->index = INDEX;\ + ++(BTSTACK)->top;\ + assert((BTSTACK)->top != &((BTSTACK)->stack[MAXTREEHEIGHT]));\ +} + +#define BT_POP(btstack)\ + ( (btstack)->top == (btstack)->stack ? NULL : --(btstack)->top ) + +#define BT_STACK(btstack)\ + ( (btstack)->top == (btstack)->stack ? NULL : (btstack)->top ) + +/* retrieve search results */ +#define BT_GETSEARCH(IP, LEAF, BN, MP, TYPE, P, INDEX, ROOT)\ +{\ + BN = (LEAF)->bn;\ + MP = (LEAF)->mp;\ + if (BN)\ + P = (TYPE *)MP->data;\ + else\ + P = (TYPE *)&JFS_IP(IP)->ROOT;\ + INDEX = (LEAF)->index;\ +} + +/* put the page buffer of search */ +#define BT_PUTSEARCH(BTSTACK)\ +{\ + if (! BT_IS_ROOT((BTSTACK)->top->mp))\ + release_metapage((BTSTACK)->top->mp);\ +} +#endif /* _H_JFS_BTREE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_debug.c linux.20pre2-ac1/fs/jfs/jfs_debug.c --- linux.20pre2/fs/jfs/jfs_debug.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_debug.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,152 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_debug.h" + +#ifdef CONFIG_JFS_DEBUG +void dump_mem(char *label, void *data, int length) +{ + int i, j; + int *intptr = data; + char *charptr = data; + char buf[10], line[80]; + + printk("%s: dump of %d bytes of data at 0x%p\n\n", label, length, + data); + for (i = 0; i < length; i += 16) { + line[0] = 0; + for (j = 0; (j < 4) && (i + j * 4 < length); j++) { + sprintf(buf, " %08x", intptr[i / 4 + j]); + strcat(line, buf); + } + buf[0] = ' '; + buf[2] = 0; + for (j = 0; (j < 16) && (i + j < length); j++) { + buf[1] = + isprint(charptr[i + j]) ? charptr[i + j] : '.'; + strcat(line, buf); + } + printk("%s\n", line); + } +} +#endif + +#ifdef PROC_FS_JFS /* see jfs_debug.h */ + +static struct proc_dir_entry *base; +#ifdef CONFIG_JFS_DEBUG +extern read_proc_t jfs_txanchor_read; + +static int loglevel_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", jfsloglevel); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} + +static int loglevel_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + + if (get_user(c, buffer)) + return -EFAULT; + + /* yes, I know this is an ASCIIism. --hch */ + if (c < '0' || c > '9') + return -EINVAL; + jfsloglevel = c - '0'; + return count; +} +#endif + + +#ifdef CONFIG_JFS_STATISTICS +extern read_proc_t jfs_lmstats_read; +extern read_proc_t jfs_xtstat_read; +extern read_proc_t jfs_mpstat_read; +#endif + +static struct { + const char *name; + read_proc_t *read_fn; + write_proc_t *write_fn; +} Entries[] = { +#ifdef CONFIG_JFS_STATISTICS + { "lmstats", jfs_lmstats_read, }, + { "xtstat", jfs_xtstat_read, }, + { "mpstat", jfs_mpstat_read, }, +#endif +#ifdef CONFIG_JFS_DEBUG + { "TxAnchor", jfs_txanchor_read, }, + { "loglevel", loglevel_read, loglevel_write } +#endif +}; +#define NPROCENT (sizeof(Entries)/sizeof(Entries[0])) + +void jfs_proc_init(void) +{ + int i; + + if (!(base = proc_mkdir("jfs", proc_root_fs))) + return; + base->owner = THIS_MODULE; + + for (i = 0; i < NPROCENT; i++) { + struct proc_dir_entry *p; + if ((p = create_proc_entry(Entries[i].name, 0, base))) { + p->read_proc = Entries[i].read_fn; + p->write_proc = Entries[i].write_fn; + } + } +} + +void jfs_proc_clean(void) +{ + int i; + + if (base) { + for (i = 0; i < NPROCENT; i++) + remove_proc_entry(Entries[i].name, base); + remove_proc_entry("jfs", base); + } +} + +#endif /* PROC_FS_JFS */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_debug.h linux.20pre2-ac1/fs/jfs/jfs_debug.h --- linux.20pre2/fs/jfs/jfs_debug.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_debug.h 2002-08-06 18:24:33.000000000 +0100 @@ -0,0 +1,103 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 _H_JFS_DEBUG +#define _H_JFS_DEBUG + +/* + * jfs_debug.h + * + * global debug message, data structure/macro definitions + * under control of CONFIG_JFS_DEBUG, CONFIG_JFS_STATISTICS; + */ + +/* + * Create /proc/fs/jfs if procfs is enabled andeither + * CONFIG_JFS_DEBUG or CONFIG_JFS_STATISTICS is defined + */ +#if defined(CONFIG_PROC_FS) && (defined(CONFIG_JFS_DEBUG) || defined(CONFIG_JFS_STATISTICS)) + #define PROC_FS_JFS +#endif + +/* + * assert with traditional printf/panic + */ +#ifdef CONFIG_KERNEL_ASSERTS +/* kgdb stuff */ +#define assert(p) KERNEL_ASSERT(#p, p) +#else +#define assert(p) {\ +if (!(p))\ + {\ + printk("assert(%s)\n",#p);\ + BUG();\ + }\ +} +#endif + +/* + * debug ON + * -------- + */ +#ifdef CONFIG_JFS_DEBUG +#define ASSERT(p) assert(p) + +/* dump memory contents */ +extern void dump_mem(char *label, void *data, int length); +extern int jfsloglevel; + +/* information message: e.g., configuration, major event */ +#define jFYI(button, prspec) \ + do { if (button && jfsloglevel > 1) printk prspec; } while (0) + +/* error event message: e.g., i/o error */ +extern int jfsERROR; +#define jERROR(button, prspec) \ + do { if (button && jfsloglevel > 0) { printk prspec; } } while (0) + +/* debug event message: */ +#define jEVENT(button,prspec) \ + do { if (button) printk prspec; } while (0) + +/* + * debug OFF + * --------- + */ +#else /* CONFIG_JFS_DEBUG */ +#define dump_mem(label,data,length) +#define ASSERT(p) +#define jEVENT(button,prspec) +#define jERROR(button,prspec) +#define jFYI(button,prspec) +#endif /* CONFIG_JFS_DEBUG */ + +/* + * statistics + * ---------- + */ +#ifdef CONFIG_JFS_STATISTICS +#define INCREMENT(x) ((x)++) +#define DECREMENT(x) ((x)--) +#define HIGHWATERMARK(x,y) ((x) = max((x), (y))) +#else +#define INCREMENT(x) +#define DECREMENT(x) +#define HIGHWATERMARK(x,y) +#endif /* CONFIG_JFS_STATISTICS */ + +#endif /* _H_JFS_DEBUG */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_defragfs.h linux.20pre2-ac1/fs/jfs/jfs_defragfs.h --- linux.20pre2/fs/jfs/jfs_defragfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_defragfs.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2001 + * + * 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 _H_JFS_DEFRAGFS +#define _H_JFS_DEFRAGFS + +/* + * defragfs parameter list + */ +typedef struct { + uint flag; /* 4: */ + u8 dev; /* 1: */ + u8 pad[3]; /* 3: */ + s32 fileset; /* 4: */ + u32 inostamp; /* 4: */ + u32 ino; /* 4: */ + u32 gen; /* 4: */ + s64 xoff; /* 8: */ + s64 old_xaddr; /* 8: */ + s64 new_xaddr; /* 8: */ + s32 xlen; /* 4: */ +} defragfs_t; /* (52) */ + +/* plist flag */ +#define DEFRAGFS_SYNC 0x80000000 +#define DEFRAGFS_COMMIT 0x40000000 +#define DEFRAGFS_RELOCATE 0x10000000 + +#define INODE_TYPE 0x0000F000 /* IFREG or IFDIR */ + +#define EXTENT_TYPE 0x000000ff +#define DTPAGE 0x00000001 +#define XTPAGE 0x00000002 +#define DATAEXT 0x00000004 +#define EAEXT 0x00000008 + +#endif /* _H_JFS_DEFRAGFS */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_dinode.h linux.20pre2-ac1/fs/jfs/jfs_dinode.h --- linux.20pre2/fs/jfs/jfs_dinode.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_dinode.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,154 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2001 + * + * 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 _H_JFS_DINODE +#define _H_JFS_DINODE + +/* + * jfs_dinode.h: on-disk inode manager + */ + +#define INODESLOTSIZE 128 +#define L2INODESLOTSIZE 7 +#define log2INODESIZE 9 /* log2(bytes per dinode) */ + + +/* + * on-disk inode (dinode_t): 512 bytes + * + * note: align 64-bit fields on 8-byte boundary. + */ +struct dinode { + /* + * I. base area (128 bytes) + * ------------------------ + * + * define generic/POSIX attributes + */ + u32 di_inostamp; /* 4: stamp to show inode belongs to fileset */ + s32 di_fileset; /* 4: fileset number */ + u32 di_number; /* 4: inode number, aka file serial number */ + u32 di_gen; /* 4: inode generation number */ + + pxd_t di_ixpxd; /* 8: inode extent descriptor */ + + s64 di_size; /* 8: size */ + s64 di_nblocks; /* 8: number of blocks allocated */ + + u32 di_nlink; /* 4: number of links to the object */ + + u32 di_uid; /* 4: user id of owner */ + u32 di_gid; /* 4: group id of owner */ + + u32 di_mode; /* 4: attribute, format and permission */ + + struct timestruc_t di_atime; /* 8: time last data accessed */ + struct timestruc_t di_ctime; /* 8: time last status changed */ + struct timestruc_t di_mtime; /* 8: time last data modified */ + struct timestruc_t di_otime; /* 8: time created */ + + dxd_t di_acl; /* 16: acl descriptor */ + + dxd_t di_ea; /* 16: ea descriptor */ + + u32 di_next_index; /* 4: Next available dir_table index */ + + s32 di_acltype; /* 4: Type of ACL */ + + /* + * Extension Areas. + * + * Historically, the inode was partitioned into 4 128-byte areas, + * the last 3 being defined as unions which could have multiple + * uses. The first 96 bytes had been completely unused until + * an index table was added to the directory. It is now more + * useful to describe the last 3/4 of the inode as a single + * union. We would probably be better off redesigning the + * entire structure from scratch, but we don't want to break + * commonality with OS/2's JFS at this time. + */ + union { + struct { + /* + * This table contains the information needed to + * find a directory entry from a 32-bit index. + * If the index is small enough, the table is inline, + * otherwise, an x-tree root overlays this table + */ + dir_table_slot_t _table[12]; /* 96: inline */ + + dtroot_t _dtroot; /* 288: dtree root */ + } _dir; /* (384) */ +#define di_dirtable u._dir._table +#define di_dtroot u._dir._dtroot +#define di_parent di_dtroot.header.idotdot +#define di_DASD di_dtroot.header.DASD + + struct { + union { + u8 _data[96]; /* 96: unused */ + struct { + void *_imap; /* 4: unused */ + u32 _gengen; /* 4: generator */ + } _imap; + } _u1; /* 96: */ +#define di_gengen u._file._u1._imap._gengen + + union { + xtpage_t _xtroot; + struct { + u8 unused[16]; /* 16: */ + dxd_t _dxd; /* 16: */ + union { + u32 _rdev; /* 4: */ + u8 _fastsymlink[128]; + } _u; + u8 _inlineea[128]; + } _special; + } _u2; + } _file; +#define di_xtroot u._file._u2._xtroot +#define di_dxd u._file._u2._special._dxd +#define di_btroot di_xtroot +#define di_inlinedata u._file._u2._special._u +#define di_rdev u._file._u2._special._u._rdev +#define di_fastsymlink u._file._u2._special._u._fastsymlink +#define di_inlineea u._file._u2._special._inlineea + } u; +}; + +typedef struct dinode dinode_t; + + +/* extended mode bits (on-disk inode di_mode) */ +#define IFJOURNAL 0x00010000 /* journalled file */ +#define ISPARSE 0x00020000 /* sparse file enabled */ +#define INLINEEA 0x00040000 /* inline EA area free */ +#define ISWAPFILE 0x00800000 /* file open for pager swap space */ + +/* more extended mode bits: attributes for OS/2 */ +#define IREADONLY 0x02000000 /* no write access to file */ +#define IARCHIVE 0x40000000 /* file archive bit */ +#define ISYSTEM 0x08000000 /* system file */ +#define IHIDDEN 0x04000000 /* hidden file */ +#define IRASH 0x4E000000 /* mask for changeable attributes */ +#define INEWNAME 0x80000000 /* non-8.3 filename format */ +#define IDIRECTORY 0x20000000 /* directory (shadow of real bit) */ +#define ATTRSHIFT 25 /* bits to shift to move attribute + specification to mode position */ + +#endif /*_H_JFS_DINODE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_dmap.c linux.20pre2-ac1/fs/jfs/jfs_dmap.c --- linux.20pre2/fs/jfs/jfs_dmap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_dmap.c 2002-08-06 18:01:05.000000000 +0100 @@ -0,0 +1,4177 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 "jfs_incore.h" +#include "jfs_dmap.h" +#include "jfs_imap.h" +#include "jfs_lock.h" +#include "jfs_metapage.h" +#include "jfs_debug.h" + +/* + * Debug code for double-checking block map + */ +/* #define _JFS_DEBUG_DMAP 1 */ + +#ifdef _JFS_DEBUG_DMAP +#define DBINITMAP(size,ipbmap,results) \ + DBinitmap(size,ipbmap,results) +#define DBALLOC(dbmap,mapsize,blkno,nblocks) \ + DBAlloc(dbmap,mapsize,blkno,nblocks) +#define DBFREE(dbmap,mapsize,blkno,nblocks) \ + DBFree(dbmap,mapsize,blkno,nblocks) +#define DBALLOCCK(dbmap,mapsize,blkno,nblocks) \ + DBAllocCK(dbmap,mapsize,blkno,nblocks) +#define DBFREECK(dbmap,mapsize,blkno,nblocks) \ + DBFreeCK(dbmap,mapsize,blkno,nblocks) + +static void DBinitmap(s64, struct inode *, u32 **); +static void DBAlloc(uint *, s64, s64, s64); +static void DBFree(uint *, s64, s64, s64); +static void DBAllocCK(uint *, s64, s64, s64); +static void DBFreeCK(uint *, s64, s64, s64); +#else +#define DBINITMAP(size,ipbmap,results) +#define DBALLOC(dbmap, mapsize, blkno, nblocks) +#define DBFREE(dbmap, mapsize, blkno, nblocks) +#define DBALLOCCK(dbmap, mapsize, blkno, nblocks) +#define DBFREECK(dbmap, mapsize, blkno, nblocks) +#endif /* _JFS_DEBUG_DMAP */ + +/* + * SERIALIZATION of the Block Allocation Map. + * + * the working state of the block allocation map is accessed in + * two directions: + * + * 1) allocation and free requests that start at the dmap + * level and move up through the dmap control pages (i.e. + * the vast majority of requests). + * + * 2) allocation requests that start at dmap control page + * level and work down towards the dmaps. + * + * the serialization scheme used here is as follows. + * + * requests which start at the bottom are serialized against each + * other through buffers and each requests holds onto its buffers + * as it works it way up from a single dmap to the required level + * of dmap control page. + * requests that start at the top are serialized against each other + * and request that start from the bottom by the multiple read/single + * write inode lock of the bmap inode. requests starting at the top + * take this lock in write mode while request starting at the bottom + * take the lock in read mode. a single top-down request may proceed + * exclusively while multiple bottoms-up requests may proceed + * simultaneously (under the protection of busy buffers). + * + * in addition to information found in dmaps and dmap control pages, + * the working state of the block allocation map also includes read/ + * write information maintained in the bmap descriptor (i.e. total + * free block count, allocation group level free block counts). + * a single exclusive lock (BMAP_LOCK) is used to guard this information + * in the face of multiple-bottoms up requests. + * (lock ordering: IREAD_LOCK, BMAP_LOCK); + * + * accesses to the persistent state of the block allocation map (limited + * to the persistent bitmaps in dmaps) is guarded by (busy) buffers. + */ + +#define BMAP_LOCK_INIT(bmp) init_MUTEX(&bmp->db_bmaplock) +#define BMAP_LOCK(bmp) down(&bmp->db_bmaplock) +#define BMAP_UNLOCK(bmp) up(&bmp->db_bmaplock) + +/* + * forward references + */ +static void dbAllocBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks); +static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval); +static void dbBackSplit(dmtree_t * tp, int leafno); +static void dbJoin(dmtree_t * tp, int leafno, int newval); +static void dbAdjTree(dmtree_t * tp, int leafno, int newval); +static int dbAdjCtl(bmap_t * bmp, s64 blkno, int newval, int alloc, + int level); +static int dbAllocAny(bmap_t * bmp, s64 nblocks, int l2nb, s64 * results); +static int dbAllocNext(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks); +static int dbAllocNear(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks, + int l2nb, s64 * results); +static int dbAllocDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks); +static int dbAllocDmapLev(bmap_t * bmp, dmap_t * dp, int nblocks, int l2nb, + s64 * results); +static int dbAllocAG(bmap_t * bmp, int agno, s64 nblocks, int l2nb, + s64 * results); +static int dbAllocCtl(bmap_t * bmp, s64 nblocks, int l2nb, s64 blkno, + s64 * results); +int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks); +static int dbFindBits(u32 word, int l2nb); +static int dbFindCtl(bmap_t * bmp, int l2nb, int level, s64 * blkno); +static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx); +static void dbFreeBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks); +static int dbFreeDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks); +static int dbMaxBud(u8 * cp); +s64 dbMapFileSizeToMapSize(struct inode *ipbmap); +int blkstol2(s64 nb); +void fsDirty(void); + +int cntlz(u32 value); +int cnttz(u32 word); + +static int dbAllocDmapBU(bmap_t * bmp, dmap_t * dp, s64 blkno, + int nblocks); +static int dbInitDmap(dmap_t * dp, s64 blkno, int nblocks); +static int dbInitDmapTree(dmap_t * dp); +static int dbInitTree(dmaptree_t * dtp); +static int dbInitDmapCtl(dmapctl_t * dcp, int level, int i); +static int dbGetL2AGSize(s64 nblocks); + +/* + * buddy table + * + * table used for determining buddy sizes within characters of + * dmap bitmap words. the characters themselves serve as indexes + * into the table, with the table elements yielding the maximum + * binary buddy of free bits within the character. + */ +signed char budtab[256] = { + 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 +}; + + +/* + * NAME: dbMount() + * + * FUNCTION: initializate the block allocation map. + * + * memory is allocated for the in-core bmap descriptor and + * the in-core descriptor is initialized from disk. + * + * PARAMETERS: + * ipbmap - pointer to in-core inode for the block map. + * + * RETURN VALUES: + * 0 - success + * ENOMEM - insufficient memory + * EIO - i/o error + */ +int dbMount(struct inode *ipbmap) +{ + bmap_t *bmp; + dbmap_t *dbmp_le; + metapage_t *mp; + int i; + + /* + * allocate/initialize the in-memory bmap descriptor + */ + /* allocate memory for the in-memory bmap descriptor */ + bmp = kmalloc(sizeof(bmap_t), GFP_KERNEL); + if (bmp == NULL) + return (ENOMEM); + + /* read the on-disk bmap descriptor. */ + mp = read_metapage(ipbmap, + BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage, + PSIZE, 0); + if (mp == NULL) { + kfree(bmp); + return (EIO); + } + + /* copy the on-disk bmap descriptor to its in-memory version. */ + dbmp_le = (dbmap_t *) mp->data; + bmp->db_mapsize = le64_to_cpu(dbmp_le->dn_mapsize); + bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree); + bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage); + bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag); + bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel); + bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag); + bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref); + bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel); + bmp->db_agheigth = le32_to_cpu(dbmp_le->dn_agheigth); + bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth); + bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart); + bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size); + for (i = 0; i < MAXAG; i++) + bmp->db_agfree[i] = le64_to_cpu(dbmp_le->dn_agfree[i]); + bmp->db_agsize = le64_to_cpu(dbmp_le->dn_agsize); + bmp->db_maxfreebud = dbmp_le->dn_maxfreebud; + + /* release the buffer. */ + release_metapage(mp); + + /* bind the bmap inode and the bmap descriptor to each other. */ + bmp->db_ipbmap = ipbmap; + JFS_SBI(ipbmap->i_sb)->bmap = bmp; + + DBINITMAP(bmp->db_mapsize, ipbmap, &bmp->db_DBmap); + + /* + * allocate/initialize the bmap lock + */ + BMAP_LOCK_INIT(bmp); + + return (0); +} + + +/* + * NAME: dbUnmount() + * + * FUNCTION: terminate the block allocation map in preparation for + * file system unmount. + * + * the in-core bmap descriptor is written to disk and + * the memory for this descriptor is freed. + * + * PARAMETERS: + * ipbmap - pointer to in-core inode for the block map. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error + */ +int dbUnmount(struct inode *ipbmap, int mounterror) +{ + bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap; + + if (!(mounterror || isReadOnly(ipbmap))) + dbSync(ipbmap); + + /* + * Invalidate the page cache buffers + */ + truncate_inode_pages(ipbmap->i_mapping, 0); + + /* free the memory for the in-memory bmap. */ + kfree(bmp); + + return (0); +} + +/* + * dbSync() + */ +int dbSync(struct inode *ipbmap) +{ + dbmap_t *dbmp_le; + bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap; + metapage_t *mp; + int i; + + /* + * write bmap global control page + */ + /* get the buffer for the on-disk bmap descriptor. */ + mp = read_metapage(ipbmap, + BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage, + PSIZE, 0); + if (mp == NULL) { + jERROR(1,("dbSync: read_metapage failed!\n")); + return (EIO); + } + /* copy the in-memory version of the bmap to the on-disk version */ + dbmp_le = (dbmap_t *) mp->data; + dbmp_le->dn_mapsize = cpu_to_le64(bmp->db_mapsize); + dbmp_le->dn_nfree = cpu_to_le64(bmp->db_nfree); + dbmp_le->dn_l2nbperpage = cpu_to_le32(bmp->db_l2nbperpage); + dbmp_le->dn_numag = cpu_to_le32(bmp->db_numag); + dbmp_le->dn_maxlevel = cpu_to_le32(bmp->db_maxlevel); + dbmp_le->dn_maxag = cpu_to_le32(bmp->db_maxag); + dbmp_le->dn_agpref = cpu_to_le32(bmp->db_agpref); + dbmp_le->dn_aglevel = cpu_to_le32(bmp->db_aglevel); + dbmp_le->dn_agheigth = cpu_to_le32(bmp->db_agheigth); + dbmp_le->dn_agwidth = cpu_to_le32(bmp->db_agwidth); + dbmp_le->dn_agstart = cpu_to_le32(bmp->db_agstart); + dbmp_le->dn_agl2size = cpu_to_le32(bmp->db_agl2size); + for (i = 0; i < MAXAG; i++) + dbmp_le->dn_agfree[i] = cpu_to_le64(bmp->db_agfree[i]); + dbmp_le->dn_agsize = cpu_to_le64(bmp->db_agsize); + dbmp_le->dn_maxfreebud = bmp->db_maxfreebud; + + /* write the buffer */ + write_metapage(mp); + + /* + * write out dirty pages of bmap + */ + fsync_inode_data_buffers(ipbmap); + + ipbmap->i_state |= I_DIRTY; + diWriteSpecial(ipbmap, 0); + + return (0); +} + + +/* + * NAME: dbFree() + * + * FUNCTION: free the specified block range from the working block + * allocation map. + * + * the blocks will be free from the working map one dmap + * at a time. + * + * PARAMETERS: + * ip - pointer to in-core inode; + * blkno - starting block number to be freed. + * nblocks - number of blocks to be freed. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error + */ +int dbFree(struct inode *ip, s64 blkno, s64 nblocks) +{ + metapage_t *mp; + dmap_t *dp; + int nb, rc; + s64 lblkno, rem; + struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; + bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap; + + IREAD_LOCK(ipbmap); + + /* block to be freed better be within the mapsize. */ + assert(blkno + nblocks <= bmp->db_mapsize); + + /* + * free the blocks a dmap at a time. + */ + mp = NULL; + for (rem = nblocks; rem > 0; rem -= nb, blkno += nb) { + /* release previous dmap if any */ + if (mp) { + write_metapage(mp); + } + + /* get the buffer for the current dmap. */ + lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage); + mp = read_metapage(ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) { + IREAD_UNLOCK(ipbmap); + return (EIO); + } + dp = (dmap_t *) mp->data; + + /* determine the number of blocks to be freed from + * this dmap. + */ + nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1))); + + DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nb); + + /* free the blocks. */ + if ((rc = dbFreeDmap(bmp, dp, blkno, nb))) { + release_metapage(mp); + IREAD_UNLOCK(ipbmap); + return (rc); + } + + DBFREE(bmp->db_DBmap, bmp->db_mapsize, blkno, nb); + } + + /* write the last buffer. */ + write_metapage(mp); + + IREAD_UNLOCK(ipbmap); + + return (0); +} + + +/* + * NAME: dbUpdatePMap() + * + * FUNCTION: update the allocation state (free or allocate) of the + * specified block range in the persistent block allocation map. + * + * the blocks will be updated in the persistent map one + * dmap at a time. + * + * PARAMETERS: + * ipbmap - pointer to in-core inode for the block map. + * free - TRUE if block range is to be freed from the persistent + * map; FALSE if it is to be allocated. + * blkno - starting block number of the range. + * nblocks - number of contiguous blocks in the range. + * tblk - transaction block; + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error + */ +int +dbUpdatePMap(struct inode *ipbmap, + int free, s64 blkno, s64 nblocks, tblock_t * tblk) +{ + int nblks, dbitno, wbitno, rbits; + int word, nbits, nwords; + bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap; + s64 lblkno, rem, lastlblkno; + u32 mask; + dmap_t *dp; + metapage_t *mp; + log_t *log; + int lsn, difft, diffp; + + /* the blocks better be within the mapsize. */ + assert(blkno + nblocks <= bmp->db_mapsize); + + /* compute delta of transaction lsn from log syncpt */ + lsn = tblk->lsn; + log = (log_t *) JFS_SBI(tblk->sb)->log; + logdiff(difft, lsn, log); + + /* + * update the block state a dmap at a time. + */ + mp = NULL; + lastlblkno = 0; + for (rem = nblocks; rem > 0; rem -= nblks, blkno += nblks) { + /* get the buffer for the current dmap. */ + lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage); + if (lblkno != lastlblkno) { + if (mp) { + write_metapage(mp); + } + + mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, + 0); + if (mp == NULL) + return (EIO); + } + dp = (dmap_t *) mp->data; + + /* determine the bit number and word within the dmap of + * the starting block. also determine how many blocks + * are to be updated within this dmap. + */ + dbitno = blkno & (BPERDMAP - 1); + word = dbitno >> L2DBWORD; + nblks = min(rem, (s64)BPERDMAP - dbitno); + + /* update the bits of the dmap words. the first and last + * words may only have a subset of their bits updated. if + * this is the case, we'll work against that word (i.e. + * partial first and/or last) only in a single pass. a + * single pass will also be used to update all words that + * are to have all their bits updated. + */ + for (rbits = nblks; rbits > 0; + rbits -= nbits, dbitno += nbits) { + /* determine the bit number within the word and + * the number of bits within the word. + */ + wbitno = dbitno & (DBWORD - 1); + nbits = min(rbits, DBWORD - wbitno); + + /* check if only part of the word is to be updated. */ + if (nbits < DBWORD) { + /* update (free or allocate) the bits + * in this word. + */ + mask = + (ONES << (DBWORD - nbits) >> wbitno); + if (free) + dp->pmap[word] &= + cpu_to_le32(~mask); + else + dp->pmap[word] |= + cpu_to_le32(mask); + + word += 1; + } else { + /* one or more words are to have all + * their bits updated. determine how + * many words and how many bits. + */ + nwords = rbits >> L2DBWORD; + nbits = nwords << L2DBWORD; + + /* update (free or allocate) the bits + * in these words. + */ + if (free) + memset(&dp->pmap[word], 0, + nwords * 4); + else + memset(&dp->pmap[word], (int) ONES, + nwords * 4); + + word += nwords; + } + } + + /* + * update dmap lsn + */ + if (lblkno == lastlblkno) + continue; + + lastlblkno = lblkno; + + if (mp->lsn != 0) { + /* inherit older/smaller lsn */ + logdiff(diffp, mp->lsn, log); + if (difft < diffp) { + mp->lsn = lsn; + + /* move bp after tblock in logsync list */ + LOGSYNC_LOCK(log); + list_del(&mp->synclist); + list_add(&mp->synclist, &tblk->synclist); + LOGSYNC_UNLOCK(log); + } + + /* inherit younger/larger clsn */ + LOGSYNC_LOCK(log); + logdiff(difft, tblk->clsn, log); + logdiff(diffp, mp->clsn, log); + if (difft > diffp) + mp->clsn = tblk->clsn; + LOGSYNC_UNLOCK(log); + } else { + mp->log = log; + mp->lsn = lsn; + + /* insert bp after tblock in logsync list */ + LOGSYNC_LOCK(log); + + log->count++; + list_add(&mp->synclist, &tblk->synclist); + + mp->clsn = tblk->clsn; + LOGSYNC_UNLOCK(log); + } + } + + /* write the last buffer. */ + if (mp) { + write_metapage(mp); + } + + return (0); +} + + +/* + * NAME: dbNextAG() + * + * FUNCTION: find the preferred allocation group for new allocations. + * + * we try to keep the trailing (rightmost) allocation groups + * free for large allocations. we try to do this by targeting + * new inode allocations towards the leftmost or 'active' + * allocation groups while keeping the rightmost or 'inactive' + * allocation groups free. once the active allocation groups + * have dropped to a certain percentage of free space, we add + * the leftmost inactive allocation group to the active set. + * + * within the active allocation groups, we maintain a preferred + * allocation group which consists of a group with at least + * average free space over the active set. it is the preferred + * group that we target new inode allocation towards. the + * tie-in between inode allocation and block allocation occurs + * as we allocate the first (data) block of an inode and specify + * the inode (block) as the allocation hint for this block. + * + * PARAMETERS: + * ipbmap - pointer to in-core inode for the block map. + * + * RETURN VALUES: + * the preferred allocation group number. + * + * note: only called by dbAlloc(); + */ +int dbNextAG(struct inode *ipbmap) +{ + s64 avgfree, inactfree, actfree, rem; + int actags, inactags, l2agsize; + bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap; + + BMAP_LOCK(bmp); + + /* determine the number of active allocation groups (i.e. + * the number of allocation groups up to and including + * the rightmost allocation group with blocks allocated + * in it. + */ + actags = bmp->db_maxag + 1; + assert(actags <= bmp->db_numag); + + /* get the number of inactive allocation groups (i.e. the + * number of allocation group following the rightmost group + * with allocation in it. + */ + inactags = bmp->db_numag - actags; + + /* determine how many blocks are in the inactive allocation + * groups. in doing this, we must account for the fact that + * the rightmost group might be a partial group (i.e. file + * system size is not a multiple of the group size). + */ + l2agsize = bmp->db_agl2size; + rem = bmp->db_mapsize & (bmp->db_agsize - 1); + inactfree = (inactags + && rem) ? ((inactags - 1) << l2agsize) + + rem : inactags << l2agsize; + + /* now determine how many free blocks are in the active + * allocation groups plus the average number of free blocks + * within the active ags. + */ + actfree = bmp->db_nfree - inactfree; + avgfree = (u32) actfree / (u32) actags; + + /* check if not all of the allocation groups are active. + */ + if (actags < bmp->db_numag) { + /* not all of the allocation groups are active. determine + * if we should extend the active set by 1 (i.e. add the + * group following the current active set). we do so if + * the number of free blocks within the active set is less + * than the allocation group set and average free within + * the active set is less than 60%. we activate a new group + * by setting the allocation group preference to the new + * group. + */ + if (actfree < bmp->db_agsize && + ((avgfree * 100) >> l2agsize) < 60) + bmp->db_agpref = actags; + } else { + /* all allocation groups are in the active set. check if + * the preferred allocation group has average free space. + * if not, re-establish the preferred group as the leftmost + * group with average free space. + */ + if (bmp->db_agfree[bmp->db_agpref] < avgfree) { + for (bmp->db_agpref = 0; bmp->db_agpref < actags; + bmp->db_agpref++) { + if (bmp->db_agfree[bmp->db_agpref] <= + avgfree) + break; + } + assert(bmp->db_agpref < bmp->db_numag); + } + } + + BMAP_UNLOCK(bmp); + + /* return the preferred group. + */ + return (bmp->db_agpref); +} + + +/* + * NAME: dbAlloc() + * + * FUNCTION: attempt to allocate a specified number of contiguous free + * blocks from the working allocation block map. + * + * the block allocation policy uses hints and a multi-step + * approach. + * + * for allocation requests smaller than the number of blocks + * per dmap, we first try to allocate the new blocks + * immediately following the hint. if these blocks are not + * available, we try to allocate blocks near the hint. if + * no blocks near the hint are available, we next try to + * allocate within the same dmap as contains the hint. + * + * if no blocks are available in the dmap or the allocation + * request is larger than the dmap size, we try to allocate + * within the same allocation group as contains the hint. if + * this does not succeed, we finally try to allocate anywhere + * within the aggregate. + * + * we also try to allocate anywhere within the aggregate for + * for allocation requests larger than the allocation group + * size or requests that specify no hint value. + * + * PARAMETERS: + * ip - pointer to in-core inode; + * hint - allocation hint. + * nblocks - number of contiguous blocks in the range. + * results - on successful return, set to the starting block number + * of the newly allocated contiguous range. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + */ +int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) +{ + int rc, agno; + struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; + bmap_t *bmp; + metapage_t *mp; + s64 lblkno, blkno; + dmap_t *dp; + int l2nb; + s64 mapSize; + + /* assert that nblocks is valid */ + assert(nblocks > 0); + +#ifdef _STILL_TO_PORT + /* DASD limit check F226941 */ + if (OVER_LIMIT(ip, nblocks)) + return ENOSPC; +#endif /* _STILL_TO_PORT */ + + /* get the log2 number of blocks to be allocated. + * if the number of blocks is not a log2 multiple, + * it will be rounded up to the next log2 multiple. + */ + l2nb = BLKSTOL2(nblocks); + + bmp = JFS_SBI(ip->i_sb)->bmap; + +//retry: /* serialize w.r.t.extendfs() */ + mapSize = bmp->db_mapsize; + + /* the hint should be within the map */ + assert(hint < mapSize); + + /* if no hint was specified or the number of blocks to be + * allocated is greater than the allocation group size, try + * to allocate anywhere. + */ + if (hint == 0 || l2nb > bmp->db_agl2size) { + IWRITE_LOCK(ipbmap); + + rc = dbAllocAny(bmp, nblocks, l2nb, results); + if (rc == 0) { + DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, + nblocks); + } + + goto write_unlock; + } + + /* we would like to allocate close to the hint. adjust the + * hint to the block following the hint since the allocators + * will start looking for free space starting at this point. + * if the hint was the last block of the file system, try to + * allocate in the same allocation group as the hint. + */ + blkno = hint + 1; + if (blkno >= bmp->db_mapsize) { + blkno--; + goto tryag; + } + + /* check if blkno crosses over into a new allocation group. + * if so, check if we should allow allocations within this + * allocation group. we try to keep the trailing (rightmost) + * allocation groups of the file system free for large + * allocations and may want to prevent this allocation from + * spilling over into this space. + */ + if ((blkno & (bmp->db_agsize - 1)) == 0) { + /* check if the AG is beyond the rightmost AG with + * allocations in it. if so, call dbNextAG() to + * determine if the allocation should be allowed + * to proceed within this AG or should be targeted + * to another AG. + */ + agno = blkno >> bmp->db_agl2size; + if (agno > bmp->db_maxag) { + agno = dbNextAG(ipbmap); + blkno = (s64) agno << bmp->db_agl2size; + goto tryag; + } + } + + /* check if the allocation request size can be satisfied from a + * single dmap. if so, try to allocate from the dmap containing + * the hint using a tiered strategy. + */ + if (nblocks <= BPERDMAP) { + IREAD_LOCK(ipbmap); + + /* get the buffer for the dmap containing the hint. + */ + rc = EIO; + lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage); + mp = read_metapage(ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) + goto read_unlock; + + dp = (dmap_t *) mp->data; + + /* first, try to satisfy the allocation request with the + * blocks beginning at the hint. + */ + if ((rc = + dbAllocNext(bmp, dp, blkno, + (int) nblocks)) != ENOSPC) { + if (rc == 0) { + *results = blkno; + DBALLOC(bmp->db_DBmap, bmp->db_mapsize, + *results, nblocks); + mark_metapage_dirty(mp); + } + + release_metapage(mp); + goto read_unlock; + } + + /* next, try to satisfy the allocation request with blocks + * near the hint. + */ + if ((rc = + dbAllocNear(bmp, dp, blkno, (int) nblocks, l2nb, + results)) + != ENOSPC) { + if (rc == 0) { + DBALLOC(bmp->db_DBmap, bmp->db_mapsize, + *results, nblocks); + mark_metapage_dirty(mp); + } + + release_metapage(mp); + goto read_unlock; + } + + /* try to satisfy the allocation request with blocks within + * the same allocation group as the hint. + */ + if ((rc = + dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results)) + != ENOSPC) { + if (rc == 0) { + DBALLOC(bmp->db_DBmap, bmp->db_mapsize, + *results, nblocks); + mark_metapage_dirty(mp); + } + + release_metapage(mp); + goto read_unlock; + } + + release_metapage(mp); + IREAD_UNLOCK(ipbmap); + } + + tryag: + IWRITE_LOCK(ipbmap); + + /* determine the allocation group number of the hint and try to + * allocate within this allocation group. if that fails, try to + * allocate anywhere in the map. + */ + agno = blkno >> bmp->db_agl2size; + if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) == ENOSPC) + rc = dbAllocAny(bmp, nblocks, l2nb, results); + if (rc == 0) { + DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks); + } + + write_unlock: + IWRITE_UNLOCK(ipbmap); + + return (rc); + + read_unlock: + IREAD_UNLOCK(ipbmap); + + return (rc); +} + + +/* + * NAME: dbAllocExact() + * + * FUNCTION: try to allocate the requested extent; + * + * PARAMETERS: + * ip - pointer to in-core inode; + * blkno - extent address; + * nblocks - extent length; + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + */ +int dbAllocExact(struct inode *ip, s64 blkno, int nblocks) +{ + int rc; + struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; + bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap; + dmap_t *dp; + s64 lblkno; + metapage_t *mp; + + IREAD_LOCK(ipbmap); + + /* + * validate extent request: + * + * note: defragfs policy: + * max 64 blocks will be moved. + * allocation request size must be satisfied from a single dmap. + */ + if (nblocks <= 0 || nblocks > BPERDMAP || blkno >= bmp->db_mapsize) { + IREAD_UNLOCK(ipbmap); + return EINVAL; + } + + if (nblocks > ((s64) 1 << bmp->db_maxfreebud)) { + /* the free space is no longer available */ + IREAD_UNLOCK(ipbmap); + return ENOSPC; + } + + /* read in the dmap covering the extent */ + lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage); + mp = read_metapage(ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) { + IREAD_UNLOCK(ipbmap); + return (EIO); + } + dp = (dmap_t *) mp->data; + + /* try to allocate the requested extent */ + rc = dbAllocNext(bmp, dp, blkno, nblocks); + + IREAD_UNLOCK(ipbmap); + + if (rc == 0) { + DBALLOC(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks); + mark_metapage_dirty(mp); + } + release_metapage(mp); + + return (rc); +} + + +/* + * NAME: dbReAlloc() + * + * FUNCTION: attempt to extend a current allocation by a specified + * number of blocks. + * + * this routine attempts to satisfy the allocation request + * by first trying to extend the existing allocation in + * place by allocating the additional blocks as the blocks + * immediately following the current allocation. if these + * blocks are not available, this routine will attempt to + * allocate a new set of contiguous blocks large enough + * to cover the existing allocation plus the additional + * number of blocks required. + * + * PARAMETERS: + * ip - pointer to in-core inode requiring allocation. + * blkno - starting block of the current allocation. + * nblocks - number of contiguous blocks within the current + * allocation. + * addnblocks - number of blocks to add to the allocation. + * results - on successful return, set to the starting block number + * of the existing allocation if the existing allocation + * was extended in place or to a newly allocated contiguous + * range if the existing allocation could not be extended + * in place. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + */ +int +dbReAlloc(struct inode *ip, + s64 blkno, s64 nblocks, s64 addnblocks, s64 * results) +{ + int rc; + + /* try to extend the allocation in place. + */ + if ((rc = dbExtend(ip, blkno, nblocks, addnblocks)) == 0) { + *results = blkno; + return (0); + } else { + if (rc != ENOSPC) + return (rc); + } + + /* could not extend the allocation in place, so allocate a + * new set of blocks for the entire request (i.e. try to get + * a range of contiguous blocks large enough to cover the + * existing allocation plus the additional blocks.) + */ + return (dbAlloc + (ip, blkno + nblocks - 1, addnblocks + nblocks, results)); +} + + +/* + * NAME: dbExtend() + * + * FUNCTION: attempt to extend a current allocation by a specified + * number of blocks. + * + * this routine attempts to satisfy the allocation request + * by first trying to extend the existing allocation in + * place by allocating the additional blocks as the blocks + * immediately following the current allocation. + * + * PARAMETERS: + * ip - pointer to in-core inode requiring allocation. + * blkno - starting block of the current allocation. + * nblocks - number of contiguous blocks within the current + * allocation. + * addnblocks - number of blocks to add to the allocation. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + */ +int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) +{ + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + s64 lblkno, lastblkno, extblkno; + uint rel_block; + metapage_t *mp; + dmap_t *dp; + int rc; + struct inode *ipbmap = sbi->ipbmap; + bmap_t *bmp; + + /* + * We don't want a non-aligned extent to cross a page boundary + */ + if (((rel_block = blkno & (sbi->nbperpage - 1))) && + (rel_block + nblocks + addnblocks > sbi->nbperpage)) + return (ENOSPC); + + /* get the last block of the current allocation */ + lastblkno = blkno + nblocks - 1; + + /* determine the block number of the block following + * the existing allocation. + */ + extblkno = lastblkno + 1; + + IREAD_LOCK(ipbmap); + + /* better be within the file system */ + bmp = sbi->bmap; + assert(lastblkno >= 0 && lastblkno < bmp->db_mapsize); + + /* we'll attempt to extend the current allocation in place by + * allocating the additional blocks as the blocks immediately + * following the current allocation. we only try to extend the + * current allocation in place if the number of additional blocks + * can fit into a dmap, the last block of the current allocation + * is not the last block of the file system, and the start of the + * inplace extension is not on an allocation group boundry. + */ + if (addnblocks > BPERDMAP || extblkno >= bmp->db_mapsize || + (extblkno & (bmp->db_agsize - 1)) == 0) { + IREAD_UNLOCK(ipbmap); + return (ENOSPC); + } + + /* get the buffer for the dmap containing the first block + * of the extension. + */ + lblkno = BLKTODMAP(extblkno, bmp->db_l2nbperpage); + mp = read_metapage(ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) { + IREAD_UNLOCK(ipbmap); + return (EIO); + } + + DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks); + dp = (dmap_t *) mp->data; + + /* try to allocate the blocks immediately following the + * current allocation. + */ + rc = dbAllocNext(bmp, dp, extblkno, (int) addnblocks); + + IREAD_UNLOCK(ipbmap); + + /* were we successful ? */ + if (rc == 0) { + DBALLOC(bmp->db_DBmap, bmp->db_mapsize, extblkno, + addnblocks); + write_metapage(mp); + } else { + /* we were not successful */ + release_metapage(mp); + assert(rc == ENOSPC || rc == EIO); + } + + return (rc); +} + + +/* + * NAME: dbAllocNext() + * + * FUNCTION: attempt to allocate the blocks of the specified block + * range within a dmap. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * dp - pointer to dmap. + * blkno - starting block number of the range. + * nblocks - number of contiguous free blocks of the range. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + * + * serialization: IREAD_LOCK(ipbmap) held on entry/exit; + */ +static int dbAllocNext(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks) +{ + int dbitno, word, rembits, nb, nwords, wbitno, nw; + int l2size; + s8 *leaf; + u32 mask; + + /* pick up a pointer to the leaves of the dmap tree. + */ + leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx); + + /* determine the bit number and word within the dmap of the + * starting block. + */ + dbitno = blkno & (BPERDMAP - 1); + word = dbitno >> L2DBWORD; + + /* check if the specified block range is contained within + * this dmap. + */ + if (dbitno + nblocks > BPERDMAP) + return (ENOSPC); + + /* check if the starting leaf indicates that anything + * is free. + */ + if (leaf[word] == NOFREE) + return (ENOSPC); + + /* check the dmaps words corresponding to block range to see + * if the block range is free. not all bits of the first and + * last words may be contained within the block range. if this + * is the case, we'll work against those words (i.e. partial first + * and/or last) on an individual basis (a single pass) and examine + * the actual bits to determine if they are free. a single pass + * will be used for all dmap words fully contained within the + * specified range. within this pass, the leaves of the dmap + * tree will be examined to determine if the blocks are free. a + * single leaf may describe the free space of multiple dmap + * words, so we may visit only a subset of the actual leaves + * corresponding to the dmap words of the block range. + */ + for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) { + /* determine the bit number within the word and + * the number of bits within the word. + */ + wbitno = dbitno & (DBWORD - 1); + nb = min(rembits, DBWORD - wbitno); + + /* check if only part of the word is to be examined. + */ + if (nb < DBWORD) { + /* check if the bits are free. + */ + mask = (ONES << (DBWORD - nb) >> wbitno); + if ((mask & ~le32_to_cpu(dp->wmap[word])) != mask) + return (ENOSPC); + + word += 1; + } else { + /* one or more dmap words are fully contained + * within the block range. determine how many + * words and how many bits. + */ + nwords = rembits >> L2DBWORD; + nb = nwords << L2DBWORD; + + /* now examine the appropriate leaves to determine + * if the blocks are free. + */ + while (nwords > 0) { + /* does the leaf describe any free space ? + */ + if (leaf[word] < BUDMIN) + return (ENOSPC); + + /* determine the l2 number of bits provided + * by this leaf. + */ + l2size = + min((int)leaf[word], NLSTOL2BSZ(nwords)); + + /* determine how many words were handled. + */ + nw = BUDSIZE(l2size, BUDMIN); + + nwords -= nw; + word += nw; + } + } + } + + /* allocate the blocks. + */ + return (dbAllocDmap(bmp, dp, blkno, nblocks)); +} + + +/* + * NAME: dbAllocNear() + * + * FUNCTION: attempt to allocate a number of contiguous free blocks near + * a specified block (hint) within a dmap. + * + * starting with the dmap leaf that covers the hint, we'll + * check the next four contiguous leaves for sufficient free + * space. if sufficient free space is found, we'll allocate + * the desired free space. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * dp - pointer to dmap. + * blkno - block number to allocate near. + * nblocks - actual number of contiguous free blocks desired. + * l2nb - log2 number of contiguous free blocks desired. + * results - on successful return, set to the starting block number + * of the newly allocated range. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + * + * serialization: IREAD_LOCK(ipbmap) held on entry/exit; + */ +static int +dbAllocNear(bmap_t * bmp, + dmap_t * dp, s64 blkno, int nblocks, int l2nb, s64 * results) +{ + int word, lword, rc; + s8 *leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx); + + /* determine the word within the dmap that holds the hint + * (i.e. blkno). also, determine the last word in the dmap + * that we'll include in our examination. + */ + word = (blkno & (BPERDMAP - 1)) >> L2DBWORD; + lword = min(word + 4, LPERDMAP); + + /* examine the leaves for sufficient free space. + */ + for (; word < lword; word++) { + /* does the leaf describe sufficient free space ? + */ + if (leaf[word] < l2nb) + continue; + + /* determine the block number within the file system + * of the first block described by this dmap word. + */ + blkno = le64_to_cpu(dp->start) + (word << L2DBWORD); + + /* if not all bits of the dmap word are free, get the + * starting bit number within the dmap word of the required + * string of free bits and adjust the block number with the + * value. + */ + if (leaf[word] < BUDMIN) + blkno += + dbFindBits(le32_to_cpu(dp->wmap[word]), l2nb); + + /* allocate the blocks. + */ + if ((rc = dbAllocDmap(bmp, dp, blkno, nblocks)) == 0) + *results = blkno; + + return (rc); + } + + return (ENOSPC); +} + + +/* + * NAME: dbAllocAG() + * + * FUNCTION: attempt to allocate the specified number of contiguous + * free blocks within the specified allocation group. + * + * unless the allocation group size is equal to the number + * of blocks per dmap, the dmap control pages will be used to + * find the required free space, if available. we start the + * search at the highest dmap control page level which + * distinctly describes the allocation group's free space + * (i.e. the highest level at which the allocation group's + * free space is not mixed in with that of any other group). + * in addition, we start the search within this level at a + * height of the dmapctl dmtree at which the nodes distinctly + * describe the allocation group's free space. at this height, + * the allocation group's free space may be represented by 1 + * or two sub-trees, depending on the allocation group size. + * we search the top nodes of these subtrees left to right for + * sufficient free space. if sufficient free space is found, + * the subtree is searched to find the leftmost leaf that + * has free space. once we have made it to the leaf, we + * move the search to the next lower level dmap control page + * corresponding to this leaf. we continue down the dmap control + * pages until we find the dmap that contains or starts the + * sufficient free space and we allocate at this dmap. + * + * if the allocation group size is equal to the dmap size, + * we'll start at the dmap corresponding to the allocation + * group and attempt the allocation at this level. + * + * the dmap control page search is also not performed if the + * allocation group is completely free and we go to the first + * dmap of the allocation group to do the allocation. this is + * done because the allocation group may be part (not the first + * part) of a larger binary buddy system, causing the dmap + * control pages to indicate no free space (NOFREE) within + * the allocation group. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * agno - allocation group number. + * nblocks - actual number of contiguous free blocks desired. + * l2nb - log2 number of contiguous free blocks desired. + * results - on successful return, set to the starting block number + * of the newly allocated range. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + * + * note: IWRITE_LOCK(ipmap) held on entry/exit; + */ +static int +dbAllocAG(bmap_t * bmp, int agno, s64 nblocks, int l2nb, s64 * results) +{ + metapage_t *mp; + dmapctl_t *dcp; + int rc, ti, i, k, m, n, agperlev; + s64 blkno, lblkno; + int budmin; + + /* allocation request should not be for more than the + * allocation group size. + */ + assert(l2nb <= bmp->db_agl2size); + + /* determine the starting block number of the allocation + * group. + */ + blkno = (s64) agno << bmp->db_agl2size; + + /* check if the allocation group size is the minimum allocation + * group size or if the allocation group is completely free. if + * the allocation group size is the minimum size of BPERDMAP (i.e. + * 1 dmap), there is no need to search the dmap control page (below) + * that fully describes the allocation group since the allocation + * group is already fully described by a dmap. in this case, we + * just call dbAllocCtl() to search the dmap tree and allocate the + * required space if available. + * + * if the allocation group is completely free, dbAllocCtl() is + * also called to allocate the required space. this is done for + * two reasons. first, it makes no sense searching the dmap control + * pages for free space when we know that free space exists. second, + * the dmap control pages may indicate that the allocation group + * has no free space if the allocation group is part (not the first + * part) of a larger binary buddy system. + */ + if (bmp->db_agsize == BPERDMAP + || bmp->db_agfree[agno] == bmp->db_agsize) { + rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); + /* assert(!(rc == ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */ + if ((rc == ENOSPC) && + (bmp->db_agfree[agno] == bmp->db_agsize)) { + jERROR(1, + ("dbAllocAG: removed assert, but still need to debug here\nblkno = 0x%Lx, nblocks = 0x%Lx\n", + (unsigned long long) blkno, + (unsigned long long) nblocks)); + } + return (rc); + } + + /* the buffer for the dmap control page that fully describes the + * allocation group. + */ + lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, bmp->db_aglevel); + mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) + return (EIO); + dcp = (dmapctl_t *) mp->data; + budmin = dcp->budmin; + + /* search the subtree(s) of the dmap control page that describes + * the allocation group, looking for sufficient free space. to begin, + * determine how many allocation groups are represented in a dmap + * control page at the control page level (i.e. L0, L1, L2) that + * fully describes an allocation group. next, determine the starting + * tree index of this allocation group within the control page. + */ + agperlev = + (1 << (L2LPERCTL - (bmp->db_agheigth << 1))) / bmp->db_agwidth; + ti = bmp->db_agstart + bmp->db_agwidth * (agno & (agperlev - 1)); + + /* dmap control page trees fan-out by 4 and a single allocation + * group may be described by 1 or 2 subtrees within the ag level + * dmap control page, depending upon the ag size. examine the ag's + * subtrees for sufficient free space, starting with the leftmost + * subtree. + */ + for (i = 0; i < bmp->db_agwidth; i++, ti++) { + /* is there sufficient free space ? + */ + if (l2nb > dcp->stree[ti]) + continue; + + /* sufficient free space found in a subtree. now search down + * the subtree to find the leftmost leaf that describes this + * free space. + */ + for (k = bmp->db_agheigth; k > 0; k--) { + for (n = 0, m = (ti << 2) + 1; n < 4; n++) { + if (l2nb <= dcp->stree[m + n]) { + ti = m + n; + break; + } + } + assert(n < 4); + } + + /* determine the block number within the file system + * that corresponds to this leaf. + */ + if (bmp->db_aglevel == 2) + blkno = 0; + else if (bmp->db_aglevel == 1) + blkno &= ~(MAXL1SIZE - 1); + else /* bmp->db_aglevel == 0 */ + blkno &= ~(MAXL0SIZE - 1); + + blkno += + ((s64) (ti - le32_to_cpu(dcp->leafidx))) << budmin; + + /* release the buffer in preparation for going down + * the next level of dmap control pages. + */ + release_metapage(mp); + + /* check if we need to continue to search down the lower + * level dmap control pages. we need to if the number of + * blocks required is less than maximum number of blocks + * described at the next lower level. + */ + if (l2nb < budmin) { + + /* search the lower level dmap control pages to get + * the starting block number of the the dmap that + * contains or starts off the free space. + */ + if ((rc = + dbFindCtl(bmp, l2nb, bmp->db_aglevel - 1, + &blkno))) { + assert(rc != ENOSPC); + return (rc); + } + } + + /* allocate the blocks. + */ + rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); + assert(rc != ENOSPC); + return (rc); + } + + /* no space in the allocation group. release the buffer and + * return ENOSPC. + */ + release_metapage(mp); + + return (ENOSPC); +} + + +/* + * NAME: dbAllocAny() + * + * FUNCTION: attempt to allocate the specified number of contiguous + * free blocks anywhere in the file system. + * + * dbAllocAny() attempts to find the sufficient free space by + * searching down the dmap control pages, starting with the + * highest level (i.e. L0, L1, L2) control page. if free space + * large enough to satisfy the desired free space is found, the + * desired free space is allocated. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * nblocks - actual number of contiguous free blocks desired. + * l2nb - log2 number of contiguous free blocks desired. + * results - on successful return, set to the starting block number + * of the newly allocated range. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + * + * serialization: IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static int dbAllocAny(bmap_t * bmp, s64 nblocks, int l2nb, s64 * results) +{ + int rc; + s64 blkno = 0; + + /* starting with the top level dmap control page, search + * down the dmap control levels for sufficient free space. + * if free space is found, dbFindCtl() returns the starting + * block number of the dmap that contains or starts off the + * range of free space. + */ + if ((rc = dbFindCtl(bmp, l2nb, bmp->db_maxlevel, &blkno))) + return (rc); + + /* allocate the blocks. + */ + rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); + assert(rc != ENOSPC); + return (rc); +} + + +/* + * NAME: dbFindCtl() + * + * FUNCTION: starting at a specified dmap control page level and block + * number, search down the dmap control levels for a range of + * contiguous free blocks large enough to satisfy an allocation + * request for the specified number of free blocks. + * + * if sufficient contiguous free blocks are found, this routine + * returns the starting block number within a dmap page that + * contains or starts a range of contiqious free blocks that + * is sufficient in size. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * level - starting dmap control page level. + * l2nb - log2 number of contiguous free blocks desired. + * *blkno - on entry, starting block number for conducting the search. + * on successful return, the first block within a dmap page + * that contains or starts a range of contiguous free blocks. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + * + * serialization: IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static int dbFindCtl(bmap_t * bmp, int l2nb, int level, s64 * blkno) +{ + int rc, leafidx, lev; + s64 b, lblkno; + dmapctl_t *dcp; + int budmin; + metapage_t *mp; + + /* starting at the specified dmap control page level and block + * number, search down the dmap control levels for the starting + * block number of a dmap page that contains or starts off + * sufficient free blocks. + */ + for (lev = level, b = *blkno; lev >= 0; lev--) { + /* get the buffer of the dmap control page for the block + * number and level (i.e. L0, L1, L2). + */ + lblkno = BLKTOCTL(b, bmp->db_l2nbperpage, lev); + mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) + return (EIO); + dcp = (dmapctl_t *) mp->data; + budmin = dcp->budmin; + + /* search the tree within the dmap control page for + * sufficent free space. if sufficient free space is found, + * dbFindLeaf() returns the index of the leaf at which + * free space was found. + */ + rc = dbFindLeaf((dmtree_t *) dcp, l2nb, &leafidx); + + /* release the buffer. + */ + release_metapage(mp); + + /* space found ? + */ + if (rc) { + assert(lev == level); + return (ENOSPC); + } + + /* adjust the block number to reflect the location within + * the dmap control page (i.e. the leaf) at which free + * space was found. + */ + b += (((s64) leafidx) << budmin); + + /* we stop the search at this dmap control page level if + * the number of blocks required is greater than or equal + * to the maximum number of blocks described at the next + * (lower) level. + */ + if (l2nb >= budmin) + break; + } + + *blkno = b; + return (0); +} + + +/* + * NAME: dbAllocCtl() + * + * FUNCTION: attempt to allocate a specified number of contiguous + * blocks starting within a specific dmap. + * + * this routine is called by higher level routines that search + * the dmap control pages above the actual dmaps for contiguous + * free space. the result of successful searches by these + * routines are the starting block numbers within dmaps, with + * the dmaps themselves containing the desired contiguous free + * space or starting a contiguous free space of desired size + * that is made up of the blocks of one or more dmaps. these + * calls should not fail due to insufficent resources. + * + * this routine is called in some cases where it is not known + * whether it will fail due to insufficient resources. more + * specifically, this occurs when allocating from an allocation + * group whose size is equal to the number of blocks per dmap. + * in this case, the dmap control pages are not examined prior + * to calling this routine (to save pathlength) and the call + * might fail. + * + * for a request size that fits within a dmap, this routine relies + * upon the dmap's dmtree to find the requested contiguous free + * space. for request sizes that are larger than a dmap, the + * requested free space will start at the first block of the + * first dmap (i.e. blkno). + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * nblocks - actual number of contiguous free blocks to allocate. + * l2nb - log2 number of contiguous free blocks to allocate. + * blkno - starting block number of the dmap to start the allocation + * from. + * results - on successful return, set to the starting block number + * of the newly allocated range. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + * + * serialization: IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static int +dbAllocCtl(bmap_t * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results) +{ + int rc, nb; + s64 b, lblkno, n; + metapage_t *mp; + dmap_t *dp; + + /* check if the allocation request is confined to a single dmap. + */ + if (l2nb <= L2BPERDMAP) { + /* get the buffer for the dmap. + */ + lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage); + mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) + return (EIO); + dp = (dmap_t *) mp->data; + + /* try to allocate the blocks. + */ + rc = dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results); + if (rc == 0) + mark_metapage_dirty(mp); + + release_metapage(mp); + + return (rc); + } + + /* allocation request involving multiple dmaps. it must start on + * a dmap boundary. + */ + assert((blkno & (BPERDMAP - 1)) == 0); + + /* allocate the blocks dmap by dmap. + */ + for (n = nblocks, b = blkno; n > 0; n -= nb, b += nb) { + /* get the buffer for the dmap. + */ + lblkno = BLKTODMAP(b, bmp->db_l2nbperpage); + mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) { + rc = EIO; + goto backout; + } + dp = (dmap_t *) mp->data; + + /* the dmap better be all free. + */ + assert(dp->tree.stree[ROOT] == L2BPERDMAP); + + /* determine how many blocks to allocate from this dmap. + */ + nb = min(n, (s64)BPERDMAP); + + /* allocate the blocks from the dmap. + */ + if ((rc = dbAllocDmap(bmp, dp, b, nb))) { + release_metapage(mp); + goto backout; + } + + /* write the buffer. + */ + write_metapage(mp); + } + + /* set the results (starting block number) and return. + */ + *results = blkno; + return (0); + + /* something failed in handling an allocation request involving + * multiple dmaps. we'll try to clean up by backing out any + * allocation that has already happened for this request. if + * we fail in backing out the allocation, we'll mark the file + * system to indicate that blocks have been leaked. + */ + backout: + + /* try to backout the allocations dmap by dmap. + */ + for (n = nblocks - n, b = blkno; n > 0; + n -= BPERDMAP, b += BPERDMAP) { + /* get the buffer for this dmap. + */ + lblkno = BLKTODMAP(b, bmp->db_l2nbperpage); + mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) { + /* could not back out. mark the file system + * to indicate that we have leaked blocks. + */ + fsDirty(); /* !!! */ + jERROR(1, + ("dbAllocCtl: I/O Error: Block Leakage.\n")); + continue; + } + dp = (dmap_t *) mp->data; + + /* free the blocks is this dmap. + */ + if (dbFreeDmap(bmp, dp, b, BPERDMAP)) { + /* could not back out. mark the file system + * to indicate that we have leaked blocks. + */ + release_metapage(mp); + fsDirty(); /* !!! */ + jERROR(1, ("dbAllocCtl: Block Leakage.\n")); + continue; + } + + /* write the buffer. + */ + write_metapage(mp); + } + + return (rc); +} + + +/* + * NAME: dbAllocDmapLev() + * + * FUNCTION: attempt to allocate a specified number of contiguous blocks + * from a specified dmap. + * + * this routine checks if the contiguous blocks are available. + * if so, nblocks of blocks are allocated; otherwise, ENOSPC is + * returned. + * + * PARAMETERS: + * mp - pointer to bmap descriptor + * dp - pointer to dmap to attempt to allocate blocks from. + * l2nb - log2 number of contiguous block desired. + * nblocks - actual number of contiguous block desired. + * results - on successful return, set to the starting block number + * of the newly allocated range. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient disk resources + * EIO - i/o error + * + * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or + * IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit; + */ +static int +dbAllocDmapLev(bmap_t * bmp, + dmap_t * dp, int nblocks, int l2nb, s64 * results) +{ + s64 blkno; + int leafidx, rc; + + /* can't be more than a dmaps worth of blocks */ + assert(l2nb <= L2BPERDMAP); + + /* search the tree within the dmap page for sufficient + * free space. if sufficient free space is found, dbFindLeaf() + * returns the index of the leaf at which free space was found. + */ + if (dbFindLeaf((dmtree_t *) & dp->tree, l2nb, &leafidx)) + return (ENOSPC); + + /* determine the block number within the file system corresponding + * to the leaf at which free space was found. + */ + blkno = le64_to_cpu(dp->start) + (leafidx << L2DBWORD); + + /* if not all bits of the dmap word are free, get the starting + * bit number within the dmap word of the required string of free + * bits and adjust the block number with this value. + */ + if (dp->tree.stree[leafidx + LEAFIND] < BUDMIN) + blkno += dbFindBits(le32_to_cpu(dp->wmap[leafidx]), l2nb); + + /* allocate the blocks */ + if ((rc = dbAllocDmap(bmp, dp, blkno, nblocks)) == 0) + *results = blkno; + + return (rc); +} + + +/* + * NAME: dbAllocDmap() + * + * FUNCTION: adjust the disk allocation map to reflect the allocation + * of a specified block range within a dmap. + * + * this routine allocates the specified blocks from the dmap + * through a call to dbAllocBits(). if the allocation of the + * block range causes the maximum string of free blocks within + * the dmap to change (i.e. the value of the root of the dmap's + * dmtree), this routine will cause this change to be reflected + * up through the appropriate levels of the dmap control pages + * by a call to dbAdjCtl() for the L0 dmap control page that + * covers this dmap. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * dp - pointer to dmap to allocate the block range from. + * blkno - starting block number of the block to be allocated. + * nblocks - number of blocks to be allocated. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error + * + * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static int dbAllocDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks) +{ + s8 oldroot; + int rc; + + /* save the current value of the root (i.e. maximum free string) + * of the dmap tree. + */ + oldroot = dp->tree.stree[ROOT]; + + /* allocate the specified (blocks) bits */ + dbAllocBits(bmp, dp, blkno, nblocks); + + /* if the root has not changed, done. */ + if (dp->tree.stree[ROOT] == oldroot) + return (0); + + /* root changed. bubble the change up to the dmap control pages. + * if the adjustment of the upper level control pages fails, + * backout the bit allocation (thus making everything consistent). + */ + if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 1, 0))) + dbFreeBits(bmp, dp, blkno, nblocks); + + return (rc); +} + + +/* + * NAME: dbFreeDmap() + * + * FUNCTION: adjust the disk allocation map to reflect the allocation + * of a specified block range within a dmap. + * + * this routine frees the specified blocks from the dmap through + * a call to dbFreeBits(). if the deallocation of the block range + * causes the maximum string of free blocks within the dmap to + * change (i.e. the value of the root of the dmap's dmtree), this + * routine will cause this change to be reflected up through the + * appropriate levels of the dmap control pages by a call to + * dbAdjCtl() for the L0 dmap control page that covers this dmap. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * dp - pointer to dmap to free the block range from. + * blkno - starting block number of the block to be freed. + * nblocks - number of blocks to be freed. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error + * + * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static int dbFreeDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks) +{ + s8 oldroot; + int rc, word; + + /* save the current value of the root (i.e. maximum free string) + * of the dmap tree. + */ + oldroot = dp->tree.stree[ROOT]; + + /* free the specified (blocks) bits */ + dbFreeBits(bmp, dp, blkno, nblocks); + + /* if the root has not changed, done. */ + if (dp->tree.stree[ROOT] == oldroot) + return (0); + + /* root changed. bubble the change up to the dmap control pages. + * if the adjustment of the upper level control pages fails, + * backout the deallocation. + */ + if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 0, 0))) { + word = (blkno & (BPERDMAP - 1)) >> L2DBWORD; + + /* as part of backing out the deallocation, we will have + * to back split the dmap tree if the deallocation caused + * the freed blocks to become part of a larger binary buddy + * system. + */ + if (dp->tree.stree[word] == NOFREE) + dbBackSplit((dmtree_t *) & dp->tree, word); + + dbAllocBits(bmp, dp, blkno, nblocks); + } + + return (rc); +} + + +/* + * NAME: dbAllocBits() + * + * FUNCTION: allocate a specified block range from a dmap. + * + * this routine updates the dmap to reflect the working + * state allocation of the specified block range. it directly + * updates the bits of the working map and causes the adjustment + * of the binary buddy system described by the dmap's dmtree + * leaves to reflect the bits allocated. it also causes the + * dmap's dmtree, as a whole, to reflect the allocated range. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * dp - pointer to dmap to allocate bits from. + * blkno - starting block number of the bits to be allocated. + * nblocks - number of bits to be allocated. + * + * RETURN VALUES: none + * + * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static void dbAllocBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks) +{ + int dbitno, word, rembits, nb, nwords, wbitno, nw, agno; + dmtree_t *tp = (dmtree_t *) & dp->tree; + int size; + s8 *leaf; + + /* pick up a pointer to the leaves of the dmap tree */ + leaf = dp->tree.stree + LEAFIND; + + /* determine the bit number and word within the dmap of the + * starting block. + */ + dbitno = blkno & (BPERDMAP - 1); + word = dbitno >> L2DBWORD; + + /* block range better be within the dmap */ + assert(dbitno + nblocks <= BPERDMAP); + + /* allocate the bits of the dmap's words corresponding to the block + * range. not all bits of the first and last words may be contained + * within the block range. if this is the case, we'll work against + * those words (i.e. partial first and/or last) on an individual basis + * (a single pass), allocating the bits of interest by hand and + * updating the leaf corresponding to the dmap word. a single pass + * will be used for all dmap words fully contained within the + * specified range. within this pass, the bits of all fully contained + * dmap words will be marked as free in a single shot and the leaves + * will be updated. a single leaf may describe the free space of + * multiple dmap words, so we may update only a subset of the actual + * leaves corresponding to the dmap words of the block range. + */ + for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) { + /* determine the bit number within the word and + * the number of bits within the word. + */ + wbitno = dbitno & (DBWORD - 1); + nb = min(rembits, DBWORD - wbitno); + + /* check if only part of a word is to be allocated. + */ + if (nb < DBWORD) { + /* allocate (set to 1) the appropriate bits within + * this dmap word. + */ + dp->wmap[word] |= cpu_to_le32(ONES << (DBWORD - nb) + >> wbitno); + + /* update the leaf for this dmap word. in addition + * to setting the leaf value to the binary buddy max + * of the updated dmap word, dbSplit() will split + * the binary system of the leaves if need be. + */ + dbSplit(tp, word, BUDMIN, + dbMaxBud((u8 *) & dp->wmap[word])); + + word += 1; + } else { + /* one or more dmap words are fully contained + * within the block range. determine how many + * words and allocate (set to 1) the bits of these + * words. + */ + nwords = rembits >> L2DBWORD; + memset(&dp->wmap[word], (int) ONES, nwords * 4); + + /* determine how many bits. + */ + nb = nwords << L2DBWORD; + + /* now update the appropriate leaves to reflect + * the allocated words. + */ + for (; nwords > 0; nwords -= nw) { + assert(leaf[word] >= BUDMIN); + + /* determine what the leaf value should be + * updated to as the minimum of the l2 number + * of bits being allocated and the l2 number + * of bits currently described by this leaf. + */ + size = min((int)leaf[word], NLSTOL2BSZ(nwords)); + + /* update the leaf to reflect the allocation. + * in addition to setting the leaf value to + * NOFREE, dbSplit() will split the binary + * system of the leaves to reflect the current + * allocation (size). + */ + dbSplit(tp, word, size, NOFREE); + + /* get the number of dmap words handled */ + nw = BUDSIZE(size, BUDMIN); + word += nw; + } + } + } + + /* update the free count for this dmap */ + dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks); + + BMAP_LOCK(bmp); + + /* if this allocation group is completely free, + * update the maximum allocation group number if this allocation + * group is the new max. + */ + agno = blkno >> bmp->db_agl2size; + if (agno > bmp->db_maxag) + bmp->db_maxag = agno; + + /* update the free count for the allocation group and map */ + bmp->db_agfree[agno] -= nblocks; + bmp->db_nfree -= nblocks; + + BMAP_UNLOCK(bmp); +} + + +/* + * NAME: dbFreeBits() + * + * FUNCTION: free a specified block range from a dmap. + * + * this routine updates the dmap to reflect the working + * state allocation of the specified block range. it directly + * updates the bits of the working map and causes the adjustment + * of the binary buddy system described by the dmap's dmtree + * leaves to reflect the bits freed. it also causes the dmap's + * dmtree, as a whole, to reflect the deallocated range. + * + * PARAMETERS: + * bmp - pointer to bmap descriptor + * dp - pointer to dmap to free bits from. + * blkno - starting block number of the bits to be freed. + * nblocks - number of bits to be freed. + * + * RETURN VALUES: none + * + * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static void dbFreeBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks) +{ + int dbitno, word, rembits, nb, nwords, wbitno, nw, agno; + dmtree_t *tp = (dmtree_t *) & dp->tree; + int size; + + /* determine the bit number and word within the dmap of the + * starting block. + */ + dbitno = blkno & (BPERDMAP - 1); + word = dbitno >> L2DBWORD; + + /* block range better be within the dmap. + */ + assert(dbitno + nblocks <= BPERDMAP); + + /* free the bits of the dmaps words corresponding to the block range. + * not all bits of the first and last words may be contained within + * the block range. if this is the case, we'll work against those + * words (i.e. partial first and/or last) on an individual basis + * (a single pass), freeing the bits of interest by hand and updating + * the leaf corresponding to the dmap word. a single pass will be used + * for all dmap words fully contained within the specified range. + * within this pass, the bits of all fully contained dmap words will + * be marked as free in a single shot and the leaves will be updated. a + * single leaf may describe the free space of multiple dmap words, + * so we may update only a subset of the actual leaves corresponding + * to the dmap words of the block range. + * + * dbJoin() is used to update leaf values and will join the binary + * buddy system of the leaves if the new leaf values indicate this + * should be done. + */ + for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) { + /* determine the bit number within the word and + * the number of bits within the word. + */ + wbitno = dbitno & (DBWORD - 1); + nb = min(rembits, DBWORD - wbitno); + + /* check if only part of a word is to be freed. + */ + if (nb < DBWORD) { + /* free (zero) the appropriate bits within this + * dmap word. + */ + dp->wmap[word] &= + cpu_to_le32(~(ONES << (DBWORD - nb) + >> wbitno)); + + /* update the leaf for this dmap word. + */ + dbJoin(tp, word, + dbMaxBud((u8 *) & dp->wmap[word])); + + word += 1; + } else { + /* one or more dmap words are fully contained + * within the block range. determine how many + * words and free (zero) the bits of these words. + */ + nwords = rembits >> L2DBWORD; + memset(&dp->wmap[word], 0, nwords * 4); + + /* determine how many bits. + */ + nb = nwords << L2DBWORD; + + /* now update the appropriate leaves to reflect + * the freed words. + */ + for (; nwords > 0; nwords -= nw) { + /* determine what the leaf value should be + * updated to as the minimum of the l2 number + * of bits being freed and the l2 (max) number + * of bits that can be described by this leaf. + */ + size = + min(LITOL2BSZ + (word, L2LPERDMAP, BUDMIN), + NLSTOL2BSZ(nwords)); + + /* update the leaf. + */ + dbJoin(tp, word, size); + + /* get the number of dmap words handled. + */ + nw = BUDSIZE(size, BUDMIN); + word += nw; + } + } + } + + /* update the free count for this dmap. + */ + dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) + nblocks); + + BMAP_LOCK(bmp); + + /* update the free count for the allocation group and + * map. + */ + agno = blkno >> bmp->db_agl2size; + bmp->db_nfree += nblocks; + bmp->db_agfree[agno] += nblocks; + + /* check if this allocation group is not completely free and + * if it is currently the maximum (rightmost) allocation group. + * if so, establish the new maximum allocation group number by + * searching left for the first allocation group with allocation. + */ + if ((bmp->db_agfree[agno] == bmp->db_agsize + && agno == bmp->db_maxag) || (agno == bmp->db_numag - 1 + && bmp->db_agfree[agno] == + (bmp-> db_mapsize & + (BPERDMAP - 1)))) { + while (bmp->db_maxag > 0) { + bmp->db_maxag -= 1; + if (bmp->db_agfree[bmp->db_maxag] != + bmp->db_agsize) + break; + } + + /* re-establish the allocation group preference if the + * current preference is right of the maximum allocation + * group. + */ + if (bmp->db_agpref > bmp->db_maxag) + bmp->db_agpref = bmp->db_maxag; + } + + BMAP_UNLOCK(bmp); +} + + +/* + * NAME: dbAdjCtl() + * + * FUNCTION: adjust a dmap control page at a specified level to reflect + * the change in a lower level dmap or dmap control page's + * maximum string of free blocks (i.e. a change in the root + * of the lower level object's dmtree) due to the allocation + * or deallocation of a range of blocks with a single dmap. + * + * on entry, this routine is provided with the new value of + * the lower level dmap or dmap control page root and the + * starting block number of the block range whose allocation + * or deallocation resulted in the root change. this range + * is respresented by a single leaf of the current dmapctl + * and the leaf will be updated with this value, possibly + * causing a binary buddy system within the leaves to be + * split or joined. the update may also cause the dmapctl's + * dmtree to be updated. + * + * if the adjustment of the dmap control page, itself, causes its + * root to change, this change will be bubbled up to the next dmap + * control level by a recursive call to this routine, specifying + * the new root value and the next dmap control page level to + * be adjusted. + * PARAMETERS: + * bmp - pointer to bmap descriptor + * blkno - the first block of a block range within a dmap. it is + * the allocation or deallocation of this block range that + * requires the dmap control page to be adjusted. + * newval - the new value of the lower level dmap or dmap control + * page root. + * alloc - TRUE if adjustment is due to an allocation. + * level - current level of dmap control page (i.e. L0, L1, L2) to + * be adjusted. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error + * + * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static int +dbAdjCtl(bmap_t * bmp, s64 blkno, int newval, int alloc, int level) +{ + metapage_t *mp; + s8 oldroot; + int oldval; + s64 lblkno; + dmapctl_t *dcp; + int rc, leafno, ti; + + /* get the buffer for the dmap control page for the specified + * block number and control page level. + */ + lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, level); + mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) + return (EIO); + dcp = (dmapctl_t *) mp->data; + + /* determine the leaf number corresponding to the block and + * the index within the dmap control tree. + */ + leafno = BLKTOCTLLEAF(blkno, dcp->budmin); + ti = leafno + le32_to_cpu(dcp->leafidx); + + /* save the current leaf value and the current root level (i.e. + * maximum l2 free string described by this dmapctl). + */ + oldval = dcp->stree[ti]; + oldroot = dcp->stree[ROOT]; + + /* check if this is a control page update for an allocation. + * if so, update the leaf to reflect the new leaf value using + * dbSplit(); otherwise (deallocation), use dbJoin() to udpate + * the leaf with the new value. in addition to updating the + * leaf, dbSplit() will also split the binary buddy system of + * the leaves, if required, and bubble new values within the + * dmapctl tree, if required. similarly, dbJoin() will join + * the binary buddy system of leaves and bubble new values up + * the dmapctl tree as required by the new leaf value. + */ + if (alloc) { + /* check if we are in the middle of a binary buddy + * system. this happens when we are performing the + * first allocation out of an allocation group that + * is part (not the first part) of a larger binary + * buddy system. if we are in the middle, back split + * the system prior to calling dbSplit() which assumes + * that it is at the front of a binary buddy system. + */ + if (oldval == NOFREE) { + dbBackSplit((dmtree_t *) dcp, leafno); + oldval = dcp->stree[ti]; + } + dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval); + } else { + dbJoin((dmtree_t *) dcp, leafno, newval); + } + + /* check if the root of the current dmap control page changed due + * to the update and if the current dmap control page is not at + * the current top level (i.e. L0, L1, L2) of the map. if so (i.e. + * root changed and this is not the top level), call this routine + * again (recursion) for the next higher level of the mapping to + * reflect the change in root for the current dmap control page. + */ + if (dcp->stree[ROOT] != oldroot) { + /* are we below the top level of the map. if so, + * bubble the root up to the next higher level. + */ + if (level < bmp->db_maxlevel) { + /* bubble up the new root of this dmap control page to + * the next level. + */ + if ((rc = + dbAdjCtl(bmp, blkno, dcp->stree[ROOT], alloc, + level + 1))) { + /* something went wrong in bubbling up the new + * root value, so backout the changes to the + * current dmap control page. + */ + if (alloc) { + dbJoin((dmtree_t *) dcp, leafno, + oldval); + } else { + /* the dbJoin() above might have + * caused a larger binary buddy system + * to form and we may now be in the + * middle of it. if this is the case, + * back split the buddies. + */ + if (dcp->stree[ti] == NOFREE) + dbBackSplit((dmtree_t *) + dcp, leafno); + dbSplit((dmtree_t *) dcp, leafno, + dcp->budmin, oldval); + } + + /* release the buffer and return the error. + */ + release_metapage(mp); + return (rc); + } + } else { + /* we're at the top level of the map. update + * the bmap control page to reflect the size + * of the maximum free buddy system. + */ + assert(level == bmp->db_maxlevel); + assert(bmp->db_maxfreebud == oldroot); + bmp->db_maxfreebud = dcp->stree[ROOT]; + } + } + + /* write the buffer. + */ + write_metapage(mp); + + return (0); +} + + +/* + * NAME: dbSplit() + * + * FUNCTION: update the leaf of a dmtree with a new value, splitting + * the leaf from the binary buddy system of the dmtree's + * leaves, as required. + * + * PARAMETERS: + * tp - pointer to the tree containing the leaf. + * leafno - the number of the leaf to be updated. + * splitsz - the size the binary buddy system starting at the leaf + * must be split to, specified as the log2 number of blocks. + * newval - the new value for the leaf. + * + * RETURN VALUES: none + * + * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval) +{ + int budsz; + int cursz; + s8 *leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx); + + /* check if the leaf needs to be split. + */ + if (leaf[leafno] > tp->dmt_budmin) { + /* the split occurs by cutting the buddy system in half + * at the specified leaf until we reach the specified + * size. pick up the starting split size (current size + * - 1 in l2) and the corresponding buddy size. + */ + cursz = leaf[leafno] - 1; + budsz = BUDSIZE(cursz, tp->dmt_budmin); + + /* split until we reach the specified size. + */ + while (cursz >= splitsz) { + /* update the buddy's leaf with its new value. + */ + dbAdjTree(tp, leafno ^ budsz, cursz); + + /* on to the next size and buddy. + */ + cursz -= 1; + budsz >>= 1; + } + } + + /* adjust the dmap tree to reflect the specified leaf's new + * value. + */ + dbAdjTree(tp, leafno, newval); +} + + +/* + * NAME: dbBackSplit() + * + * FUNCTION: back split the binary buddy system of dmtree leaves + * that hold a specified leaf until the specified leaf + * starts its own binary buddy system. + * + * the allocators typically perform allocations at the start + * of binary buddy systems and dbSplit() is used to accomplish + * any required splits. in some cases, however, allocation + * may occur in the middle of a binary system and requires a + * back split, with the split proceeding out from the middle of + * the system (less efficient) rather than the start of the + * system (more efficient). the cases in which a back split + * is required are rare and are limited to the first allocation + * within an allocation group which is a part (not first part) + * of a larger binary buddy system and a few exception cases + * in which a previous join operation must be backed out. + * + * PARAMETERS: + * tp - pointer to the tree containing the leaf. + * leafno - the number of the leaf to be updated. + * + * RETURN VALUES: none + * + * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; + */ +static void dbBackSplit(dmtree_t * tp, int leafno) +{ + int budsz, bud, w, bsz, size; + int cursz; + s8 *leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx); + + /* leaf should be part (not first part) of a binary + * buddy system. + */ + assert(leaf[leafno] == NOFREE); + + /* the back split is accomplished by iteratively finding the leaf + * that starts the buddy system that contains the specified leaf and + * splitting that system in two. this iteration continues until + * the specified leaf becomes the start of a buddy system. + * + * determine maximum possible l2 size for the specified leaf. + */ + size = + LITOL2BSZ(leafno, le32_to_cpu(tp->dmt_l2nleafs), + tp->dmt_budmin); + + /* determine the number of leaves covered by this size. this + * is the buddy size that we will start with as we search for + * the buddy system that contains the specified leaf. + */ + budsz = BUDSIZE(size, tp->dmt_budmin); + + /* back split. + */ + while (leaf[leafno] == NOFREE) { + /* find the leftmost buddy leaf. + */ + for (w = leafno, bsz = budsz;; bsz <<= 1, + w = (w < bud) ? w : bud) { + assert(bsz < le32_to_cpu(tp->dmt_nleafs)); + + /* determine the buddy. + */ + bud = w ^ bsz; + + /* check if this buddy is the start of the system. + */ + if (leaf[bud] != NOFREE) { + /* split the leaf at the start of the + * system in two. + */ + cursz = leaf[bud] - 1; + dbSplit(tp, bud, cursz, cursz); + break; + } + } + } + + assert(leaf[leafno] == size); +} + + +/* + * NAME: dbJoin() + * + * FUNCTION: update the leaf of a dmtree with a new value, joining + * the leaf with other leaves of the dmtree into a multi-leaf + * binary buddy system, as required. + * + * PARAMETERS: + * tp - pointer to the tree containing the leaf. + * leafno - the number of the leaf to be updated. + * newval - the new value for the leaf. + * + * RETURN VALUES: none + */ +static void dbJoin(dmtree_t * tp, int leafno, int newval) +{ + int budsz, buddy; + s8 *leaf; + + /* can the new leaf value require a join with other leaves ? + */ + if (newval >= tp->dmt_budmin) { + /* pickup a pointer to the leaves of the tree. + */ + leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx); + + /* try to join the specified leaf into a large binary + * buddy system. the join proceeds by attempting to join + * the specified leafno with its buddy (leaf) at new value. + * if the join occurs, we attempt to join the left leaf + * of the joined buddies with its buddy at new value + 1. + * we continue to join until we find a buddy that cannot be + * joined (does not have a value equal to the size of the + * last join) or until all leaves have been joined into a + * single system. + * + * get the buddy size (number of words covered) of + * the new value. + */ + budsz = BUDSIZE(newval, tp->dmt_budmin); + + /* try to join. + */ + while (budsz < le32_to_cpu(tp->dmt_nleafs)) { + /* get the buddy leaf. + */ + buddy = leafno ^ budsz; + + /* if the leaf's new value is greater than its + * buddy's value, we join no more. + */ + if (newval > leaf[buddy]) + break; + + assert(newval == leaf[buddy]); + + /* check which (leafno or buddy) is the left buddy. + * the left buddy gets to claim the blocks resulting + * from the join while the right gets to claim none. + * the left buddy is also eligable to participate in + * a join at the next higher level while the right + * is not. + * + */ + if (leafno < buddy) { + /* leafno is the left buddy. + */ + dbAdjTree(tp, buddy, NOFREE); + } else { + /* buddy is the left buddy and becomes + * leafno. + */ + dbAdjTree(tp, leafno, NOFREE); + leafno = buddy; + } + + /* on to try the next join. + */ + newval += 1; + budsz <<= 1; + } + } + + /* update the leaf value. + */ + dbAdjTree(tp, leafno, newval); +} + + +/* + * NAME: dbAdjTree() + * + * FUNCTION: update a leaf of a dmtree with a new value, adjusting + * the dmtree, as required, to reflect the new leaf value. + * the combination of any buddies must already be done before + * this is called. + * + * PARAMETERS: + * tp - pointer to the tree to be adjusted. + * leafno - the number of the leaf to be updated. + * newval - the new value for the leaf. + * + * RETURN VALUES: none + */ +static void dbAdjTree(dmtree_t * tp, int leafno, int newval) +{ + int lp, pp, k; + int max; + + /* pick up the index of the leaf for this leafno. + */ + lp = leafno + le32_to_cpu(tp->dmt_leafidx); + + /* is the current value the same as the old value ? if so, + * there is nothing to do. + */ + if (tp->dmt_stree[lp] == newval) + return; + + /* set the new value. + */ + tp->dmt_stree[lp] = newval; + + /* bubble the new value up the tree as required. + */ + for (k = 0; k < le32_to_cpu(tp->dmt_height); k++) { + /* get the index of the first leaf of the 4 leaf + * group containing the specified leaf (leafno). + */ + lp = ((lp - 1) & ~0x03) + 1; + + /* get the index of the parent of this 4 leaf group. + */ + pp = (lp - 1) >> 2; + + /* determine the maximum of the 4 leaves. + */ + max = TREEMAX(&tp->dmt_stree[lp]); + + /* if the maximum of the 4 is the same as the + * parent's value, we're done. + */ + if (tp->dmt_stree[pp] == max) + break; + + /* parent gets new value. + */ + tp->dmt_stree[pp] = max; + + /* parent becomes leaf for next go-round. + */ + lp = pp; + } +} + + +/* + * NAME: dbFindLeaf() + * + * FUNCTION: search a dmtree_t for sufficient free blocks, returning + * the index of a leaf describing the free blocks if + * sufficient free blocks are found. + * + * the search starts at the top of the dmtree_t tree and + * proceeds down the tree to the leftmost leaf with sufficient + * free space. + * + * PARAMETERS: + * tp - pointer to the tree to be searched. + * l2nb - log2 number of free blocks to search for. + * leafidx - return pointer to be set to the index of the leaf + * describing at least l2nb free blocks if sufficient + * free blocks are found. + * + * RETURN VALUES: + * 0 - success + * ENOSPC - insufficient free blocks. + */ +static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx) +{ + int ti, n = 0, k, x = 0; + + /* first check the root of the tree to see if there is + * sufficient free space. + */ + if (l2nb > tp->dmt_stree[ROOT]) + return (ENOSPC); + + /* sufficient free space available. now search down the tree + * starting at the next level for the leftmost leaf that + * describes sufficient free space. + */ + for (k = le32_to_cpu(tp->dmt_height), ti = 1; + k > 0; k--, ti = ((ti + n) << 2) + 1) { + /* search the four nodes at this level, starting from + * the left. + */ + for (x = ti, n = 0; n < 4; n++) { + /* sufficient free space found. move to the next + * level (or quit if this is the last level). + */ + if (l2nb <= tp->dmt_stree[x + n]) + break; + } + + /* better have found something since the higher + * levels of the tree said it was here. + */ + assert(n < 4); + } + + /* set the return to the leftmost leaf describing sufficient + * free space. + */ + *leafidx = x + n - le32_to_cpu(tp->dmt_leafidx); + + return (0); +} + + +/* + * NAME: dbFindBits() + * + * FUNCTION: find a specified number of binary buddy free bits within a + * dmap bitmap word value. + * + * this routine searches the bitmap value for (1 << l2nb) free + * bits at (1 << l2nb) alignments within the value. + * + * PARAMETERS: + * word - dmap bitmap word value. + * l2nb - number of free bits specified as a log2 number. + * + * RETURN VALUES: + * starting bit number of free bits. + */ +static int dbFindBits(u32 word, int l2nb) +{ + int bitno, nb; + u32 mask; + + /* get the number of bits. + */ + nb = 1 << l2nb; + assert(nb <= DBWORD); + + /* complement the word so we can use a mask (i.e. 0s represent + * free bits) and compute the mask. + */ + word = ~word; + mask = ONES << (DBWORD - nb); + + /* scan the word for nb free bits at nb alignments. + */ + for (bitno = 0; mask != 0; bitno += nb, mask >>= nb) { + if ((mask & word) == mask) + break; + } + + ASSERT(bitno < 32); + + /* return the bit number. + */ + return (bitno); +} + + +/* + * NAME: dbMaxBud(u8 *cp) + * + * FUNCTION: determine the largest binary buddy string of free + * bits within 32-bits of the map. + * + * PARAMETERS: + * cp - pointer to the 32-bit value. + * + * RETURN VALUES: + * largest binary buddy of free bits within a dmap word. + */ +static int dbMaxBud(u8 * cp) +{ + signed char tmp1, tmp2; + + /* check if the wmap word is all free. if so, the + * free buddy size is BUDMIN. + */ + if (*((uint *) cp) == 0) + return (BUDMIN); + + /* check if the wmap word is half free. if so, the + * free buddy size is BUDMIN-1. + */ + if (*((u16 *) cp) == 0 || *((u16 *) cp + 1) == 0) + return (BUDMIN - 1); + + /* not all free or half free. determine the free buddy + * size thru table lookup using quarters of the wmap word. + */ + tmp1 = max(budtab[cp[2]], budtab[cp[3]]); + tmp2 = max(budtab[cp[0]], budtab[cp[1]]); + return (max(tmp1, tmp2)); +} + + +/* + * NAME: cnttz(uint word) + * + * FUNCTION: determine the number of trailing zeros within a 32-bit + * value. + * + * PARAMETERS: + * value - 32-bit value to be examined. + * + * RETURN VALUES: + * count of trailing zeros + */ +int cnttz(u32 word) +{ + int n; + + for (n = 0; n < 32; n++, word >>= 1) { + if (word & 0x01) + break; + } + + return (n); +} + + +/* + * NAME: cntlz(u32 value) + * + * FUNCTION: determine the number of leading zeros within a 32-bit + * value. + * + * PARAMETERS: + * value - 32-bit value to be examined. + * + * RETURN VALUES: + * count of leading zeros + */ +int cntlz(u32 value) +{ + int n; + + for (n = 0; n < 32; n++, value <<= 1) { + if (value & HIGHORDER) + break; + } + return (n); +} + + +/* + * NAME: blkstol2(s64 nb) + * + * FUNCTION: convert a block count to its log2 value. if the block + * count is not a l2 multiple, it is rounded up to the next + * larger l2 multiple. + * + * PARAMETERS: + * nb - number of blocks + * + * RETURN VALUES: + * log2 number of blocks + */ +int blkstol2(s64 nb) +{ + int l2nb; + s64 mask; /* meant to be signed */ + + mask = (s64) 1 << (64 - 1); + + /* count the leading bits. + */ + for (l2nb = 0; l2nb < 64; l2nb++, mask >>= 1) { + /* leading bit found. + */ + if (nb & mask) { + /* determine the l2 value. + */ + l2nb = (64 - 1) - l2nb; + + /* check if we need to round up. + */ + if (~mask & nb) + l2nb++; + + return (l2nb); + } + } + assert(0); + return 0; /* fix compiler warning */ +} + + +/* + * NAME: fsDirty() + * + * FUNCTION: xxx + * + * PARAMETERS: + * ipmnt - mount inode + * + * RETURN VALUES: + * none + */ +void fsDirty() +{ + printk("fsDirty(): bye-bye\n"); + assert(0); +} + + +/* + * NAME: dbAllocBottomUp() + * + * FUNCTION: alloc the specified block range from the working block + * allocation map. + * + * the blocks will be alloc from the working map one dmap + * at a time. + * + * PARAMETERS: + * ip - pointer to in-core inode; + * blkno - starting block number to be freed. + * nblocks - number of blocks to be freed. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error + */ +int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks) +{ + metapage_t *mp; + dmap_t *dp; + int nb, rc; + s64 lblkno, rem; + struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; + bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap; + + IREAD_LOCK(ipbmap); + + /* block to be allocated better be within the mapsize. */ + ASSERT(nblocks <= bmp->db_mapsize - blkno); + + /* + * allocate the blocks a dmap at a time. + */ + mp = NULL; + for (rem = nblocks; rem > 0; rem -= nb, blkno += nb) { + /* release previous dmap if any */ + if (mp) { + write_metapage(mp); + } + + /* get the buffer for the current dmap. */ + lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage); + mp = read_metapage(ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) { + IREAD_UNLOCK(ipbmap); + return (EIO); + } + dp = (dmap_t *) mp->data; + + /* determine the number of blocks to be allocated from + * this dmap. + */ + nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1))); + + DBFREECK(bmp->db_DBmap, bmp->db_mapsize, blkno, nb); + + /* allocate the blocks. */ + if ((rc = dbAllocDmapBU(bmp, dp, blkno, nb))) { + release_metapage(mp); + IREAD_UNLOCK(ipbmap); + return (rc); + } + + DBALLOC(bmp->db_DBmap, bmp->db_mapsize, blkno, nb); + } + + /* write the last buffer. */ + write_metapage(mp); + + IREAD_UNLOCK(ipbmap); + + return (0); +} + + +static int dbAllocDmapBU(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks) +{ + int rc; + int dbitno, word, rembits, nb, nwords, wbitno, agno; + s8 oldroot, *leaf; + dmaptree_t *tp = (dmaptree_t *) & dp->tree; + + /* save the current value of the root (i.e. maximum free string) + * of the dmap tree. + */ + oldroot = tp->stree[ROOT]; + + /* pick up a pointer to the leaves of the dmap tree */ + leaf = tp->stree + LEAFIND; + + /* determine the bit number and word within the dmap of the + * starting block. + */ + dbitno = blkno & (BPERDMAP - 1); + word = dbitno >> L2DBWORD; + + /* block range better be within the dmap */ + assert(dbitno + nblocks <= BPERDMAP); + + /* allocate the bits of the dmap's words corresponding to the block + * range. not all bits of the first and last words may be contained + * within the block range. if this is the case, we'll work against + * those words (i.e. partial first and/or last) on an individual basis + * (a single pass), allocating the bits of interest by hand and + * updating the leaf corresponding to the dmap word. a single pass + * will be used for all dmap words fully contained within the + * specified range. within this pass, the bits of all fully contained + * dmap words will be marked as free in a single shot and the leaves + * will be updated. a single leaf may describe the free space of + * multiple dmap words, so we may update only a subset of the actual + * leaves corresponding to the dmap words of the block range. + */ + for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) { + /* determine the bit number within the word and + * the number of bits within the word. + */ + wbitno = dbitno & (DBWORD - 1); + nb = min(rembits, DBWORD - wbitno); + + /* check if only part of a word is to be allocated. + */ + if (nb < DBWORD) { + /* allocate (set to 1) the appropriate bits within + * this dmap word. + */ + dp->wmap[word] |= cpu_to_le32(ONES << (DBWORD - nb) + >> wbitno); + + word++; + } else { + /* one or more dmap words are fully contained + * within the block range. determine how many + * words and allocate (set to 1) the bits of these + * words. + */ + nwords = rembits >> L2DBWORD; + memset(&dp->wmap[word], (int) ONES, nwords * 4); + + /* determine how many bits */ + nb = nwords << L2DBWORD; + word += nwords; + } + } + + /* update the free count for this dmap */ + dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks); + + /* reconstruct summary tree */ + dbInitDmapTree(dp); + + BMAP_LOCK(bmp); + + /* if this allocation group is completely free, + * update the highest active allocation group number + * if this allocation group is the new max. + */ + agno = blkno >> bmp->db_agl2size; + if (agno > bmp->db_maxag) + bmp->db_maxag = agno; + + /* update the free count for the allocation group and map */ + bmp->db_agfree[agno] -= nblocks; + bmp->db_nfree -= nblocks; + + BMAP_UNLOCK(bmp); + + /* if the root has not changed, done. */ + if (tp->stree[ROOT] == oldroot) + return (0); + + /* root changed. bubble the change up to the dmap control pages. + * if the adjustment of the upper level control pages fails, + * backout the bit allocation (thus making everything consistent). + */ + if ((rc = dbAdjCtl(bmp, blkno, tp->stree[ROOT], 1, 0))) + dbFreeBits(bmp, dp, blkno, nblocks); + + return (rc); +} + + +/* + * NAME: dbExtendFS() + * + * FUNCTION: extend bmap from blkno for nblocks; + * dbExtendFS() updates bmap ready for dbAllocBottomUp(); + * + * L2 + * | + * L1---------------------------------L1 + * | | + * L0---------L0---------L0 L0---------L0---------L0 + * | | | | | | + * d0,...,dn d0,...,dn d0,...,dn d0,...,dn d0,...,dn d0,.,dm; + * L2L1L0d0,...,dnL0d0,...,dnL0d0,...,dnL1L0d0,...,dnL0d0,...,dnL0d0,..dm + * + * <---old---><----------------------------extend-----------------------> + */ +int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) +{ + struct jfs_sb_info *sbi = JFS_SBI(ipbmap->i_sb); + int nbperpage = sbi->nbperpage; + int i, i0 = TRUE, j, j0 = TRUE, k, n; + s64 newsize; + s64 p; + metapage_t *mp, *l2mp, *l1mp, *l0mp; + dmapctl_t *l2dcp, *l1dcp, *l0dcp; + dmap_t *dp; + s8 *l0leaf, *l1leaf, *l2leaf; + bmap_t *bmp = sbi->bmap; + int agno, l2agsize, oldl2agsize; + s64 ag_rem; + + newsize = blkno + nblocks; + + jEVENT(0, ("dbExtendFS: blkno:%Ld nblocks:%Ld newsize:%Ld\n", + (long long) blkno, (long long) nblocks, + (long long) newsize)); + + /* + * initialize bmap control page. + * + * all the data in bmap control page should exclude + * the mkfs hidden dmap page. + */ + + /* update mapsize */ + bmp->db_mapsize = newsize; + bmp->db_maxlevel = BMAPSZTOLEV(bmp->db_mapsize); + + /* compute new AG size */ + l2agsize = dbGetL2AGSize(newsize); + oldl2agsize = bmp->db_agl2size; + + bmp->db_agl2size = l2agsize; + bmp->db_agsize = 1 << l2agsize; + + /* compute new number of AG */ + agno = bmp->db_numag; + bmp->db_numag = newsize >> l2agsize; + bmp->db_numag += ((u32) newsize % (u32) bmp->db_agsize) ? 1 : 0; + + /* + * reconfigure db_agfree[] + * from old AG configuration to new AG configuration; + * + * coalesce contiguous k (newAGSize/oldAGSize) AGs; + * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn; + * note: new AG size = old AG size * (2**x). + */ + if (l2agsize == oldl2agsize) + goto extend; + k = 1 << (l2agsize - oldl2agsize); + ag_rem = bmp->db_agfree[0]; /* save agfree[0] */ + for (i = 0, n = 0; i < agno; n++) { + bmp->db_agfree[n] = 0; /* init collection point */ + + /* coalesce cotiguous k AGs; */ + for (j = 0; j < k && i < agno; j++, i++) { + /* merge AGi to AGn */ + bmp->db_agfree[n] += bmp->db_agfree[i]; + } + } + bmp->db_agfree[0] += ag_rem; /* restore agfree[0] */ + + for (; n < MAXAG; n++) + bmp->db_agfree[n] = 0; + + /* + * update highest active ag number + */ + + bmp->db_maxag = bmp->db_maxag / k; + + /* + * extend bmap + * + * update bit maps and corresponding level control pages; + * global control page db_nfree, db_agfree[agno], db_maxfreebud; + */ + extend: + /* get L2 page */ + p = BMAPBLKNO + nbperpage; /* L2 page */ + l2mp = read_metapage(ipbmap, p, PSIZE, 0); + assert(l2mp); + l2dcp = (dmapctl_t *) l2mp->data; + + /* compute start L1 */ + k = blkno >> L2MAXL1SIZE; + l2leaf = l2dcp->stree + CTLLEAFIND + k; + p = BLKTOL1(blkno, sbi->l2nbperpage); /* L1 page */ + + /* + * extend each L1 in L2 + */ + for (; k < LPERCTL; k++, p += nbperpage) { + /* get L1 page */ + if (j0) { + /* read in L1 page: (blkno & (MAXL1SIZE - 1)) */ + l1mp = read_metapage(ipbmap, p, PSIZE, 0); + if (l1mp == NULL) + goto errout; + l1dcp = (dmapctl_t *) l1mp->data; + + /* compute start L0 */ + j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE; + l1leaf = l1dcp->stree + CTLLEAFIND + j; + p = BLKTOL0(blkno, sbi->l2nbperpage); + j0 = FALSE; + } else { + /* assign/init L1 page */ + l1mp = get_metapage(ipbmap, p, PSIZE, 0); + if (l1mp == NULL) + goto errout; + + l1dcp = (dmapctl_t *) l1mp->data; + + /* compute start L0 */ + j = 0; + l1leaf = l1dcp->stree + CTLLEAFIND; + p += nbperpage; /* 1st L0 of L1.k */ + } + + /* + * extend each L0 in L1 + */ + for (; j < LPERCTL; j++) { + /* get L0 page */ + if (i0) { + /* read in L0 page: (blkno & (MAXL0SIZE - 1)) */ + + l0mp = read_metapage(ipbmap, p, PSIZE, 0); + if (l0mp == NULL) + goto errout; + l0dcp = (dmapctl_t *) l0mp->data; + + /* compute start dmap */ + i = (blkno & (MAXL0SIZE - 1)) >> + L2BPERDMAP; + l0leaf = l0dcp->stree + CTLLEAFIND + i; + p = BLKTODMAP(blkno, + sbi->l2nbperpage); + i0 = FALSE; + } else { + /* assign/init L0 page */ + l0mp = get_metapage(ipbmap, p, PSIZE, 0); + if (l0mp == NULL) + goto errout; + + l0dcp = (dmapctl_t *) l0mp->data; + + /* compute start dmap */ + i = 0; + l0leaf = l0dcp->stree + CTLLEAFIND; + p += nbperpage; /* 1st dmap of L0.j */ + } + + /* + * extend each dmap in L0 + */ + for (; i < LPERCTL; i++) { + /* + * reconstruct the dmap page, and + * initialize corresponding parent L0 leaf + */ + if ((n = blkno & (BPERDMAP - 1))) { + /* read in dmap page: */ + mp = read_metapage(ipbmap, p, + PSIZE, 0); + if (mp == NULL) + goto errout; + n = min(nblocks, (s64)BPERDMAP - n); + } else { + /* assign/init dmap page */ + mp = read_metapage(ipbmap, p, + PSIZE, 0); + if (mp == NULL) + goto errout; + + n = min(nblocks, (s64)BPERDMAP); + } + + dp = (dmap_t *) mp->data; + *l0leaf = dbInitDmap(dp, blkno, n); + + bmp->db_nfree += n; + agno = le64_to_cpu(dp->start) >> l2agsize; + bmp->db_agfree[agno] += n; + + write_metapage(mp); + + l0leaf++; + p += nbperpage; + + blkno += n; + nblocks -= n; + if (nblocks == 0) + break; + } /* for each dmap in a L0 */ + + /* + * build current L0 page from its leaves, and + * initialize corresponding parent L1 leaf + */ + *l1leaf = dbInitDmapCtl(l0dcp, 0, ++i); + write_metapage(l0mp); + + if (nblocks) + l1leaf++; /* continue for next L0 */ + else { + /* more than 1 L0 ? */ + if (j > 0) + break; /* build L1 page */ + else { + /* summarize in global bmap page */ + bmp->db_maxfreebud = *l1leaf; + release_metapage(l1mp); + release_metapage(l2mp); + goto finalize; + } + } + } /* for each L0 in a L1 */ + + /* + * build current L1 page from its leaves, and + * initialize corresponding parent L2 leaf + */ + *l2leaf = dbInitDmapCtl(l1dcp, 1, ++j); + write_metapage(l1mp); + + if (nblocks) + l2leaf++; /* continue for next L1 */ + else { + /* more than 1 L1 ? */ + if (k > 0) + break; /* build L2 page */ + else { + /* summarize in global bmap page */ + bmp->db_maxfreebud = *l2leaf; + release_metapage(l2mp); + goto finalize; + } + } + } /* for each L1 in a L2 */ + + assert(0); + + /* + * finalize bmap control page + */ + finalize: + + return 0; + + errout: + return EIO; +} + + +/* + * dbFinalizeBmap() + */ +void dbFinalizeBmap(struct inode *ipbmap) +{ + bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap; + int actags, inactags, l2nl; + s64 ag_rem, actfree, inactfree, avgfree; + int i, n; + + /* + * finalize bmap control page + */ +//finalize: + /* + * compute db_agpref: preferred ag to allocate from + * (the leftmost ag with average free space in it); + */ +//agpref: + /* get the number of active ags and inacitve ags */ + actags = bmp->db_maxag + 1; + inactags = bmp->db_numag - actags; + ag_rem = bmp->db_mapsize & (bmp->db_agsize - 1); /* ??? */ + + /* determine how many blocks are in the inactive allocation + * groups. in doing this, we must account for the fact that + * the rightmost group might be a partial group (i.e. file + * system size is not a multiple of the group size). + */ + inactfree = (inactags && ag_rem) ? + ((inactags - 1) << bmp->db_agl2size) + ag_rem + : inactags << bmp->db_agl2size; + + /* determine how many free blocks are in the active + * allocation groups plus the average number of free blocks + * within the active ags. + */ + actfree = bmp->db_nfree - inactfree; + avgfree = (u32) actfree / (u32) actags; + + /* if the preferred allocation group has not average free space. + * re-establish the preferred group as the leftmost + * group with average free space. + */ + if (bmp->db_agfree[bmp->db_agpref] < avgfree) { + for (bmp->db_agpref = 0; bmp->db_agpref < actags; + bmp->db_agpref++) { + if (bmp->db_agfree[bmp->db_agpref] >= avgfree) + break; + } + assert(bmp->db_agpref < bmp->db_numag); + } + + /* + * compute db_aglevel, db_agheigth, db_width, db_agstart: + * an ag is covered in aglevel dmapctl summary tree, + * at agheight level height (from leaf) with agwidth number of nodes + * each, which starts at agstart index node of the smmary tree node + * array; + */ + bmp->db_aglevel = BMAPSZTOLEV(bmp->db_agsize); + l2nl = + bmp->db_agl2size - (L2BPERDMAP + bmp->db_aglevel * L2LPERCTL); + bmp->db_agheigth = l2nl >> 1; + bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheigth << 1)); + for (i = 5 - bmp->db_agheigth, bmp->db_agstart = 0, n = 1; i > 0; + i--) { + bmp->db_agstart += n; + n <<= 2; + } + +/* +printk("bmap: agpref:%d aglevel:%d agheigth:%d agwidth:%d\n", + bmp->db_agpref, bmp->db_aglevel, bmp->db_agheigth, bmp->db_agwidth); +*/ +} + + +/* + * NAME: dbInitDmap()/ujfs_idmap_page() + * + * FUNCTION: initialize working/persistent bitmap of the dmap page + * for the specified number of blocks: + * + * at entry, the bitmaps had been initialized as free (ZEROS); + * The number of blocks will only account for the actually + * existing blocks. Blocks which don't actually exist in + * the aggregate will be marked as allocated (ONES); + * + * PARAMETERS: + * dp - pointer to page of map + * nblocks - number of blocks this page + * + * RETURNS: NONE + */ +static int dbInitDmap(dmap_t * dp, s64 Blkno, int nblocks) +{ + int blkno, w, b, r, nw, nb, i; +/* +printk("sbh_dmap: in dbInitDmap blkno:%Ld nblocks:%ld\n", Blkno, nblocks); +*/ + + /* starting block number within the dmap */ + blkno = Blkno & (BPERDMAP - 1); + + if (blkno == 0) { + dp->nblocks = dp->nfree = cpu_to_le32(nblocks); + dp->start = cpu_to_le64(Blkno); + + if (nblocks == BPERDMAP) { + memset(&dp->wmap[0], 0, LPERDMAP * 4); + memset(&dp->pmap[0], 0, LPERDMAP * 4); + goto initTree; + } + } else { + dp->nblocks = + cpu_to_le32(le32_to_cpu(dp->nblocks) + nblocks); + dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) + nblocks); + } + + /* word number containing start block number */ + w = blkno >> L2DBWORD; + + /* + * free the bits corresponding to the block range (ZEROS): + * note: not all bits of the first and last words may be contained + * within the block range. + */ + for (r = nblocks; r > 0; r -= nb, blkno += nb) { + /* number of bits preceding range to be freed in the word */ + b = blkno & (DBWORD - 1); + /* number of bits to free in the word */ + nb = min(r, DBWORD - b); + + /* is partial word to be freed ? */ + if (nb < DBWORD) { + /* free (set to 0) from the bitmap word */ + dp->wmap[w] &= cpu_to_le32(~(ONES << (DBWORD - nb) + >> b)); + dp->pmap[w] &= cpu_to_le32(~(ONES << (DBWORD - nb) + >> b)); + + /* skip the word freed */ + w++; + } else { + /* free (set to 0) contiguous bitmap words */ + nw = r >> L2DBWORD; + memset(&dp->wmap[w], 0, nw * 4); + memset(&dp->pmap[w], 0, nw * 4); + + /* skip the words freed */ + nb = nw << L2DBWORD; + w += nw; + } + } + + /* + * mark bits following the range to be freed (non-existing + * blocks) as allocated (ONES) + */ +/* +printk("sbh_dmap: in dbInitDmap, preparing to mark unbacked, blkno:%ld nblocks:%ld\n", + blkno, nblocks); +*/ + + if (blkno == BPERDMAP) + goto initTree; + + /* the first word beyond the end of existing blocks */ + w = blkno >> L2DBWORD; + + /* does nblocks fall on a 32-bit boundary ? */ + b = blkno & (DBWORD - 1); +/* +printk("sbh_dmap: in dbInitDmap, b:%ld w:%ld mask: %lx\n", b, w, (ONES>>b)); +*/ + if (b) { + /* mark a partial word allocated */ + dp->wmap[w] = dp->pmap[w] = cpu_to_le32(ONES >> b); + w++; + } + + /* set the rest of the words in the page to allocated (ONES) */ + for (i = w; i < LPERDMAP; i++) + dp->pmap[i] = dp->wmap[i] = ONES; + + /* + * init tree + */ + initTree: + return (dbInitDmapTree(dp)); +} + + +/* + * NAME: dbInitDmapTree()/ujfs_complete_dmap() + * + * FUNCTION: initialize summary tree of the specified dmap: + * + * at entry, bitmap of the dmap has been initialized; + * + * PARAMETERS: + * dp - dmap to complete + * blkno - starting block number for this dmap + * treemax - will be filled in with max free for this dmap + * + * RETURNS: max free string at the root of the tree + */ +static int dbInitDmapTree(dmap_t * dp) +{ + dmaptree_t *tp; + s8 *cp; + int i; + + /* init fixed info of tree */ + tp = &dp->tree; + tp->nleafs = cpu_to_le32(LPERDMAP); + tp->l2nleafs = cpu_to_le32(L2LPERDMAP); + tp->leafidx = cpu_to_le32(LEAFIND); + tp->height = cpu_to_le32(4); + tp->budmin = BUDMIN; + + /* init each leaf from corresponding wmap word: + * note: leaf is set to NOFREE(-1) if all blocks of corresponding + * bitmap word are allocated. + */ + cp = tp->stree + le32_to_cpu(tp->leafidx); + for (i = 0; i < LPERDMAP; i++) + *cp++ = dbMaxBud((u8 *) & dp->wmap[i]); + + /* build the dmap's binary buddy summary tree */ + return (dbInitTree(tp)); +} + + +/* + * NAME: dbInitTree()/ujfs_adjtree() + * + * FUNCTION: initialize binary buddy summary tree of a dmap or dmapctl. + * + * at entry, the leaves of the tree has been initialized + * from corresponding bitmap word or root of summary tree + * of the child control page; + * configure binary buddy system at the leaf level, then + * bubble up the values of the leaf nodes up the tree. + * + * PARAMETERS: + * cp - Pointer to the root of the tree + * l2leaves- Number of leaf nodes as a power of 2 + * l2min - Number of blocks that can be covered by a leaf + * as a power of 2 + * + * RETURNS: max free string at the root of the tree + */ +static int dbInitTree(dmaptree_t * dtp) +{ + int l2max, l2free, bsize, nextb, i; + int child, parent, nparent; + s8 *tp, *cp, *cp1; + + tp = dtp->stree; + + /* Determine the maximum free string possible for the leaves */ + l2max = le32_to_cpu(dtp->l2nleafs) + dtp->budmin; + + /* + * configure the leaf levevl into binary buddy system + * + * Try to combine buddies starting with a buddy size of 1 + * (i.e. two leaves). At a buddy size of 1 two buddy leaves + * can be combined if both buddies have a maximum free of l2min; + * the combination will result in the left-most buddy leaf having + * a maximum free of l2min+1. + * After processing all buddies for a given size, process buddies + * at the next higher buddy size (i.e. current size * 2) and + * the next maximum free (current free + 1). + * This continues until the maximum possible buddy combination + * yields maximum free. + */ + for (l2free = dtp->budmin, bsize = 1; l2free < l2max; + l2free++, bsize = nextb) { + /* get next buddy size == current buddy pair size */ + nextb = bsize << 1; + + /* scan each adjacent buddy pair at current buddy size */ + for (i = 0, cp = tp + le32_to_cpu(dtp->leafidx); + i < le32_to_cpu(dtp->nleafs); + i += nextb, cp += nextb) { + /* coalesce if both adjacent buddies are max free */ + if (*cp == l2free && *(cp + bsize) == l2free) { + *cp = l2free + 1; /* left take right */ + *(cp + bsize) = -1; /* right give left */ + } + } + } + + /* + * bubble summary information of leaves up the tree. + * + * Starting at the leaf node level, the four nodes described by + * the higher level parent node are compared for a maximum free and + * this maximum becomes the value of the parent node. + * when all lower level nodes are processed in this fashion then + * move up to the next level (parent becomes a lower level node) and + * continue the process for that level. + */ + for (child = le32_to_cpu(dtp->leafidx), + nparent = le32_to_cpu(dtp->nleafs) >> 2; + nparent > 0; nparent >>= 2, child = parent) { + /* get index of 1st node of parent level */ + parent = (child - 1) >> 2; + + /* set the value of the parent node as the maximum + * of the four nodes of the current level. + */ + for (i = 0, cp = tp + child, cp1 = tp + parent; + i < nparent; i++, cp += 4, cp1++) + *cp1 = TREEMAX(cp); + } + + return (*tp); +} + + +/* + * dbInitDmapCtl() + * + * function: initialize dmapctl page + */ +static int dbInitDmapCtl(dmapctl_t * dcp, int level, int i) +{ /* start leaf index not covered by range */ + s8 *cp; + + dcp->nleafs = cpu_to_le32(LPERCTL); + dcp->l2nleafs = cpu_to_le32(L2LPERCTL); + dcp->leafidx = cpu_to_le32(CTLLEAFIND); + dcp->height = cpu_to_le32(5); + dcp->budmin = L2BPERDMAP + L2LPERCTL * level; + + /* + * initialize the leaves of current level that were not covered + * by the specified input block range (i.e. the leaves have no + * low level dmapctl or dmap). + */ + cp = &dcp->stree[CTLLEAFIND + i]; + for (; i < LPERCTL; i++) + *cp++ = NOFREE; + + /* build the dmap's binary buddy summary tree */ + return (dbInitTree((dmaptree_t *) dcp)); +} + + +/* + * NAME: dbGetL2AGSize()/ujfs_getagl2size() + * + * FUNCTION: Determine log2(allocation group size) from aggregate size + * + * PARAMETERS: + * nblocks - Number of blocks in aggregate + * + * RETURNS: log2(allocation group size) in aggregate blocks + */ +static int dbGetL2AGSize(s64 nblocks) +{ + s64 sz; + s64 m; + int l2sz; + + if (nblocks < BPERDMAP * MAXAG) + return (L2BPERDMAP); + + /* round up aggregate size to power of 2 */ + m = ((u64) 1 << (64 - 1)); + for (l2sz = 64; l2sz >= 0; l2sz--, m >>= 1) { + if (m & nblocks) + break; + } + + sz = (s64) 1 << l2sz; + if (sz < nblocks) + l2sz += 1; + + /* agsize = roundupSize/max_number_of_ag */ + return (l2sz - L2MAXAG); +} + + +/* + * NAME: dbMapFileSizeToMapSize() + * + * FUNCTION: compute number of blocks the block allocation map file + * can cover from the map file size; + * + * RETURNS: Number of blocks which can be covered by this block map file; + */ + +/* + * maximum number of map pages at each level including control pages + */ +#define MAXL0PAGES (1 + LPERCTL) +#define MAXL1PAGES (1 + LPERCTL * MAXL0PAGES) +#define MAXL2PAGES (1 + LPERCTL * MAXL1PAGES) + +/* + * convert number of map pages to the zero origin top dmapctl level + */ +#define BMAPPGTOLEV(npages) \ + (((npages) <= 3 + MAXL0PAGES) ? 0 \ + : ((npages) <= 2 + MAXL1PAGES) ? 1 : 2) + +s64 dbMapFileSizeToMapSize(struct inode * ipbmap) +{ + struct super_block *sb = ipbmap->i_sb; + s64 nblocks; + s64 npages, ndmaps; + int level, i; + int complete, factor; + + nblocks = ipbmap->i_size >> JFS_SBI(sb)->l2bsize; + npages = nblocks >> JFS_SBI(sb)->l2nbperpage; + level = BMAPPGTOLEV(npages); + + /* At each level, accumulate the number of dmap pages covered by + * the number of full child levels below it; + * repeat for the last incomplete child level. + */ + ndmaps = 0; + npages--; /* skip the first global control page */ + /* skip higher level control pages above top level covered by map */ + npages -= (2 - level); + npages--; /* skip top level's control page */ + for (i = level; i >= 0; i--) { + factor = + (i == 2) ? MAXL1PAGES : ((i == 1) ? MAXL0PAGES : 1); + complete = (u32) npages / factor; + ndmaps += complete * ((i == 2) ? LPERCTL * LPERCTL + : ((i == 1) ? LPERCTL : 1)); + + /* pages in last/incomplete child */ + npages = (u32) npages % factor; + /* skip incomplete child's level control page */ + npages--; + } + + /* convert the number of dmaps into the number of blocks + * which can be covered by the dmaps; + */ + nblocks = ndmaps << L2BPERDMAP; + + return (nblocks); +} + + +#ifdef _JFS_DEBUG_DMAP +/* + * DBinitmap() + */ +static void DBinitmap(s64 size, struct inode *ipbmap, u32 ** results) +{ + int npages; + u32 *dbmap, *d; + int n; + s64 lblkno, cur_block; + dmap_t *dp; + metapage_t *mp; + + npages = size / 32768; + npages += (size % 32768) ? 1 : 0; + + dbmap = (u32 *) xmalloc(npages * 4096, L2PSIZE, kernel_heap); + if (dbmap == NULL) + assert(0); + + for (n = 0, d = dbmap; n < npages; n++, d += 1024) + bzero(d, 4096); + + /* Need to initialize from disk map pages + */ + for (d = dbmap, cur_block = 0; cur_block < size; + cur_block += BPERDMAP, d += LPERDMAP) { + lblkno = BLKTODMAP(cur_block, + JFS_SBI(ipbmap->i_sb)->bmap-> + db_l2nbperpage); + mp = read_metapage(ipbmap, lblkno, PSIZE, 0); + if (mp == NULL) { + assert(0); + } + dp = (dmap_t *) mp->data; + + for (n = 0; n < LPERDMAP; n++) + d[n] = le32_to_cpu(dp->wmap[n]); + + release_metapage(mp); + } + + *results = dbmap; +} + + +/* + * DBAlloc() + */ +void DBAlloc(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks) +{ + int word, nb, bitno; + u32 mask; + + assert(blkno > 0 && blkno < mapsize); + assert(nblocks > 0 && nblocks <= mapsize); + + assert(blkno + nblocks <= mapsize); + + dbmap += (blkno / 32); + while (nblocks > 0) { + bitno = blkno & (32 - 1); + nb = min(nblocks, 32 - bitno); + + mask = (0xffffffff << (32 - nb) >> bitno); + assert((mask & *dbmap) == 0); + *dbmap |= mask; + + dbmap++; + blkno += nb; + nblocks -= nb; + } +} + + +/* + * DBFree() + */ +static void DBFree(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks) +{ + int word, nb, bitno; + u32 mask; + + assert(blkno > 0 && blkno < mapsize); + assert(nblocks > 0 && nblocks <= mapsize); + + assert(blkno + nblocks <= mapsize); + + dbmap += (blkno / 32); + while (nblocks > 0) { + bitno = blkno & (32 - 1); + nb = min(nblocks, 32 - bitno); + + mask = (0xffffffff << (32 - nb) >> bitno); + assert((mask & *dbmap) == mask); + *dbmap &= ~mask; + + dbmap++; + blkno += nb; + nblocks -= nb; + } +} + + +/* + * DBAllocCK() + */ +static void DBAllocCK(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks) +{ + int word, nb, bitno; + u32 mask; + + assert(blkno > 0 && blkno < mapsize); + assert(nblocks > 0 && nblocks <= mapsize); + + assert(blkno + nblocks <= mapsize); + + dbmap += (blkno / 32); + while (nblocks > 0) { + bitno = blkno & (32 - 1); + nb = min(nblocks, 32 - bitno); + + mask = (0xffffffff << (32 - nb) >> bitno); + assert((mask & *dbmap) == mask); + + dbmap++; + blkno += nb; + nblocks -= nb; + } +} + + +/* + * DBFreeCK() + */ +static void DBFreeCK(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks) +{ + int word, nb, bitno; + u32 mask; + + assert(blkno > 0 && blkno < mapsize); + assert(nblocks > 0 && nblocks <= mapsize); + + assert(blkno + nblocks <= mapsize); + + dbmap += (blkno / 32); + while (nblocks > 0) { + bitno = blkno & (32 - 1); + nb = min(nblocks, 32 - bitno); + + mask = (0xffffffff << (32 - nb) >> bitno); + assert((mask & *dbmap) == 0); + + dbmap++; + blkno += nb; + nblocks -= nb; + } +} + + +/* + * dbPrtMap() + */ +static void dbPrtMap(bmap_t * bmp) +{ + printk(" mapsize: %d%d\n", bmp->db_mapsize); + printk(" nfree: %d%d\n", bmp->db_nfree); + printk(" numag: %d\n", bmp->db_numag); + printk(" agsize: %d%d\n", bmp->db_agsize); + printk(" agl2size: %d\n", bmp->db_agl2size); + printk(" agwidth: %d\n", bmp->db_agwidth); + printk(" agstart: %d\n", bmp->db_agstart); + printk(" agheigth: %d\n", bmp->db_agheigth); + printk(" aglevel: %d\n", bmp->db_aglevel); + printk(" maxlevel: %d\n", bmp->db_maxlevel); + printk(" maxag: %d\n", bmp->db_maxag); + printk(" agpref: %d\n", bmp->db_agpref); + printk(" l2nbppg: %d\n", bmp->db_l2nbperpage); +} + + +/* + * dbPrtCtl() + */ +static void dbPrtCtl(dmapctl_t * dcp) +{ + int i, j, n; + + printk(" height: %08x\n", le32_to_cpu(dcp->height)); + printk(" leafidx: %08x\n", le32_to_cpu(dcp->leafidx)); + printk(" budmin: %08x\n", dcp->budmin); + printk(" nleafs: %08x\n", le32_to_cpu(dcp->nleafs)); + printk(" l2nleafs: %08x\n", le32_to_cpu(dcp->l2nleafs)); + + printk("\n Tree:\n"); + for (i = 0; i < CTLLEAFIND; i += 8) { + n = min(8, CTLLEAFIND - i); + + for (j = 0; j < n; j++) + printf(" [%03x]: %02x", i + j, + (char) dcp->stree[i + j]); + printf("\n"); + } + + printk("\n Tree Leaves:\n"); + for (i = 0; i < LPERCTL; i += 8) { + n = min(8, LPERCTL - i); + + for (j = 0; j < n; j++) + printf(" [%03x]: %02x", + i + j, + (char) dcp->stree[i + j + CTLLEAFIND]); + printf("\n"); + } +} +#endif /* _JFS_DEBUG_DMAP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_dmap.h linux.20pre2-ac1/fs/jfs/jfs_dmap.h --- linux.20pre2/fs/jfs/jfs_dmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_dmap.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,298 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 _H_JFS_DMAP +#define _H_JFS_DMAP + +#include "jfs_txnmgr.h" + +#define BMAPVERSION 1 /* version number */ +#define TREESIZE (256+64+16+4+1) /* size of a dmap tree */ +#define LEAFIND (64+16+4+1) /* index of 1st leaf of a dmap tree */ +#define LPERDMAP 256 /* num leaves per dmap tree */ +#define L2LPERDMAP 8 /* l2 number of leaves per dmap tree */ +#define DBWORD 32 /* # of blks covered by a map word */ +#define L2DBWORD 5 /* l2 # of blks covered by a mword */ +#define BUDMIN L2DBWORD /* max free string in a map word */ +#define BPERDMAP (LPERDMAP * DBWORD) /* num of blks per dmap */ +#define L2BPERDMAP 13 /* l2 num of blks per dmap */ +#define CTLTREESIZE (1024+256+64+16+4+1) /* size of a dmapctl tree */ +#define CTLLEAFIND (256+64+16+4+1) /* idx of 1st leaf of a dmapctl tree */ +#define LPERCTL 1024 /* num of leaves per dmapctl tree */ +#define L2LPERCTL 10 /* l2 num of leaves per dmapctl tree */ +#define ROOT 0 /* index of the root of a tree */ +#define NOFREE ((s8) -1) /* no blocks free */ +#define MAXAG 128 /* max number of allocation groups */ +#define L2MAXAG 7 /* l2 max num of AG */ +#define L2MINAGSZ 25 /* l2 of minimum AG size in bytes */ +#define BMAPBLKNO 0 /* lblkno of bmap within the map */ + +/* + * maximum l2 number of disk blocks at the various dmapctl levels. + */ +#define L2MAXL0SIZE (L2BPERDMAP + 1 * L2LPERCTL) +#define L2MAXL1SIZE (L2BPERDMAP + 2 * L2LPERCTL) +#define L2MAXL2SIZE (L2BPERDMAP + 3 * L2LPERCTL) + +/* + * maximum number of disk blocks at the various dmapctl levels. + */ +#define MAXL0SIZE ((s64)1 << L2MAXL0SIZE) +#define MAXL1SIZE ((s64)1 << L2MAXL1SIZE) +#define MAXL2SIZE ((s64)1 << L2MAXL2SIZE) + +#define MAXMAPSIZE MAXL2SIZE /* maximum aggregate map size */ + +/* + * determine the maximum free string for four (lower level) nodes + * of the tree. + */ +static __inline signed char TREEMAX(signed char *cp) +{ + signed char tmp1, tmp2; + + tmp1 = max(*(cp+2), *(cp+3)); + tmp2 = max(*(cp), *(cp+1)); + + return max(tmp1, tmp2); +} + +/* + * convert disk block number to the logical block number of the dmap + * describing the disk block. s is the log2(number of logical blocks per page) + * + * The calculation figures out how many logical pages are in front of the dmap. + * - the number of dmaps preceding it + * - the number of L0 pages preceding its L0 page + * - the number of L1 pages preceding its L1 page + * - 3 is added to account for the L2, L1, and L0 page for this dmap + * - 1 is added to account for the control page of the map. + */ +#define BLKTODMAP(b,s) \ + ((((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1) << (s)) + +/* + * convert disk block number to the logical block number of the LEVEL 0 + * dmapctl describing the disk block. s is the log2(number of logical blocks + * per page) + * + * The calculation figures out how many logical pages are in front of the L0. + * - the number of dmap pages preceding it + * - the number of L0 pages preceding it + * - the number of L1 pages preceding its L1 page + * - 2 is added to account for the L2, and L1 page for this L0 + * - 1 is added to account for the control page of the map. + */ +#define BLKTOL0(b,s) \ + (((((b) >> 23) << 10) + ((b) >> 23) + ((b) >> 33) + 2 + 1) << (s)) + +/* + * convert disk block number to the logical block number of the LEVEL 1 + * dmapctl describing the disk block. s is the log2(number of logical blocks + * per page) + * + * The calculation figures out how many logical pages are in front of the L1. + * - the number of dmap pages preceding it + * - the number of L0 pages preceding it + * - the number of L1 pages preceding it + * - 1 is added to account for the L2 page + * - 1 is added to account for the control page of the map. + */ +#define BLKTOL1(b,s) \ + (((((b) >> 33) << 20) + (((b) >> 33) << 10) + ((b) >> 33) + 1 + 1) << (s)) + +/* + * convert disk block number to the logical block number of the dmapctl + * at the specified level which describes the disk block. + */ +#define BLKTOCTL(b,s,l) \ + (((l) == 2) ? 1 : ((l) == 1) ? BLKTOL1((b),(s)) : BLKTOL0((b),(s))) + +/* + * convert aggregate map size to the zero origin dmapctl level of the + * top dmapctl. + */ +#define BMAPSZTOLEV(size) \ + (((size) <= MAXL0SIZE) ? 0 : ((size) <= MAXL1SIZE) ? 1 : 2) + +/* convert disk block number to allocation group number. + */ +#define BLKTOAG(b,sbi) ((b) >> ((sbi)->bmap->db_agl2size)) + +/* convert allocation group number to starting disk block + * number. + */ +#define AGTOBLK(a,ip) \ + ((s64)(a) << (JFS_SBI((ip)->i_sb)->bmap->db_agl2size)) + +/* + * dmap summary tree + * + * dmaptree_t must be consistent with dmapctl_t. + */ +typedef struct { + s32 nleafs; /* 4: number of tree leafs */ + s32 l2nleafs; /* 4: l2 number of tree leafs */ + s32 leafidx; /* 4: index of first tree leaf */ + s32 height; /* 4: height of the tree */ + s8 budmin; /* 1: min l2 tree leaf value to combine */ + s8 stree[TREESIZE]; /* TREESIZE: tree */ + u8 pad[2]; /* 2: pad to word boundary */ +} dmaptree_t; /* - 360 - */ + +/* + * dmap page per 8K blocks bitmap + */ +typedef struct { + s32 nblocks; /* 4: num blks covered by this dmap */ + s32 nfree; /* 4: num of free blks in this dmap */ + s64 start; /* 8: starting blkno for this dmap */ + dmaptree_t tree; /* 360: dmap tree */ + u8 pad[1672]; /* 1672: pad to 2048 bytes */ + u32 wmap[LPERDMAP]; /* 1024: bits of the working map */ + u32 pmap[LPERDMAP]; /* 1024: bits of the persistent map */ +} dmap_t; /* - 4096 - */ + +/* + * disk map control page per level. + * + * dmapctl_t must be consistent with dmaptree_t. + */ +typedef struct { + s32 nleafs; /* 4: number of tree leafs */ + s32 l2nleafs; /* 4: l2 number of tree leafs */ + s32 leafidx; /* 4: index of the first tree leaf */ + s32 height; /* 4: height of tree */ + s8 budmin; /* 1: minimum l2 tree leaf value */ + s8 stree[CTLTREESIZE]; /* CTLTREESIZE: dmapctl tree */ + u8 pad[2714]; /* 2714: pad to 4096 */ +} dmapctl_t; /* - 4096 - */ + +/* + * common definition for dmaptree_t within dmap and dmapctl + */ +typedef union { + dmaptree_t t1; + dmapctl_t t2; +} dmtree_t; + +/* macros for accessing fields within dmtree_t */ +#define dmt_nleafs t1.nleafs +#define dmt_l2nleafs t1.l2nleafs +#define dmt_leafidx t1.leafidx +#define dmt_height t1.height +#define dmt_budmin t1.budmin +#define dmt_stree t1.stree + +/* + * on-disk aggregate disk allocation map descriptor. + */ +typedef struct { + s64 dn_mapsize; /* 8: number of blocks in aggregate */ + s64 dn_nfree; /* 8: num free blks in aggregate map */ + s32 dn_l2nbperpage; /* 4: number of blks per page */ + s32 dn_numag; /* 4: total number of ags */ + s32 dn_maxlevel; /* 4: number of active ags */ + s32 dn_maxag; /* 4: max active alloc group number */ + s32 dn_agpref; /* 4: preferred alloc group (hint) */ + s32 dn_aglevel; /* 4: dmapctl level holding the AG */ + s32 dn_agheigth; /* 4: height in dmapctl of the AG */ + s32 dn_agwidth; /* 4: width in dmapctl of the AG */ + s32 dn_agstart; /* 4: start tree index at AG height */ + s32 dn_agl2size; /* 4: l2 num of blks per alloc group */ + s64 dn_agfree[MAXAG]; /* 8*MAXAG: per AG free count */ + s64 dn_agsize; /* 8: num of blks per alloc group */ + s8 dn_maxfreebud; /* 1: max free buddy system */ + u8 pad[3007]; /* 3007: pad to 4096 */ +} dbmap_t; /* - 4096 - */ + +/* + * in-memory aggregate disk allocation map descriptor. + */ +typedef struct bmap { + dbmap_t db_bmap; /* on-disk aggregate map descriptor */ + struct inode *db_ipbmap; /* ptr to aggregate map incore inode */ + struct semaphore db_bmaplock; /* aggregate map lock */ + u32 *db_DBmap; +} bmap_t; + +/* macros for accessing fields within in-memory aggregate map descriptor */ +#define db_mapsize db_bmap.dn_mapsize +#define db_nfree db_bmap.dn_nfree +#define db_agfree db_bmap.dn_agfree +#define db_agsize db_bmap.dn_agsize +#define db_agl2size db_bmap.dn_agl2size +#define db_agwidth db_bmap.dn_agwidth +#define db_agheigth db_bmap.dn_agheigth +#define db_agstart db_bmap.dn_agstart +#define db_numag db_bmap.dn_numag +#define db_maxlevel db_bmap.dn_maxlevel +#define db_aglevel db_bmap.dn_aglevel +#define db_agpref db_bmap.dn_agpref +#define db_maxag db_bmap.dn_maxag +#define db_maxfreebud db_bmap.dn_maxfreebud +#define db_l2nbperpage db_bmap.dn_l2nbperpage + +/* + * macros for various conversions needed by the allocators. + * blkstol2(), cntlz(), and cnttz() are operating system dependent functions. + */ +/* convert number of blocks to log2 number of blocks, rounding up to + * the next log2 value if blocks is not a l2 multiple. + */ +#define BLKSTOL2(d) (blkstol2(d)) + +/* convert number of leafs to log2 leaf value */ +#define NLSTOL2BSZ(n) (31 - cntlz((n)) + BUDMIN) + +/* convert leaf index to log2 leaf value */ +#define LITOL2BSZ(n,m,b) ((((n) == 0) ? (m) : cnttz((n))) + (b)) + +/* convert a block number to a dmap control leaf index */ +#define BLKTOCTLLEAF(b,m) \ + (((b) & (((s64)1 << ((m) + L2LPERCTL)) - 1)) >> (m)) + +/* convert log2 leaf value to buddy size */ +#define BUDSIZE(s,m) (1 << ((s) - (m))) + +/* + * external references. + */ +extern int dbMount(struct inode *ipbmap); + +extern int dbUnmount(struct inode *ipbmap, int mounterror); + +extern int dbFree(struct inode *ipbmap, s64 blkno, s64 nblocks); + +extern int dbUpdatePMap(struct inode *ipbmap, + int free, s64 blkno, s64 nblocks, tblock_t * tblk); + +extern int dbNextAG(struct inode *ipbmap); + +extern int dbAlloc(struct inode *ipbmap, s64 hint, s64 nblocks, s64 * results); + +extern int dbAllocExact(struct inode *ip, s64 blkno, int nblocks); + +extern int dbReAlloc(struct inode *ipbmap, + s64 blkno, s64 nblocks, s64 addnblocks, s64 * results); + +extern int dbSync(struct inode *ipbmap); +extern int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks); +extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks); +extern void dbFinalizeBmap(struct inode *ipbmap); +extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap); +#endif /* _H_JFS_DMAP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_dtree.c linux.20pre2-ac1/fs/jfs/jfs_dtree.c --- linux.20pre2/fs/jfs/jfs_dtree.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_dtree.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,4520 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 + */ + +/* + * jfs_dtree.c: directory B+-tree manager + * + * B+-tree with variable length key directory: + * + * each directory page is structured as an array of 32-byte + * directory entry slots initialized as a freelist + * to avoid search/compaction of free space at insertion. + * when an entry is inserted, a number of slots are allocated + * from the freelist as required to store variable length data + * of the entry; when the entry is deleted, slots of the entry + * are returned to freelist. + * + * leaf entry stores full name as key and file serial number + * (aka inode number) as data. + * internal/router entry stores sufffix compressed name + * as key and simple extent descriptor as data. + * + * each directory page maintains a sorted entry index table + * which stores the start slot index of sorted entries + * to allow binary search on the table. + * + * directory starts as a root/leaf page in on-disk inode + * inline data area. + * when it becomes full, it starts a leaf of a external extent + * of length of 1 block. each time the first leaf becomes full, + * it is extended rather than split (its size is doubled), + * until its length becoms 4 KBytes, from then the extent is split + * with new 4 Kbyte extent when it becomes full + * to reduce external fragmentation of small directories. + * + * blah, blah, blah, for linear scan of directory in pieces by + * readdir(). + * + * + * case-insensitive directory file system + * + * names are stored in case-sensitive way in leaf entry. + * but stored, searched and compared in case-insensitive (uppercase) order + * (i.e., both search key and entry key are folded for search/compare): + * (note that case-sensitive order is BROKEN in storage, e.g., + * sensitive: Ad, aB, aC, aD -> insensitive: aB, aC, aD, Ad + * + * entries which folds to the same key makes up a equivalent class + * whose members are stored as contiguous cluster (may cross page boundary) + * but whose order is arbitrary and acts as duplicate, e.g., + * abc, Abc, aBc, abC) + * + * once match is found at leaf, requires scan forward/backward + * either for, in case-insensitive search, duplicate + * or for, in case-sensitive search, for exact match + * + * router entry must be created/stored in case-insensitive way + * in internal entry: + * (right most key of left page and left most key of right page + * are folded, and its suffix compression is propagated as router + * key in parent) + * (e.g., if split occurs and , trather than + * should be made the router key for the split) + * + * case-insensitive search: + * + * fold search key; + * + * case-insensitive search of B-tree: + * for internal entry, router key is already folded; + * for leaf entry, fold the entry key before comparison. + * + * if (leaf entry case-insensitive match found) + * if (next entry satisfies case-insensitive match) + * return EDUPLICATE; + * if (prev entry satisfies case-insensitive match) + * return EDUPLICATE; + * return match; + * else + * return no match; + * + * serialization: + * target directory inode lock is being held on entry/exit + * of all main directory service routines. + * + * log based recovery: + */ + +#include +#include +#include "jfs_incore.h" +#include "jfs_superblock.h" +#include "jfs_filsys.h" +#include "jfs_metapage.h" +#include "jfs_dmap.h" +#include "jfs_unicode.h" +#include "jfs_debug.h" + +/* dtree split parameter */ +typedef struct { + metapage_t *mp; + s16 index; + s16 nslot; + component_t *key; + ddata_t *data; + pxdlist_t *pxdlist; +} dtsplit_t; + +#define DT_PAGE(IP, MP) BT_PAGE(IP, MP, dtpage_t, i_dtroot) + +/* get page buffer for specified block address */ +#define DT_GETPAGE(IP, BN, MP, SIZE, P, RC)\ +{\ + BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot)\ + if (!(RC))\ + {\ + if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\ + ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\ + {\ + jERROR(1,("DT_GETPAGE: dtree page corrupt\n"));\ + BT_PUTPAGE(MP);\ + updateSuper((IP)->i_sb, FM_DIRTY);\ + MP = NULL;\ + RC = EIO;\ + }\ + }\ +} + +/* for consistency */ +#define DT_PUTPAGE(MP) BT_PUTPAGE(MP) + +#define DT_GETSEARCH(IP, LEAF, BN, MP, P, INDEX) \ + BT_GETSEARCH(IP, LEAF, BN, MP, dtpage_t, P, INDEX, i_dtroot) + +/* + * forward references + */ +static int dtSplitUp(tid_t tid, struct inode *ip, + dtsplit_t * split, btstack_t * btstack); + +static int dtSplitPage(tid_t tid, struct inode *ip, dtsplit_t * split, + metapage_t ** rmpp, dtpage_t ** rpp, pxd_t * rxdp); + +static int dtExtendPage(tid_t tid, struct inode *ip, + dtsplit_t * split, btstack_t * btstack); + +static int dtSplitRoot(tid_t tid, struct inode *ip, + dtsplit_t * split, metapage_t ** rmpp); + +static int dtDeleteUp(tid_t tid, struct inode *ip, metapage_t * fmp, + dtpage_t * fp, btstack_t * btstack); + +static int dtSearchNode(struct inode *ip, + s64 lmxaddr, pxd_t * kpxd, btstack_t * btstack); + +static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p); + +static int dtReadFirst(struct inode *ip, btstack_t * btstack); + +static int dtReadNext(struct inode *ip, + loff_t * offset, btstack_t * btstack); + +static int dtCompare(component_t * key, dtpage_t * p, int si); + +static int ciCompare(component_t * key, dtpage_t * p, int si, int flag); + +static void dtGetKey(dtpage_t * p, int i, component_t * key, int flag); + +static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp, + int ri, component_t * key, int flag); + +static void dtInsertEntry(dtpage_t * p, int index, component_t * key, + ddata_t * data, dtlock_t ** dtlock); + +static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp, + dtlock_t ** sdtlock, dtlock_t ** ddtlock, + int do_index); + +static void dtDeleteEntry(dtpage_t * p, int fi, dtlock_t ** dtlock); + +static void dtTruncateEntry(dtpage_t * p, int ti, dtlock_t ** dtlock); + +static void dtLinelockFreelist(dtpage_t * p, int m, dtlock_t ** dtlock); + +#define ciToUpper(c) UniStrupr((c)->name) + +/* + * find_index() + * + * Returns dtree page containing directory table entry for specified + * index and pointer to its entry. + * + * mp must be released by caller. + */ +static dir_table_slot_t *find_index(struct inode *ip, u32 index, + metapage_t ** mp) +{ + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + s64 blkno; + s64 offset; + int page_offset; + dir_table_slot_t *slot; + static int maxWarnings = 10; + + if (index < 2) { + if (maxWarnings) { + jERROR(1, ("find_entry called with index = %d\n", + index)); + maxWarnings--; + } + return 0; + } + + if (index >= jfs_ip->next_index) { + jFYI(1, ("find_entry called with index >= next_index\n")); + return 0; + } + + if (jfs_ip->next_index <= (MAX_INLINE_DIRTABLE_ENTRY + 1)) { + /* + * Inline directory table + */ + *mp = 0; + slot = &jfs_ip->i_dirtable[index - 2]; + } else { + offset = (index - 2) * sizeof(dir_table_slot_t); + page_offset = offset & (PSIZE - 1); + blkno = ((offset + 1) >> L2PSIZE) << + JFS_SBI(ip->i_sb)->l2nbperpage; + + if (*mp && ((*mp)->index != blkno)) { + release_metapage(*mp); + *mp = 0; + } + if (*mp == 0) + *mp = read_metapage(ip, blkno, PSIZE, 0); + if (*mp == 0) { + jERROR(1, + ("free_index: error reading directory table\n")); + return 0; + } + + slot = + (dir_table_slot_t *) ((char *) (*mp)->data + + page_offset); + } + return slot; +} + +static inline void lock_index(tid_t tid, struct inode *ip, metapage_t * mp, + u32 index) +{ + tlock_t *tlck; + linelock_t *llck; + lv_t *lv; + + tlck = txLock(tid, ip, mp, tlckDATA); + llck = (linelock_t *) tlck->lock; + + if (llck->index >= llck->maxcnt) + llck = txLinelock(llck); + lv = &llck->lv[llck->index]; + + /* + * Linelock slot size is twice the size of directory table + * slot size. 512 entries per page. + */ + lv->offset = ((index - 2) & 511) >> 1; + lv->length = 1; + llck->index++; +} + +/* + * add_index() + * + * Adds an entry to the directory index table. This is used to provide + * each directory entry with a persistent index in which to resume + * directory traversals + */ +static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) +{ + struct super_block *sb = ip->i_sb; + struct jfs_sb_info *sbi = JFS_SBI(sb); + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + u64 blkno; + dir_table_slot_t *dirtab_slot; + u32 index; + linelock_t *llck; + lv_t *lv; + metapage_t *mp; + s64 offset; + uint page_offset; + int rc; + tlock_t *tlck; + s64 xaddr; + + ASSERT(DO_INDEX(ip)); + + if (jfs_ip->next_index < 2) { + jERROR(1, ("next_index = %d. Please fix this!\n", + jfs_ip->next_index)); + jfs_ip->next_index = 2; + } + + index = jfs_ip->next_index++; + + if (index <= MAX_INLINE_DIRTABLE_ENTRY) { + /* + * i_size reflects size of index table, or 8 bytes per entry. + */ + ip->i_size = (loff_t) (index - 1) << 3; + + /* + * dir table fits inline within inode + */ + dirtab_slot = &jfs_ip->i_dirtable[index-2]; + dirtab_slot->flag = DIR_INDEX_VALID; + dirtab_slot->slot = slot; + DTSaddress(dirtab_slot, bn); + + set_cflag(COMMIT_Dirtable, ip); + + return index; + } + if (index == (MAX_INLINE_DIRTABLE_ENTRY + 1)) { + /* + * It's time to move the inline table to an external + * page and begin to build the xtree + */ + + /* + * Save the table, we're going to overwrite it with the + * xtree root + */ + dir_table_slot_t temp_table[12]; + memcpy(temp_table, &jfs_ip->i_dirtable, sizeof(temp_table)); + + /* + * Initialize empty x-tree + */ + xtInitRoot(tid, ip); + + /* + * Allocate the first block & add it to the xtree + */ + xaddr = 0; + if ((rc = + xtInsert(tid, ip, 0, 0, sbi->nbperpage, + &xaddr, 0))) { + jFYI(1, ("add_index: xtInsert failed!\n")); + return -1; + } + ip->i_size = PSIZE; + ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage); + + if ((mp = get_metapage(ip, 0, ip->i_blksize, 0)) == 0) { + jERROR(1, ("add_index: get_metapage failed!\n")); + xtTruncate(tid, ip, 0, COMMIT_PWMAP); + return -1; + } + tlck = txLock(tid, ip, mp, tlckDATA); + llck = (linelock_t *) & tlck->lock; + ASSERT(llck->index == 0); + lv = &llck->lv[0]; + + lv->offset = 0; + lv->length = 6; /* tlckDATA slot size is 16 bytes */ + llck->index++; + + memcpy(mp->data, temp_table, sizeof(temp_table)); + + mark_metapage_dirty(mp); + release_metapage(mp); + + /* + * Logging is now directed by xtree tlocks + */ + clear_cflag(COMMIT_Dirtable, ip); + } + + offset = (index - 2) * sizeof(dir_table_slot_t); + page_offset = offset & (PSIZE - 1); + blkno = ((offset + 1) >> L2PSIZE) << sbi->l2nbperpage; + if (page_offset == 0) { + /* + * This will be the beginning of a new page + */ + xaddr = 0; + if ((rc = + xtInsert(tid, ip, 0, blkno, sbi->nbperpage, + &xaddr, 0))) { + jFYI(1, ("add_index: xtInsert failed!\n")); + jfs_ip->next_index--; + return -1; + } + ip->i_size += PSIZE; + ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage); + + if ((mp = get_metapage(ip, blkno, PSIZE, 0))) + memset(mp->data, 0, PSIZE); /* Just looks better */ + else + xtTruncate(tid, ip, offset, COMMIT_PWMAP); + } else + mp = read_metapage(ip, blkno, PSIZE, 0); + + if (mp == 0) { + jERROR(1, ("add_index: get/read_metapage failed!\n")); + return -1; + } + + lock_index(tid, ip, mp, index); + + dirtab_slot = + (dir_table_slot_t *) ((char *) mp->data + page_offset); + dirtab_slot->flag = DIR_INDEX_VALID; + dirtab_slot->slot = slot; + DTSaddress(dirtab_slot, bn); + + mark_metapage_dirty(mp); + release_metapage(mp); + + return index; +} + +/* + * free_index() + * + * Marks an entry to the directory index table as free. + */ +static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next) +{ + dir_table_slot_t *dirtab_slot; + metapage_t *mp = 0; + + dirtab_slot = find_index(ip, index, &mp); + + if (dirtab_slot == 0) + return; + + dirtab_slot->flag = DIR_INDEX_FREE; + dirtab_slot->slot = dirtab_slot->addr1 = 0; + dirtab_slot->addr2 = cpu_to_le32(next); + + if (mp) { + lock_index(tid, ip, mp, index); + mark_metapage_dirty(mp); + release_metapage(mp); + } else + set_cflag(COMMIT_Dirtable, ip); +} + +/* + * modify_index() + * + * Changes an entry in the directory index table + */ +static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn, + int slot, metapage_t ** mp) +{ + dir_table_slot_t *dirtab_slot; + + dirtab_slot = find_index(ip, index, mp); + + if (dirtab_slot == 0) + return; + + DTSaddress(dirtab_slot, bn); + dirtab_slot->slot = slot; + + if (*mp) { + lock_index(tid, ip, *mp, index); + mark_metapage_dirty(*mp); + } else + set_cflag(COMMIT_Dirtable, ip); +} + +/* + * get_index() + * + * reads a directory table slot + */ +static int get_index(struct inode *ip, u32 index, + dir_table_slot_t * dirtab_slot) +{ + metapage_t *mp = 0; + dir_table_slot_t *slot; + + slot = find_index(ip, index, &mp); + if (slot == 0) { + return -EIO; + } + + memcpy(dirtab_slot, slot, sizeof(dir_table_slot_t)); + + if (mp) + release_metapage(mp); + + return 0; +} + +/* + * dtSearch() + * + * function: + * Search for the entry with specified key + * + * parameter: + * + * return: 0 - search result on stack, leaf page pinned; + * errno - I/O error + */ +int dtSearch(struct inode *ip, + component_t * key, ino_t * data, btstack_t * btstack, int flag) +{ + int rc = 0; + int cmp = 1; /* init for empty page */ + s64 bn; + metapage_t *mp; + dtpage_t *p; + s8 *stbl; + int base, index, lim; + btframe_t *btsp; + pxd_t *pxd; + int psize = 288; /* initial in-line directory */ + ino_t inumber; + component_t ciKey; + struct super_block *sb = ip->i_sb; + + ciKey.name = + (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), + GFP_NOFS); + if (ciKey.name == 0) { + rc = ENOMEM; + goto dtSearch_Exit2; + } + + + /* uppercase search key for c-i directory */ + UniStrcpy(ciKey.name, key->name); + ciKey.namlen = key->namlen; + + /* only uppercase if case-insensitive support is on */ + if ((JFS_SBI(sb)->mntflag & JFS_OS2) == JFS_OS2) { + ciToUpper(&ciKey); + } + BT_CLR(btstack); /* reset stack */ + + /* init level count for max pages to split */ + btstack->nsplit = 1; + + /* + * search down tree from root: + * + * between two consecutive entries of and of + * internal page, child page Pi contains entry with k, Ki <= K < Kj. + * + * if entry with search key K is not found + * internal page search find the entry with largest key Ki + * less than K which point to the child page to search; + * leaf page search find the entry with smallest key Kj + * greater than K so that the returned index is the position of + * the entry to be shifted right for insertion of new entry. + * for empty tree, search key is greater than any key of the tree. + * + * by convention, root bn = 0. + */ + for (bn = 0;;) { + /* get/pin the page to search */ + DT_GETPAGE(ip, bn, mp, psize, p, rc); + if (rc) + goto dtSearch_Exit1; + + /* get sorted entry table of the page */ + stbl = DT_GETSTBL(p); + + /* + * binary search with search key K on the current page. + */ + for (base = 0, lim = p->header.nextindex; lim; lim >>= 1) { + index = base + (lim >> 1); + + if (p->header.flag & BT_LEAF) { + /* uppercase leaf name to compare */ + cmp = + ciCompare(&ciKey, p, stbl[index], + JFS_SBI(sb)->mntflag); + } else { + /* router key is in uppercase */ + + cmp = dtCompare(&ciKey, p, stbl[index]); + + + } + if (cmp == 0) { + /* + * search hit + */ + /* search hit - leaf page: + * return the entry found + */ + if (p->header.flag & BT_LEAF) { + inumber = le32_to_cpu( + ((ldtentry_t *) & p->slot[stbl[index]])->inumber); + + /* + * search for JFS_LOOKUP + */ + if (flag == JFS_LOOKUP) { + *data = inumber; + rc = 0; + goto out; + } + + /* + * search for JFS_CREATE + */ + if (flag == JFS_CREATE) { + *data = inumber; + rc = EEXIST; + goto out; + } + + /* + * search for JFS_REMOVE or JFS_RENAME + */ + if ((flag == JFS_REMOVE || + flag == JFS_RENAME) && + *data != inumber) { + rc = ESTALE; + goto out; + } + + /* + * JFS_REMOVE|JFS_FINDDIR|JFS_RENAME + */ + /* save search result */ + *data = inumber; + btsp = btstack->top; + btsp->bn = bn; + btsp->index = index; + btsp->mp = mp; + + rc = 0; + goto dtSearch_Exit1; + } + + /* search hit - internal page: + * descend/search its child page + */ + goto getChild; + } + + if (cmp > 0) { + base = index + 1; + --lim; + } + } + + /* + * search miss + * + * base is the smallest index with key (Kj) greater than + * search key (K) and may be zero or (maxindex + 1) index. + */ + /* + * search miss - leaf page + * + * return location of entry (base) where new entry with + * search key K is to be inserted. + */ + if (p->header.flag & BT_LEAF) { + /* + * search for JFS_LOOKUP, JFS_REMOVE, or JFS_RENAME + */ + if (flag == JFS_LOOKUP || flag == JFS_REMOVE || + flag == JFS_RENAME) { + rc = ENOENT; + goto out; + } + + /* + * search for JFS_CREATE|JFS_FINDDIR: + * + * save search result + */ + *data = 0; + btsp = btstack->top; + btsp->bn = bn; + btsp->index = base; + btsp->mp = mp; + + rc = 0; + goto dtSearch_Exit1; + } + + /* + * search miss - internal page + * + * if base is non-zero, decrement base by one to get the parent + * entry of the child page to search. + */ + index = base ? base - 1 : base; + + /* + * go down to child page + */ + getChild: + /* update max. number of pages to split */ + if (btstack->nsplit >= 8) { + /* Something's corrupted, mark filesytem dirty so + * chkdsk will fix it. + */ + jERROR(1, ("stack overrun in dtSearch!\n")); + updateSuper(sb, FM_DIRTY); + rc = EIO; + goto out; + } + btstack->nsplit++; + + /* push (bn, index) of the parent page/entry */ + BT_PUSH(btstack, bn, index); + + /* get the child page block number */ + pxd = (pxd_t *) & p->slot[stbl[index]]; + bn = addressPXD(pxd); + psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize; + + /* unpin the parent page */ + DT_PUTPAGE(mp); + } + + out: + DT_PUTPAGE(mp); + + dtSearch_Exit1: + + kfree(ciKey.name); + + dtSearch_Exit2: + + return rc; +} + + +/* + * dtInsert() + * + * function: insert an entry to directory tree + * + * parameter: + * + * return: 0 - success; + * errno - failure; + */ +int dtInsert(tid_t tid, struct inode *ip, + component_t * name, ino_t * fsn, btstack_t * btstack) +{ + int rc = 0; + metapage_t *mp; /* meta-page buffer */ + dtpage_t *p; /* base B+-tree index page */ + s64 bn; + int index; + dtsplit_t split; /* split information */ + ddata_t data; + dtlock_t *dtlck; + int n; + tlock_t *tlck; + lv_t *lv; + + /* + * retrieve search result + * + * dtSearch() returns (leaf page pinned, index at which to insert). + * n.b. dtSearch() may return index of (maxindex + 1) of + * the full page. + */ + DT_GETSEARCH(ip, btstack->top, bn, mp, p, index); + + /* + * insert entry for new key + */ + if (DO_INDEX(ip)) { + if (JFS_IP(ip)->next_index == DIREND) { + DT_PUTPAGE(mp); + return EMLINK; + } + n = NDTLEAF(name->namlen); + data.leaf.tid = tid; + data.leaf.ip = ip; + } else { + n = NDTLEAF_LEGACY(name->namlen); + data.leaf.ip = 0; /* signifies legacy directory format */ + } + data.leaf.ino = cpu_to_le32(*fsn); + + /* + * leaf page does not have enough room for new entry: + * + * extend/split the leaf page; + * + * dtSplitUp() will insert the entry and unpin the leaf page. + */ + if (n > p->header.freecnt) { + split.mp = mp; + split.index = index; + split.nslot = n; + split.key = name; + split.data = &data; + rc = dtSplitUp(tid, ip, &split, btstack); + return rc; + } + + /* + * leaf page does have enough room for new entry: + * + * insert the new data entry into the leaf page; + */ + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the leaf page + */ + tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY); + dtlck = (dtlock_t *) & tlck->lock; + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + + /* linelock header */ + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + dtInsertEntry(p, index, name, &data, &dtlck); + + /* linelock stbl of non-root leaf page */ + if (!(p->header.flag & BT_ROOT)) { + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + n = index >> L2DTSLOTSIZE; + lv->offset = p->header.stblindex + n; + lv->length = + ((p->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1; + dtlck->index++; + } + + /* unpin the leaf page */ + DT_PUTPAGE(mp); + + return 0; +} + + +/* + * dtSplitUp() + * + * function: propagate insertion bottom up; + * + * parameter: + * + * return: 0 - success; + * errno - failure; + * leaf page unpinned; + */ +static int dtSplitUp(tid_t tid, + struct inode *ip, dtsplit_t * split, btstack_t * btstack) +{ + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + int rc = 0; + metapage_t *smp; + dtpage_t *sp; /* split page */ + metapage_t *rmp; + dtpage_t *rp; /* new right page split from sp */ + pxd_t rpxd; /* new right page extent descriptor */ + metapage_t *lmp; + dtpage_t *lp; /* left child page */ + int skip; /* index of entry of insertion */ + btframe_t *parent; /* parent page entry on traverse stack */ + s64 xaddr, nxaddr; + int xlen, xsize; + pxdlist_t pxdlist; + pxd_t *pxd; + component_t key = { 0, 0 }; + ddata_t *data = split->data; + int n; + dtlock_t *dtlck; + tlock_t *tlck; + lv_t *lv; + + /* get split page */ + smp = split->mp; + sp = DT_PAGE(ip, smp); + + key.name = + (wchar_t *) kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t), + GFP_NOFS); + if (key.name == 0) { + DT_PUTPAGE(smp); + rc = ENOMEM; + goto dtSplitUp_Exit; + } + + /* + * split leaf page + * + * The split routines insert the new entry, and + * acquire txLock as appropriate. + */ + /* + * split root leaf page: + */ + if (sp->header.flag & BT_ROOT) { + /* + * allocate a single extent child page + */ + xlen = 1; + n = sbi->bsize >> L2DTSLOTSIZE; + n -= (n + 31) >> L2DTSLOTSIZE; /* stbl size */ + n -= DTROOTMAXSLOT - sp->header.freecnt; /* header + entries */ + if (n <= split->nslot) + xlen++; + if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr))) + goto freeKeyName; + + pxdlist.maxnpxd = 1; + pxdlist.npxd = 0; + pxd = &pxdlist.pxd[0]; + PXDaddress(pxd, xaddr); + PXDlength(pxd, xlen); + split->pxdlist = &pxdlist; + rc = dtSplitRoot(tid, ip, split, &rmp); + + DT_PUTPAGE(rmp); + DT_PUTPAGE(smp); + + goto freeKeyName; + } + + /* + * extend first leaf page + * + * extend the 1st extent if less than buffer page size + * (dtExtendPage() reurns leaf page unpinned) + */ + pxd = &sp->header.self; + xlen = lengthPXD(pxd); + xsize = xlen << sbi->l2bsize; + if (xsize < PSIZE) { + xaddr = addressPXD(pxd); + n = xsize >> L2DTSLOTSIZE; + n -= (n + 31) >> L2DTSLOTSIZE; /* stbl size */ + if ((n + sp->header.freecnt) <= split->nslot) + n = xlen + (xlen << 1); + else + n = xlen; + if ((rc = dbReAlloc(sbi->ipbmap, xaddr, (s64) xlen, + (s64) n, &nxaddr))) + goto extendOut; + + pxdlist.maxnpxd = 1; + pxdlist.npxd = 0; + pxd = &pxdlist.pxd[0]; + PXDaddress(pxd, nxaddr) + PXDlength(pxd, xlen + n); + split->pxdlist = &pxdlist; + if ((rc = dtExtendPage(tid, ip, split, btstack))) { + nxaddr = addressPXD(pxd); + if (xaddr != nxaddr) { + /* free relocated extent */ + xlen = lengthPXD(pxd); + dbFree(ip, nxaddr, (s64) xlen); + } else { + /* free extended delta */ + xlen = lengthPXD(pxd) - n; + xaddr = addressPXD(pxd) + xlen; + dbFree(ip, xaddr, (s64) n); + } + } + + extendOut: + DT_PUTPAGE(smp); + goto freeKeyName; + } + + /* + * split leaf page into and a new right page . + * + * return pinned and its extent descriptor + */ + /* + * allocate new directory page extent and + * new index page(s) to cover page split(s) + * + * allocation hint: ? + */ + n = btstack->nsplit; + pxdlist.maxnpxd = pxdlist.npxd = 0; + xlen = sbi->nbperpage; + for (pxd = pxdlist.pxd; n > 0; n--, pxd++) { + if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr)) == 0) { + PXDaddress(pxd, xaddr); + PXDlength(pxd, xlen); + pxdlist.maxnpxd++; + continue; + } + + DT_PUTPAGE(smp); + + /* undo allocation */ + goto splitOut; + } + + split->pxdlist = &pxdlist; + if ((rc = dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd))) { + DT_PUTPAGE(smp); + + /* undo allocation */ + goto splitOut; + } + + /* + * propagate up the router entry for the leaf page just split + * + * insert a router entry for the new page into the parent page, + * propagate the insert/split up the tree by walking back the stack + * of (bn of parent page, index of child page entry in parent page) + * that were traversed during the search for the page that split. + * + * the propagation of insert/split up the tree stops if the root + * splits or the page inserted into doesn't have to split to hold + * the new entry. + * + * the parent entry for the split page remains the same, and + * a new entry is inserted at its right with the first key and + * block number of the new right page. + * + * There are a maximum of 4 pages pinned at any time: + * two children, left parent and right parent (when the parent splits). + * keep the child pages pinned while working on the parent. + * make sure that all pins are released at exit. + */ + while ((parent = BT_POP(btstack)) != NULL) { + /* parent page specified by stack frame */ + + /* keep current child pages (, ) pinned */ + lmp = smp; + lp = sp; + + /* + * insert router entry in parent for new right child page + */ + /* get the parent page */ + DT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc); + if (rc) { + DT_PUTPAGE(lmp); + DT_PUTPAGE(rmp); + goto splitOut; + } + + /* + * The new key entry goes ONE AFTER the index of parent entry, + * because the split was to the right. + */ + skip = parent->index + 1; + + /* + * compute the key for the router entry + * + * key suffix compression: + * for internal pages that have leaf pages as children, + * retain only what's needed to distinguish between + * the new entry and the entry on the page to its left. + * If the keys compare equal, retain the entire key. + * + * note that compression is performed only at computing + * router key at the lowest internal level. + * further compression of the key between pairs of higher + * level internal pages loses too much information and + * the search may fail. + * (e.g., two adjacent leaf pages of {a, ..., x} {xx, ...,} + * results in two adjacent parent entries (a)(xx). + * if split occurs between these two entries, and + * if compression is applied, the router key of parent entry + * of right page (x) will divert search for x into right + * subtree and miss x in the left subtree.) + * + * the entire key must be retained for the next-to-leftmost + * internal key at any level of the tree, or search may fail + * (e.g., ?) + */ + switch (rp->header.flag & BT_TYPE) { + case BT_LEAF: + /* + * compute the length of prefix for suffix compression + * between last entry of left page and first entry + * of right page + */ + if ((sp->header.flag & BT_ROOT && skip > 1) || + sp->header.prev != 0 || skip > 1) { + /* compute uppercase router prefix key */ + ciGetLeafPrefixKey(lp, + lp->header.nextindex - 1, + rp, 0, &key, sbi->mntflag); + } else { + /* next to leftmost entry of + lowest internal level */ + + /* compute uppercase router key */ + dtGetKey(rp, 0, &key, sbi->mntflag); + key.name[key.namlen] = 0; + + if ((sbi->mntflag & JFS_OS2) == JFS_OS2) + ciToUpper(&key); + } + + n = NDTINTERNAL(key.namlen); + break; + + case BT_INTERNAL: + dtGetKey(rp, 0, &key, sbi->mntflag); + n = NDTINTERNAL(key.namlen); + break; + + default: + jERROR(2, ("dtSplitUp(): UFO!\n")); + break; + } + + /* unpin left child page */ + DT_PUTPAGE(lmp); + + /* + * compute the data for the router entry + */ + data->xd = rpxd; /* child page xd */ + + /* + * parent page is full - split the parent page + */ + if (n > sp->header.freecnt) { + /* init for parent page split */ + split->mp = smp; + split->index = skip; /* index at insert */ + split->nslot = n; + split->key = &key; + /* split->data = data; */ + + /* unpin right child page */ + DT_PUTPAGE(rmp); + + /* The split routines insert the new entry, + * acquire txLock as appropriate. + * return pinned and its block number . + */ + rc = (sp->header.flag & BT_ROOT) ? + dtSplitRoot(tid, ip, split, &rmp) : + dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd); + if (rc) { + DT_PUTPAGE(smp); + goto splitOut; + } + + /* smp and rmp are pinned */ + } + /* + * parent page is not full - insert router entry in parent page + */ + else { + BT_MARK_DIRTY(smp, ip); + /* + * acquire a transaction lock on the parent page + */ + tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY); + dtlck = (dtlock_t *) & tlck->lock; + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + + /* linelock header */ + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + /* linelock stbl of non-root parent page */ + if (!(sp->header.flag & BT_ROOT)) { + lv++; + n = skip >> L2DTSLOTSIZE; + lv->offset = sp->header.stblindex + n; + lv->length = + ((sp->header.nextindex - + 1) >> L2DTSLOTSIZE) - n + 1; + dtlck->index++; + } + + dtInsertEntry(sp, skip, &key, data, &dtlck); + + /* exit propagate up */ + break; + } + } + + /* unpin current split and its right page */ + DT_PUTPAGE(smp); + DT_PUTPAGE(rmp); + + /* + * free remaining extents allocated for split + */ + splitOut: + n = pxdlist.npxd; + pxd = &pxdlist.pxd[n]; + for (; n < pxdlist.maxnpxd; n++, pxd++) + dbFree(ip, addressPXD(pxd), (s64) lengthPXD(pxd)); + + freeKeyName: + kfree(key.name); + + dtSplitUp_Exit: + + return rc; +} + + +/* + * dtSplitPage() + * + * function: Split a non-root page of a btree. + * + * parameter: + * + * return: 0 - success; + * errno - failure; + * return split and new page pinned; + */ +static int dtSplitPage(tid_t tid, struct inode *ip, dtsplit_t * split, + metapage_t ** rmpp, dtpage_t ** rpp, pxd_t * rpxdp) +{ + struct super_block *sb = ip->i_sb; + int rc = 0; + metapage_t *smp; + dtpage_t *sp; + metapage_t *rmp; + dtpage_t *rp; /* new right page allocated */ + s64 rbn; /* new right page block number */ + metapage_t *mp; + dtpage_t *p; + s64 nextbn; + pxdlist_t *pxdlist; + pxd_t *pxd; + int skip, nextindex, half, left, nxt, off, si; + ldtentry_t *ldtentry; + idtentry_t *idtentry; + u8 *stbl; + dtslot_t *f; + int fsi, stblsize; + int n; + dtlock_t *sdtlck, *rdtlck; + tlock_t *tlck; + dtlock_t *dtlck; + lv_t *slv, *rlv, *lv; + + /* get split page */ + smp = split->mp; + sp = DT_PAGE(ip, smp); + + /* + * allocate the new right page for the split + */ + pxdlist = split->pxdlist; + pxd = &pxdlist->pxd[pxdlist->npxd]; + pxdlist->npxd++; + rbn = addressPXD(pxd); + rmp = get_metapage(ip, rbn, PSIZE, 1); + if (rmp == NULL) + return EIO; + + jEVENT(0, + ("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p\n", ip, smp, rmp)); + + BT_MARK_DIRTY(rmp, ip); + /* + * acquire a transaction lock on the new right page + */ + tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW); + rdtlck = (dtlock_t *) & tlck->lock; + + rp = (dtpage_t *) rmp->data; + *rpp = rp; + rp->header.self = *pxd; + + BT_MARK_DIRTY(smp, ip); + /* + * acquire a transaction lock on the split page + * + * action: + */ + tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY); + sdtlck = (dtlock_t *) & tlck->lock; + + /* linelock header of split page */ + ASSERT(sdtlck->index == 0); + slv = (lv_t *) & sdtlck->lv[0]; + slv->offset = 0; + slv->length = 1; + sdtlck->index++; + + /* + * initialize/update sibling pointers between sp and rp + */ + nextbn = le64_to_cpu(sp->header.next); + rp->header.next = cpu_to_le64(nextbn); + rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self)); + sp->header.next = cpu_to_le64(rbn); + + /* + * initialize new right page + */ + rp->header.flag = sp->header.flag; + + /* compute sorted entry table at start of extent data area */ + rp->header.nextindex = 0; + rp->header.stblindex = 1; + + n = PSIZE >> L2DTSLOTSIZE; + rp->header.maxslot = n; + stblsize = (n + 31) >> L2DTSLOTSIZE; /* in unit of slot */ + + /* init freelist */ + fsi = rp->header.stblindex + stblsize; + rp->header.freelist = fsi; + rp->header.freecnt = rp->header.maxslot - fsi; + + /* + * sequential append at tail: append without split + * + * If splitting the last page on a level because of appending + * a entry to it (skip is maxentry), it's likely that the access is + * sequential. Adding an empty page on the side of the level is less + * work and can push the fill factor much higher than normal. + * If we're wrong it's no big deal, we'll just do the split the right + * way next time. + * (It may look like it's equally easy to do a similar hack for + * reverse sorted data, that is, split the tree left, + * but it's not. Be my guest.) + */ + if (nextbn == 0 && split->index == sp->header.nextindex) { + /* linelock header + stbl (first slot) of new page */ + rlv = (lv_t *) & rdtlck->lv[rdtlck->index]; + rlv->offset = 0; + rlv->length = 2; + rdtlck->index++; + + /* + * initialize freelist of new right page + */ + f = &rp->slot[fsi]; + for (fsi++; fsi < rp->header.maxslot; f++, fsi++) + f->next = fsi; + f->next = -1; + + /* insert entry at the first entry of the new right page */ + dtInsertEntry(rp, 0, split->key, split->data, &rdtlck); + + goto out; + } + + /* + * non-sequential insert (at possibly middle page) + */ + + /* + * update prev pointer of previous right sibling page; + */ + if (nextbn != 0) { + DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc); + if (rc) + return rc; + + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the next page + */ + tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK); + jEVENT(0, + ("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p\n", + tlck, ip, mp)); + dtlck = (dtlock_t *) & tlck->lock; + + /* linelock header of previous right sibling page */ + lv = (lv_t *) & dtlck->lv[dtlck->index]; + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + p->header.prev = cpu_to_le64(rbn); + + DT_PUTPAGE(mp); + } + + /* + * split the data between the split and right pages. + */ + skip = split->index; + half = (PSIZE >> L2DTSLOTSIZE) >> 1; /* swag */ + left = 0; + + /* + * compute fill factor for split pages + * + * traces the next entry to move to rp + * traces the next entry to stay in sp + */ + stbl = (u8 *) & sp->slot[sp->header.stblindex]; + nextindex = sp->header.nextindex; + for (nxt = off = 0; nxt < nextindex; ++off) { + if (off == skip) + /* check for fill factor with new entry size */ + n = split->nslot; + else { + si = stbl[nxt]; + switch (sp->header.flag & BT_TYPE) { + case BT_LEAF: + ldtentry = (ldtentry_t *) & sp->slot[si]; + if (DO_INDEX(ip)) + n = NDTLEAF(ldtentry->namlen); + else + n = NDTLEAF_LEGACY(ldtentry-> + namlen); + break; + + case BT_INTERNAL: + idtentry = (idtentry_t *) & sp->slot[si]; + n = NDTINTERNAL(idtentry->namlen); + break; + + default: + break; + } + + ++nxt; /* advance to next entry to move in sp */ + } + + left += n; + if (left >= half) + break; + } + + /* poins to the 1st entry to move */ + + /* + * move entries to right page + * + * dtMoveEntry() initializes rp and reserves entry for insertion + * + * split page moved out entries are linelocked; + * new/right page moved in entries are linelocked; + */ + /* linelock header + stbl of new right page */ + rlv = (lv_t *) & rdtlck->lv[rdtlck->index]; + rlv->offset = 0; + rlv->length = 5; + rdtlck->index++; + + dtMoveEntry(sp, nxt, rp, &sdtlck, &rdtlck, DO_INDEX(ip)); + + sp->header.nextindex = nxt; + + /* + * finalize freelist of new right page + */ + fsi = rp->header.freelist; + f = &rp->slot[fsi]; + for (fsi++; fsi < rp->header.maxslot; f++, fsi++) + f->next = fsi; + f->next = -1; + + /* + * Update directory index table for entries now in right page + */ + if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) { + mp = 0; + stbl = DT_GETSTBL(rp); + for (n = 0; n < rp->header.nextindex; n++) { + ldtentry = (ldtentry_t *) & rp->slot[stbl[n]]; + modify_index(tid, ip, le32_to_cpu(ldtentry->index), + rbn, n, &mp); + } + if (mp) + release_metapage(mp); + } + + /* + * the skipped index was on the left page, + */ + if (skip <= off) { + /* insert the new entry in the split page */ + dtInsertEntry(sp, skip, split->key, split->data, &sdtlck); + + /* linelock stbl of split page */ + if (sdtlck->index >= sdtlck->maxcnt) + sdtlck = (dtlock_t *) txLinelock(sdtlck); + slv = (lv_t *) & sdtlck->lv[sdtlck->index]; + n = skip >> L2DTSLOTSIZE; + slv->offset = sp->header.stblindex + n; + slv->length = + ((sp->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1; + sdtlck->index++; + } + /* + * the skipped index was on the right page, + */ + else { + /* adjust the skip index to reflect the new position */ + skip -= nxt; + + /* insert the new entry in the right page */ + dtInsertEntry(rp, skip, split->key, split->data, &rdtlck); + } + + out: + *rmpp = rmp; + *rpxdp = *pxd; + + ip->i_blocks += LBLK2PBLK(sb, lengthPXD(pxd)); + + jEVENT(0, ("dtSplitPage: ip:0x%p sp:0x%p rp:0x%p\n", ip, sp, rp)); + return 0; +} + + +/* + * dtExtendPage() + * + * function: extend 1st/only directory leaf page + * + * parameter: + * + * return: 0 - success; + * errno - failure; + * return extended page pinned; + */ +static int dtExtendPage(tid_t tid, + struct inode *ip, dtsplit_t * split, btstack_t * btstack) +{ + struct super_block *sb = ip->i_sb; + int rc; + metapage_t *smp, *pmp, *mp; + dtpage_t *sp, *pp; + pxdlist_t *pxdlist; + pxd_t *pxd, *tpxd; + int xlen, xsize; + int newstblindex, newstblsize; + int oldstblindex, oldstblsize; + int fsi, last; + dtslot_t *f; + btframe_t *parent; + int n; + dtlock_t *dtlck; + s64 xaddr, txaddr; + tlock_t *tlck; + pxdlock_t *pxdlock; + lv_t *lv; + uint type; + ldtentry_t *ldtentry; + u8 *stbl; + + /* get page to extend */ + smp = split->mp; + sp = DT_PAGE(ip, smp); + + /* get parent/root page */ + parent = BT_POP(btstack); + DT_GETPAGE(ip, parent->bn, pmp, PSIZE, pp, rc); + if (rc) + return (rc); + + /* + * extend the extent + */ + pxdlist = split->pxdlist; + pxd = &pxdlist->pxd[pxdlist->npxd]; + pxdlist->npxd++; + + xaddr = addressPXD(pxd); + tpxd = &sp->header.self; + txaddr = addressPXD(tpxd); + /* in-place extension */ + if (xaddr == txaddr) { + type = tlckEXTEND; + } + /* relocation */ + else { + type = tlckNEW; + + /* save moved extent descriptor for later free */ + tlck = txMaplock(tid, ip, tlckDTREE | tlckRELOCATE); + pxdlock = (pxdlock_t *) & tlck->lock; + pxdlock->flag = mlckFREEPXD; + pxdlock->pxd = sp->header.self; + pxdlock->index = 1; + + /* + * Update directory index table to reflect new page address + */ + if (DO_INDEX(ip)) { + mp = 0; + stbl = DT_GETSTBL(sp); + for (n = 0; n < sp->header.nextindex; n++) { + ldtentry = + (ldtentry_t *) & sp->slot[stbl[n]]; + modify_index(tid, ip, + le32_to_cpu(ldtentry->index), + xaddr, n, &mp); + } + if (mp) + release_metapage(mp); + } + } + + /* + * extend the page + */ + sp->header.self = *pxd; + + jEVENT(0, + ("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p\n", ip, smp, sp)); + + BT_MARK_DIRTY(smp, ip); + /* + * acquire a transaction lock on the extended/leaf page + */ + tlck = txLock(tid, ip, smp, tlckDTREE | type); + dtlck = (dtlock_t *) & tlck->lock; + lv = (lv_t *) & dtlck->lv[0]; + + /* update buffer extent descriptor of extended page */ + xlen = lengthPXD(pxd); + xsize = xlen << JFS_SBI(sb)->l2bsize; +#ifdef _STILL_TO_PORT + bmSetXD(smp, xaddr, xsize); +#endif /* _STILL_TO_PORT */ + + /* + * copy old stbl to new stbl at start of extended area + */ + oldstblindex = sp->header.stblindex; + oldstblsize = (sp->header.maxslot + 31) >> L2DTSLOTSIZE; + newstblindex = sp->header.maxslot; + n = xsize >> L2DTSLOTSIZE; + newstblsize = (n + 31) >> L2DTSLOTSIZE; + memcpy(&sp->slot[newstblindex], &sp->slot[oldstblindex], + sp->header.nextindex); + + /* + * in-line extension: linelock old area of extended page + */ + if (type == tlckEXTEND) { + /* linelock header */ + lv->offset = 0; + lv->length = 1; + dtlck->index++; + lv++; + + /* linelock new stbl of extended page */ + lv->offset = newstblindex; + lv->length = newstblsize; + } + /* + * relocation: linelock whole relocated area + */ + else { + lv->offset = 0; + lv->length = sp->header.maxslot + newstblsize; + } + + dtlck->index++; + + sp->header.maxslot = n; + sp->header.stblindex = newstblindex; + /* sp->header.nextindex remains the same */ + + /* + * add old stbl region at head of freelist + */ + fsi = oldstblindex; + f = &sp->slot[fsi]; + last = sp->header.freelist; + for (n = 0; n < oldstblsize; n++, fsi++, f++) { + f->next = last; + last = fsi; + } + sp->header.freelist = last; + sp->header.freecnt += oldstblsize; + + /* + * append free region of newly extended area at tail of freelist + */ + /* init free region of newly extended area */ + fsi = n = newstblindex + newstblsize; + f = &sp->slot[fsi]; + for (fsi++; fsi < sp->header.maxslot; f++, fsi++) + f->next = fsi; + f->next = -1; + + /* append new free region at tail of old freelist */ + fsi = sp->header.freelist; + if (fsi == -1) + sp->header.freelist = n; + else { + do { + f = &sp->slot[fsi]; + fsi = f->next; + } while (fsi != -1); + + f->next = n; + } + + sp->header.freecnt += sp->header.maxslot - n; + + /* + * insert the new entry + */ + dtInsertEntry(sp, split->index, split->key, split->data, &dtlck); + + BT_MARK_DIRTY(pmp, ip); + /* + * linelock any freeslots residing in old extent + */ + if (type == tlckEXTEND) { + n = sp->header.maxslot >> 2; + if (sp->header.freelist < n) + dtLinelockFreelist(sp, n, &dtlck); + } + + /* + * update parent entry on the parent/root page + */ + /* + * acquire a transaction lock on the parent/root page + */ + tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY); + dtlck = (dtlock_t *) & tlck->lock; + lv = (lv_t *) & dtlck->lv[dtlck->index]; + + /* linelock parent entry - 1st slot */ + lv->offset = 1; + lv->length = 1; + dtlck->index++; + + /* update the parent pxd for page extension */ + tpxd = (pxd_t *) & pp->slot[1]; + *tpxd = *pxd; + + /* Since the directory might have an EA and/or ACL associated with it + * we need to make sure we take that into account when setting the + * i_nblocks + */ + ip->i_blocks = LBLK2PBLK(ip->i_sb, xlen + + ((JFS_IP(ip)->ea.flag & DXD_EXTENT) ? + lengthDXD(&JFS_IP(ip)->ea) : 0) + + ((JFS_IP(ip)->acl.flag & DXD_EXTENT) ? + lengthDXD(&JFS_IP(ip)->acl) : 0)); + + jEVENT(0, + ("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p\n", ip, smp, sp)); + + + DT_PUTPAGE(pmp); + return 0; +} + + +/* + * dtSplitRoot() + * + * function: + * split the full root page into + * original/root/split page and new right page + * i.e., root remains fixed in tree anchor (inode) and + * the root is copied to a single new right child page + * since root page << non-root page, and + * the split root page contains a single entry for the + * new right child page. + * + * parameter: + * + * return: 0 - success; + * errno - failure; + * return new page pinned; + */ +static int dtSplitRoot(tid_t tid, + struct inode *ip, dtsplit_t * split, metapage_t ** rmpp) +{ + struct super_block *sb = ip->i_sb; + metapage_t *smp; + dtroot_t *sp; + metapage_t *rmp; + dtpage_t *rp; + s64 rbn; + int xlen; + int xsize; + dtslot_t *f; + s8 *stbl; + int fsi, stblsize, n; + idtentry_t *s; + pxd_t *ppxd; + pxdlist_t *pxdlist; + pxd_t *pxd; + dtlock_t *dtlck; + tlock_t *tlck; + lv_t *lv; + + /* get split root page */ + smp = split->mp; + sp = &JFS_IP(ip)->i_dtroot; + + /* + * allocate/initialize a single (right) child page + * + * N.B. at first split, a one (or two) block to fit new entry + * is allocated; at subsequent split, a full page is allocated; + */ + pxdlist = split->pxdlist; + pxd = &pxdlist->pxd[pxdlist->npxd]; + pxdlist->npxd++; + rbn = addressPXD(pxd); + xlen = lengthPXD(pxd); + xsize = xlen << JFS_SBI(sb)->l2bsize; + rmp = get_metapage(ip, rbn, xsize, 1); + rp = rmp->data; + + BT_MARK_DIRTY(rmp, ip); + /* + * acquire a transaction lock on the new right page + */ + tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW); + dtlck = (dtlock_t *) & tlck->lock; + + rp->header.flag = + (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL; + rp->header.self = *pxd; + + /* initialize sibling pointers */ + rp->header.next = 0; + rp->header.prev = 0; + + /* + * move in-line root page into new right page extent + */ + /* linelock header + copied entries + new stbl (1st slot) in new page */ + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + lv->offset = 0; + lv->length = 10; /* 1 + 8 + 1 */ + dtlck->index++; + + n = xsize >> L2DTSLOTSIZE; + rp->header.maxslot = n; + stblsize = (n + 31) >> L2DTSLOTSIZE; + + /* copy old stbl to new stbl at start of extended area */ + rp->header.stblindex = DTROOTMAXSLOT; + stbl = (s8 *) & rp->slot[DTROOTMAXSLOT]; + memcpy(stbl, sp->header.stbl, sp->header.nextindex); + rp->header.nextindex = sp->header.nextindex; + + /* copy old data area to start of new data area */ + memcpy(&rp->slot[1], &sp->slot[1], IDATASIZE); + + /* + * append free region of newly extended area at tail of freelist + */ + /* init free region of newly extended area */ + fsi = n = DTROOTMAXSLOT + stblsize; + f = &rp->slot[fsi]; + for (fsi++; fsi < rp->header.maxslot; f++, fsi++) + f->next = fsi; + f->next = -1; + + /* append new free region at tail of old freelist */ + fsi = sp->header.freelist; + if (fsi == -1) + rp->header.freelist = n; + else { + rp->header.freelist = fsi; + + do { + f = &rp->slot[fsi]; + fsi = f->next; + } while (fsi != -1); + + f->next = n; + } + + rp->header.freecnt = sp->header.freecnt + rp->header.maxslot - n; + + /* + * Update directory index table for entries now in right page + */ + if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) { + metapage_t *mp = 0; + ldtentry_t *ldtentry; + + stbl = DT_GETSTBL(rp); + for (n = 0; n < rp->header.nextindex; n++) { + ldtentry = (ldtentry_t *) & rp->slot[stbl[n]]; + modify_index(tid, ip, le32_to_cpu(ldtentry->index), + rbn, n, &mp); + } + if (mp) + release_metapage(mp); + } + /* + * insert the new entry into the new right/child page + * (skip index in the new right page will not change) + */ + dtInsertEntry(rp, split->index, split->key, split->data, &dtlck); + + /* + * reset parent/root page + * + * set the 1st entry offset to 0, which force the left-most key + * at any level of the tree to be less than any search key. + * + * The btree comparison code guarantees that the left-most key on any + * level of the tree is never used, so it doesn't need to be filled in. + */ + BT_MARK_DIRTY(smp, ip); + /* + * acquire a transaction lock on the root page (in-memory inode) + */ + tlck = txLock(tid, ip, smp, tlckDTREE | tlckNEW | tlckBTROOT); + dtlck = (dtlock_t *) & tlck->lock; + + /* linelock root */ + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + lv->offset = 0; + lv->length = DTROOTMAXSLOT; + dtlck->index++; + + /* update page header of root */ + if (sp->header.flag & BT_LEAF) { + sp->header.flag &= ~BT_LEAF; + sp->header.flag |= BT_INTERNAL; + } + + /* init the first entry */ + s = (idtentry_t *) & sp->slot[DTENTRYSTART]; + ppxd = (pxd_t *) s; + *ppxd = *pxd; + s->next = -1; + s->namlen = 0; + + stbl = sp->header.stbl; + stbl[0] = DTENTRYSTART; + sp->header.nextindex = 1; + + /* init freelist */ + fsi = DTENTRYSTART + 1; + f = &sp->slot[fsi]; + + /* init free region of remaining area */ + for (fsi++; fsi < DTROOTMAXSLOT; f++, fsi++) + f->next = fsi; + f->next = -1; + + sp->header.freelist = DTENTRYSTART + 1; + sp->header.freecnt = DTROOTMAXSLOT - (DTENTRYSTART + 1); + + *rmpp = rmp; + + ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd)); + return 0; +} + + +/* + * dtDelete() + * + * function: delete the entry(s) referenced by a key. + * + * parameter: + * + * return: + */ +int dtDelete(tid_t tid, + struct inode *ip, component_t * key, ino_t * ino, int flag) +{ + int rc = 0; + s64 bn; + metapage_t *mp, *imp; + dtpage_t *p; + int index; + btstack_t btstack; + dtlock_t *dtlck; + tlock_t *tlck; + lv_t *lv; + int i; + ldtentry_t *ldtentry; + u8 *stbl; + u32 table_index, next_index; + metapage_t *nmp; + dtpage_t *np; + + /* + * search for the entry to delete: + * + * dtSearch() returns (leaf page pinned, index at which to delete). + */ + if ((rc = dtSearch(ip, key, ino, &btstack, flag))) + return rc; + + /* retrieve search result */ + DT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + /* + * We need to find put the index of the next entry into the + * directory index table in order to resume a readdir from this + * entry. + */ + if (DO_INDEX(ip)) { + stbl = DT_GETSTBL(p); + ldtentry = (ldtentry_t *) & p->slot[stbl[index]]; + table_index = le32_to_cpu(ldtentry->index); + if (index == (p->header.nextindex - 1)) { + /* + * Last entry in this leaf page + */ + if ((p->header.flag & BT_ROOT) + || (p->header.next == 0)) + next_index = -1; + else { + /* Read next leaf page */ + DT_GETPAGE(ip, le64_to_cpu(p->header.next), + nmp, PSIZE, np, rc); + if (rc) + next_index = -1; + else { + stbl = DT_GETSTBL(np); + ldtentry = + (ldtentry_t *) & np-> + slot[stbl[0]]; + next_index = + le32_to_cpu(ldtentry->index); + DT_PUTPAGE(nmp); + } + } + } else { + ldtentry = + (ldtentry_t *) & p->slot[stbl[index + 1]]; + next_index = le32_to_cpu(ldtentry->index); + } + free_index(tid, ip, table_index, next_index); + } + /* + * the leaf page becomes empty, delete the page + */ + if (p->header.nextindex == 1) { + /* delete empty page */ + rc = dtDeleteUp(tid, ip, mp, p, &btstack); + } + /* + * the leaf page has other entries remaining: + * + * delete the entry from the leaf page. + */ + else { + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the leaf page + */ + tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY); + dtlck = (dtlock_t *) & tlck->lock; + + /* + * Do not assume that dtlck->index will be zero. During a + * rename within a directory, this transaction may have + * modified this page already when adding the new entry. + */ + + /* linelock header */ + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + /* linelock stbl of non-root leaf page */ + if (!(p->header.flag & BT_ROOT)) { + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + i = index >> L2DTSLOTSIZE; + lv->offset = p->header.stblindex + i; + lv->length = + ((p->header.nextindex - 1) >> L2DTSLOTSIZE) - + i + 1; + dtlck->index++; + } + + /* free the leaf entry */ + dtDeleteEntry(p, index, &dtlck); + + /* + * Update directory index table for entries moved in stbl + */ + if (DO_INDEX(ip) && index < p->header.nextindex) { + imp = 0; + stbl = DT_GETSTBL(p); + for (i = index; i < p->header.nextindex; i++) { + ldtentry = + (ldtentry_t *) & p->slot[stbl[i]]; + modify_index(tid, ip, + le32_to_cpu(ldtentry->index), + bn, i, &imp); + } + if (imp) + release_metapage(imp); + } + + DT_PUTPAGE(mp); + } + + return rc; +} + + +/* + * dtDeleteUp() + * + * function: + * free empty pages as propagating deletion up the tree + * + * parameter: + * + * return: + */ +static int dtDeleteUp(tid_t tid, struct inode *ip, + metapage_t * fmp, dtpage_t * fp, btstack_t * btstack) +{ + int rc = 0; + metapage_t *mp; + dtpage_t *p; + int index, nextindex; + int xlen; + btframe_t *parent; + dtlock_t *dtlck; + tlock_t *tlck; + lv_t *lv; + pxdlock_t *pxdlock; + int i; + + /* + * keep the root leaf page which has become empty + */ + if (BT_IS_ROOT(fmp)) { + /* + * reset the root + * + * dtInitRoot() acquires txlock on the root + */ + dtInitRoot(tid, ip, PARENT(ip)); + + DT_PUTPAGE(fmp); + + return 0; + } + + /* + * free the non-root leaf page + */ + /* + * acquire a transaction lock on the page + * + * write FREEXTENT|NOREDOPAGE log record + * N.B. linelock is overlaid as freed extent descriptor, and + * the buffer page is freed; + */ + tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE); + pxdlock = (pxdlock_t *) & tlck->lock; + pxdlock->flag = mlckFREEPXD; + pxdlock->pxd = fp->header.self; + pxdlock->index = 1; + + /* update sibling pointers */ + if ((rc = dtRelink(tid, ip, fp))) + return rc; + + xlen = lengthPXD(&fp->header.self); + ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen); + + /* free/invalidate its buffer page */ + discard_metapage(fmp); + + /* + * propagate page deletion up the directory tree + * + * If the delete from the parent page makes it empty, + * continue all the way up the tree. + * stop if the root page is reached (which is never deleted) or + * if the entry deletion does not empty the page. + */ + while ((parent = BT_POP(btstack)) != NULL) { + /* pin the parent page */ + DT_GETPAGE(ip, parent->bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* + * free the extent of the child page deleted + */ + index = parent->index; + + /* + * delete the entry for the child page from parent + */ + nextindex = p->header.nextindex; + + /* + * the parent has the single entry being deleted: + * + * free the parent page which has become empty. + */ + if (nextindex == 1) { + /* + * keep the root internal page which has become empty + */ + if (p->header.flag & BT_ROOT) { + /* + * reset the root + * + * dtInitRoot() acquires txlock on the root + */ + dtInitRoot(tid, ip, PARENT(ip)); + + DT_PUTPAGE(mp); + + return 0; + } + /* + * free the parent page + */ + else { + /* + * acquire a transaction lock on the page + * + * write FREEXTENT|NOREDOPAGE log record + */ + tlck = + txMaplock(tid, ip, + tlckDTREE | tlckFREE); + pxdlock = (pxdlock_t *) & tlck->lock; + pxdlock->flag = mlckFREEPXD; + pxdlock->pxd = p->header.self; + pxdlock->index = 1; + + /* update sibling pointers */ + if ((rc = dtRelink(tid, ip, p))) + return rc; + + xlen = lengthPXD(&p->header.self); + ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen); + + /* free/invalidate its buffer page */ + discard_metapage(mp); + + /* propagate up */ + continue; + } + } + + /* + * the parent has other entries remaining: + * + * delete the router entry from the parent page. + */ + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the page + * + * action: router entry deletion + */ + tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY); + dtlck = (dtlock_t *) & tlck->lock; + + /* linelock header */ + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + /* linelock stbl of non-root leaf page */ + if (!(p->header.flag & BT_ROOT)) { + if (dtlck->index < dtlck->maxcnt) + lv++; + else { + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[0]; + } + i = index >> L2DTSLOTSIZE; + lv->offset = p->header.stblindex + i; + lv->length = + ((p->header.nextindex - 1) >> L2DTSLOTSIZE) - + i + 1; + dtlck->index++; + } + + /* free the router entry */ + dtDeleteEntry(p, index, &dtlck); + + /* reset key of new leftmost entry of level (for consistency) */ + if (index == 0 && + ((p->header.flag & BT_ROOT) || p->header.prev == 0)) + dtTruncateEntry(p, 0, &dtlck); + + /* unpin the parent page */ + DT_PUTPAGE(mp); + + /* exit propagation up */ + break; + } + + return 0; +} + + +/* + * NAME: dtRelocate() + * + * FUNCTION: relocate dtpage (internal or leaf) of directory; + * This function is mainly used by defragfs utility. + */ +int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd, + s64 nxaddr) +{ + int rc = 0; + metapage_t *mp, *pmp, *lmp, *rmp; + dtpage_t *p, *pp, *rp = 0, *lp= 0; + s64 bn; + int index; + btstack_t btstack; + pxd_t *pxd; + s64 oxaddr, nextbn, prevbn; + int xlen, xsize; + tlock_t *tlck; + dtlock_t *dtlck; + pxdlock_t *pxdlock; + s8 *stbl; + lv_t *lv; + + oxaddr = addressPXD(opxd); + xlen = lengthPXD(opxd); + + jEVENT(0, ("dtRelocate: lmxaddr:%Ld xaddr:%Ld:%Ld xlen:%d\n", + (long long)lmxaddr, (long long)oxaddr, (long long)nxaddr, xlen)); + + /* + * 1. get the internal parent dtpage covering + * router entry for the tartget page to be relocated; + */ + rc = dtSearchNode(ip, lmxaddr, opxd, &btstack); + if (rc) + return rc; + + /* retrieve search result */ + DT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); + jEVENT(0, ("dtRelocate: parent router entry validated.\n")); + + /* + * 2. relocate the target dtpage + */ + /* read in the target page from src extent */ + DT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc); + if (rc) { + /* release the pinned parent page */ + DT_PUTPAGE(pmp); + return rc; + } + + /* + * read in sibling pages if any to update sibling pointers; + */ + rmp = NULL; + if (p->header.next) { + nextbn = le64_to_cpu(p->header.next); + DT_GETPAGE(ip, nextbn, rmp, PSIZE, rp, rc); + if (rc) { + DT_PUTPAGE(mp); + DT_PUTPAGE(pmp); + return (rc); + } + } + + lmp = NULL; + if (p->header.prev) { + prevbn = le64_to_cpu(p->header.prev); + DT_GETPAGE(ip, prevbn, lmp, PSIZE, lp, rc); + if (rc) { + DT_PUTPAGE(mp); + DT_PUTPAGE(pmp); + if (rmp) + DT_PUTPAGE(rmp); + return (rc); + } + } + + /* at this point, all xtpages to be updated are in memory */ + + /* + * update sibling pointers of sibling dtpages if any; + */ + if (lmp) { + tlck = txLock(tid, ip, lmp, tlckDTREE | tlckRELINK); + dtlck = (dtlock_t *) & tlck->lock; + /* linelock header */ + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + lp->header.next = cpu_to_le64(nxaddr); + DT_PUTPAGE(lmp); + } + + if (rmp) { + tlck = txLock(tid, ip, rmp, tlckDTREE | tlckRELINK); + dtlck = (dtlock_t *) & tlck->lock; + /* linelock header */ + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + rp->header.prev = cpu_to_le64(nxaddr); + DT_PUTPAGE(rmp); + } + + /* + * update the target dtpage to be relocated + * + * write LOG_REDOPAGE of LOG_NEW type for dst page + * for the whole target page (logredo() will apply + * after image and update bmap for allocation of the + * dst extent), and update bmap for allocation of + * the dst extent; + */ + tlck = txLock(tid, ip, mp, tlckDTREE | tlckNEW); + dtlck = (dtlock_t *) & tlck->lock; + /* linelock header */ + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + + /* update the self address in the dtpage header */ + pxd = &p->header.self; + PXDaddress(pxd, nxaddr); + + /* the dst page is the same as the src page, i.e., + * linelock for afterimage of the whole page; + */ + lv->offset = 0; + lv->length = p->header.maxslot; + dtlck->index++; + + /* update the buffer extent descriptor of the dtpage */ + xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize; +#ifdef _STILL_TO_PORT + bmSetXD(mp, nxaddr, xsize); +#endif /* _STILL_TO_PORT */ + /* unpin the relocated page */ + DT_PUTPAGE(mp); + jEVENT(0, ("dtRelocate: target dtpage relocated.\n")); + + /* the moved extent is dtpage, then a LOG_NOREDOPAGE log rec + * needs to be written (in logredo(), the LOG_NOREDOPAGE log rec + * will also force a bmap update ). + */ + + /* + * 3. acquire maplock for the source extent to be freed; + */ + /* for dtpage relocation, write a LOG_NOREDOPAGE record + * for the source dtpage (logredo() will init NoRedoPage + * filter and will also update bmap for free of the source + * dtpage), and upadte bmap for free of the source dtpage; + */ + tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE); + pxdlock = (pxdlock_t *) & tlck->lock; + pxdlock->flag = mlckFREEPXD; + PXDaddress(&pxdlock->pxd, oxaddr); + PXDlength(&pxdlock->pxd, xlen); + pxdlock->index = 1; + + /* + * 4. update the parent router entry for relocation; + * + * acquire tlck for the parent entry covering the target dtpage; + * write LOG_REDOPAGE to apply after image only; + */ + jEVENT(0, ("dtRelocate: update parent router entry.\n")); + tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY); + dtlck = (dtlock_t *) & tlck->lock; + lv = (lv_t *) & dtlck->lv[dtlck->index]; + + /* update the PXD with the new address */ + stbl = DT_GETSTBL(pp); + pxd = (pxd_t *) & pp->slot[stbl[index]]; + PXDaddress(pxd, nxaddr); + lv->offset = stbl[index]; + lv->length = 1; + dtlck->index++; + + /* unpin the parent dtpage */ + DT_PUTPAGE(pmp); + + return rc; +} + + +/* + * NAME: dtSearchNode() + * + * FUNCTION: Search for an dtpage containing a specified address + * This function is mainly used by defragfs utility. + * + * NOTE: Search result on stack, the found page is pinned at exit. + * The result page must be an internal dtpage. + * lmxaddr give the address of the left most page of the + * dtree level, in which the required dtpage resides. + */ +static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd, + btstack_t * btstack) +{ + int rc = 0; + s64 bn; + metapage_t *mp; + dtpage_t *p; + int psize = 288; /* initial in-line directory */ + s8 *stbl; + int i; + pxd_t *pxd; + btframe_t *btsp; + + BT_CLR(btstack); /* reset stack */ + + /* + * descend tree to the level with specified leftmost page + * + * by convention, root bn = 0. + */ + for (bn = 0;;) { + /* get/pin the page to search */ + DT_GETPAGE(ip, bn, mp, psize, p, rc); + if (rc) + return rc; + + /* does the xaddr of leftmost page of the levevl + * matches levevl search key ? + */ + if (p->header.flag & BT_ROOT) { + if (lmxaddr == 0) + break; + } else if (addressPXD(&p->header.self) == lmxaddr) + break; + + /* + * descend down to leftmost child page + */ + if (p->header.flag & BT_LEAF) + return ESTALE; + + /* get the leftmost entry */ + stbl = DT_GETSTBL(p); + pxd = (pxd_t *) & p->slot[stbl[0]]; + + /* get the child page block address */ + bn = addressPXD(pxd); + psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize; + /* unpin the parent page */ + DT_PUTPAGE(mp); + } + + /* + * search each page at the current levevl + */ + loop: + stbl = DT_GETSTBL(p); + for (i = 0; i < p->header.nextindex; i++) { + pxd = (pxd_t *) & p->slot[stbl[i]]; + + /* found the specified router entry */ + if (addressPXD(pxd) == addressPXD(kpxd) && + lengthPXD(pxd) == lengthPXD(kpxd)) { + btsp = btstack->top; + btsp->bn = bn; + btsp->index = i; + btsp->mp = mp; + + return 0; + } + } + + /* get the right sibling page if any */ + if (p->header.next) + bn = le64_to_cpu(p->header.next); + else { + DT_PUTPAGE(mp); + return ESTALE; + } + + /* unpin current page */ + DT_PUTPAGE(mp); + + /* get the right sibling page */ + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + goto loop; +} + + +/* + * dtRelink() + * + * function: + * link around a freed page. + * + * parameter: + * fp: page to be freed + * + * return: + */ +static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p) +{ + int rc; + metapage_t *mp; + s64 nextbn, prevbn; + tlock_t *tlck; + dtlock_t *dtlck; + lv_t *lv; + + nextbn = le64_to_cpu(p->header.next); + prevbn = le64_to_cpu(p->header.prev); + + /* update prev pointer of the next page */ + if (nextbn != 0) { + DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc); + if (rc) + return rc; + + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the next page + * + * action: update prev pointer; + */ + tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK); + jEVENT(0, + ("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n", + tlck, ip, mp)); + dtlck = (dtlock_t *) & tlck->lock; + + /* linelock header */ + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + p->header.prev = cpu_to_le64(prevbn); + DT_PUTPAGE(mp); + } + + /* update next pointer of the previous page */ + if (prevbn != 0) { + DT_GETPAGE(ip, prevbn, mp, PSIZE, p, rc); + if (rc) + return rc; + + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the prev page + * + * action: update next pointer; + */ + tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK); + jEVENT(0, + ("dtRelink prevbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n", + tlck, ip, mp)); + dtlck = (dtlock_t *) & tlck->lock; + + /* linelock header */ + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + lv->offset = 0; + lv->length = 1; + dtlck->index++; + + p->header.next = cpu_to_le64(nextbn); + DT_PUTPAGE(mp); + } + + return 0; +} + + +/* + * dtInitRoot() + * + * initialize directory root (inline in inode) + */ +void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot) +{ + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + dtroot_t *p; + int fsi; + dtslot_t *f; + tlock_t *tlck; + dtlock_t *dtlck; + lv_t *lv; + u16 xflag_save; + + /* + * If this was previously an non-empty directory, we need to remove + * the old directory table. + */ + if (DO_INDEX(ip)) { + if (jfs_ip->next_index > (MAX_INLINE_DIRTABLE_ENTRY + 1)) { + tblock_t *tblk = tid_to_tblock(tid); + /* + * We're playing games with the tid's xflag. If + * we're removing a regular file, the file's xtree + * is committed with COMMIT_PMAP, but we always + * commit the directories xtree with COMMIT_PWMAP. + */ + xflag_save = tblk->xflag; + tblk->xflag = 0; + /* + * xtTruncate isn't guaranteed to fully truncate + * the xtree. The caller needs to check i_size + * after committing the transaction to see if + * additional truncation is needed. The + * COMMIT_Stale flag tells caller that we + * initiated the truncation. + */ + xtTruncate(tid, ip, 0, COMMIT_PWMAP); + set_cflag(COMMIT_Stale, ip); + + tblk->xflag = xflag_save; + /* + * Tells jfs_metapage code that the metadata pages + * for the index table are no longer useful, and + * remove them from page cache. + */ + invalidate_inode_metapages(ip); + } else + ip->i_size = 1; + + jfs_ip->next_index = 2; + } else + ip->i_size = IDATASIZE; + + /* + * acquire a transaction lock on the root + * + * action: directory initialization; + */ + tlck = txLock(tid, ip, (metapage_t *) & jfs_ip->bxflag, + tlckDTREE | tlckENTRY | tlckBTROOT); + dtlck = (dtlock_t *) & tlck->lock; + + /* linelock root */ + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + lv->offset = 0; + lv->length = DTROOTMAXSLOT; + dtlck->index++; + + p = &jfs_ip->i_dtroot; + + p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF; + + p->header.nextindex = 0; + + /* init freelist */ + fsi = 1; + f = &p->slot[fsi]; + + /* init data area of root */ + for (fsi++; fsi < DTROOTMAXSLOT; f++, fsi++) + f->next = fsi; + f->next = -1; + + p->header.freelist = 1; + p->header.freecnt = 8; + + /* init '..' entry */ + p->header.idotdot = cpu_to_le32(idotdot); + +#if 0 + ip->i_blocks = LBLK2PBLK(ip->i_sb, + ((jfs_ip->ea.flag & DXD_EXTENT) ? + lengthDXD(&jfs_ip->ea) : 0) + + ((jfs_ip->acl.flag & DXD_EXTENT) ? + lengthDXD(&jfs_ip->acl) : 0)); +#endif + + return; +} + +/* + * jfs_readdir() + * + * function: read directory entries sequentially + * from the specified entry offset + * + * parameter: + * + * return: offset = (pn, index) of start entry + * of next jfs_readdir()/dtRead() + */ +int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct inode *ip = filp->f_dentry->d_inode; + struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab; + int rc = 0; + struct dtoffset { + s16 pn; + s16 index; + s32 unused; + } *dtoffset = (struct dtoffset *) &filp->f_pos; + s64 bn; + metapage_t *mp; + dtpage_t *p; + int index; + s8 *stbl; + btstack_t btstack; + int i, next; + ldtentry_t *d; + dtslot_t *t; + int d_namleft, d_namlen, len, outlen; + char *d_name, *name_ptr; + int dtlhdrdatalen; + u32 dir_index; + int do_index = 0; + uint loop_count = 0; + + if (filp->f_pos == DIREND) + return 0; + + if (DO_INDEX(ip)) { + /* + * persistent index is stored in directory entries. + * Special cases: 0 = . + * 1 = .. + * -1 = End of directory + */ + do_index = 1; + dtlhdrdatalen = DTLHDRDATALEN; + + dir_index = (u32) filp->f_pos; + + if (dir_index > 1) { + dir_table_slot_t dirtab_slot; + + if (dtEmpty(ip)) { + filp->f_pos = DIREND; + return 0; + } + repeat: + rc = get_index(ip, dir_index, &dirtab_slot); + if (rc) { + filp->f_pos = DIREND; + return rc; + } + if (dirtab_slot.flag == DIR_INDEX_FREE) { + if (loop_count++ > JFS_IP(ip)->next_index) { + jERROR(1, ("jfs_readdir detected " + "infinite loop!\n")); + filp->f_pos = DIREND; + return 0; + } + dir_index = le32_to_cpu(dirtab_slot.addr2); + if (dir_index == -1) { + filp->f_pos = DIREND; + return 0; + } + goto repeat; + } + bn = addressDTS(&dirtab_slot); + index = dirtab_slot.slot; + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) { + filp->f_pos = DIREND; + return 0; + } + if (p->header.flag & BT_INTERNAL) { + jERROR(1,("jfs_readdir: bad index table\n")); + DT_PUTPAGE(mp); + filp->f_pos = -1; + return 0; + } + } else { + if (dir_index == 0) { + /* + * self "." + */ + filp->f_pos = 0; + if (filldir(dirent, ".", 1, 0, ip->i_ino, + DT_DIR)) + return 0; + } + /* + * parent ".." + */ + filp->f_pos = 1; + if (filldir + (dirent, "..", 2, 1, PARENT(ip), DT_DIR)) + return 0; + + /* + * Find first entry of left-most leaf + */ + if (dtEmpty(ip)) { + filp->f_pos = DIREND; + return 0; + } + + if ((rc = dtReadFirst(ip, &btstack))) + return -rc; + + DT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + } + } else { + /* + * Legacy filesystem - OS/2 & Linux JFS < 0.3.6 + * + * pn = index = 0: First entry "." + * pn = 0; index = 1: Second entry ".." + * pn > 0: Real entries, pn=1 -> leftmost page + * pn = index = -1: No more entries + */ + dtlhdrdatalen = DTLHDRDATALEN_LEGACY; + + if (filp->f_pos == 0) { + /* build "." entry */ + + if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino, + DT_DIR)) + return 0; + dtoffset->index = 1; + } + + if (dtoffset->pn == 0) { + if (dtoffset->index == 1) { + /* build ".." entry */ + + if (filldir(dirent, "..", 2, filp->f_pos, + PARENT(ip), DT_DIR)) + return 0; + } else { + jERROR(1, + ("jfs_readdir called with invalid offset!\n")); + } + dtoffset->pn = 1; + dtoffset->index = 0; + } + + if (dtEmpty(ip)) { + filp->f_pos = DIREND; + return 0; + } + + if ((rc = dtReadNext(ip, &filp->f_pos, &btstack))) { + jERROR(1, + ("jfs_readdir: unexpected rc = %d from dtReadNext\n", + rc)); + filp->f_pos = DIREND; + return 0; + } + /* get start leaf page and index */ + DT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + /* offset beyond directory eof ? */ + if (bn < 0) { + filp->f_pos = DIREND; + return 0; + } + } + + d_name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_NOFS); + if (d_name == NULL) { + DT_PUTPAGE(mp); + jERROR(1, ("jfs_readdir: kmalloc failed!\n")); + filp->f_pos = DIREND; + return 0; + } + while (1) { + stbl = DT_GETSTBL(p); + + for (i = index; i < p->header.nextindex; i++) { + d = (ldtentry_t *) & p->slot[stbl[i]]; + + d_namleft = d->namlen; + name_ptr = d_name; + + if (do_index) { + filp->f_pos = le32_to_cpu(d->index); + len = min(d_namleft, DTLHDRDATALEN); + } else + len = min(d_namleft, DTLHDRDATALEN_LEGACY); + + /* copy the name of head/only segment */ + outlen = jfs_strfromUCS_le(name_ptr, d->name, len, + codepage); + d_namlen = outlen; + + /* copy name in the additional segment(s) */ + next = d->next; + while (next >= 0) { + t = (dtslot_t *) & p->slot[next]; + name_ptr += outlen; + d_namleft -= len; + /* Sanity Check */ + if (d_namleft == 0) { + jERROR(1,("JFS:Dtree error: " + "ino = %ld, bn=%Ld, index = %d\n", + (long)ip->i_ino, (long long)bn, i)); + updateSuper(ip->i_sb, FM_DIRTY); + goto skip_one; + } + len = min(d_namleft, DTSLOTDATALEN); + outlen = jfs_strfromUCS_le(name_ptr, t->name, + len, codepage); + d_namlen+= outlen; + + next = t->next; + } + + if (filldir(dirent, d_name, d_namlen, filp->f_pos, + le32_to_cpu(d->inumber), DT_UNKNOWN)) + goto out; +skip_one: + if (!do_index) + dtoffset->index++; + } + + /* + * get next leaf page + */ + + if (p->header.flag & BT_ROOT) { + filp->f_pos = DIREND; + break; + } + + bn = le64_to_cpu(p->header.next); + if (bn == 0) { + filp->f_pos = DIREND; + break; + } + + /* unpin previous leaf page */ + DT_PUTPAGE(mp); + + /* get next leaf page */ + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) { + kfree(d_name); + return -rc; + } + + /* update offset (pn:index) for new page */ + index = 0; + if (!do_index) { + dtoffset->pn++; + dtoffset->index = 0; + } + + } + + out: + kfree(d_name); + DT_PUTPAGE(mp); + + return rc; +} + + +/* + * dtReadFirst() + * + * function: get the leftmost page of the directory + */ +static int dtReadFirst(struct inode *ip, btstack_t * btstack) +{ + int rc = 0; + s64 bn; + int psize = 288; /* initial in-line directory */ + metapage_t *mp; + dtpage_t *p; + s8 *stbl; + btframe_t *btsp; + pxd_t *xd; + + BT_CLR(btstack); /* reset stack */ + + /* + * descend leftmost path of the tree + * + * by convention, root bn = 0. + */ + for (bn = 0;;) { + DT_GETPAGE(ip, bn, mp, psize, p, rc); + if (rc) + return rc; + + /* + * leftmost leaf page + */ + if (p->header.flag & BT_LEAF) { + /* return leftmost entry */ + btsp = btstack->top; + btsp->bn = bn; + btsp->index = 0; + btsp->mp = mp; + + return 0; + } + + /* + * descend down to leftmost child page + */ + /* push (bn, index) of the parent page/entry */ + BT_PUSH(btstack, bn, 0); + + /* get the leftmost entry */ + stbl = DT_GETSTBL(p); + xd = (pxd_t *) & p->slot[stbl[0]]; + + /* get the child page block address */ + bn = addressPXD(xd); + psize = lengthPXD(xd) << JFS_SBI(ip->i_sb)->l2bsize; + + /* unpin the parent page */ + DT_PUTPAGE(mp); + } +} + + +/* + * dtReadNext() + * + * function: get the page of the specified offset (pn:index) + * + * return: if (offset > eof), bn = -1; + * + * note: if index > nextindex of the target leaf page, + * start with 1st entry of next leaf page; + */ +static int dtReadNext(struct inode *ip, loff_t * offset, btstack_t * btstack) +{ + int rc = 0; + struct dtoffset { + s16 pn; + s16 index; + s32 unused; + } *dtoffset = (struct dtoffset *) offset; + s64 bn; + metapage_t *mp; + dtpage_t *p; + int index; + int pn; + s8 *stbl; + btframe_t *btsp, *parent; + pxd_t *xd; + + /* + * get leftmost leaf page pinned + */ + if ((rc = dtReadFirst(ip, btstack))) + return rc; + + /* get leaf page */ + DT_GETSEARCH(ip, btstack->top, bn, mp, p, index); + + /* get the start offset (pn:index) */ + pn = dtoffset->pn - 1; /* Now pn = 0 represents leftmost leaf */ + index = dtoffset->index; + + /* start at leftmost page ? */ + if (pn == 0) { + /* offset beyond eof ? */ + if (index < p->header.nextindex) + goto out; + + if (p->header.flag & BT_ROOT) { + bn = -1; + goto out; + } + + /* start with 1st entry of next leaf page */ + dtoffset->pn++; + dtoffset->index = index = 0; + goto a; + } + + /* start at non-leftmost page: scan parent pages for large pn */ + if (p->header.flag & BT_ROOT) { + bn = -1; + goto out; + } + + /* start after next leaf page ? */ + if (pn > 1) + goto b; + + /* get leaf page pn = 1 */ + a: + bn = le64_to_cpu(p->header.next); + + /* unpin leaf page */ + DT_PUTPAGE(mp); + + /* offset beyond eof ? */ + if (bn == 0) { + bn = -1; + goto out; + } + + goto c; + + /* + * scan last internal page level to get target leaf page + */ + b: + /* unpin leftmost leaf page */ + DT_PUTPAGE(mp); + + /* get left most parent page */ + btsp = btstack->top; + parent = btsp - 1; + bn = parent->bn; + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* scan parent pages at last internal page level */ + while (pn >= p->header.nextindex) { + pn -= p->header.nextindex; + + /* get next parent page address */ + bn = le64_to_cpu(p->header.next); + + /* unpin current parent page */ + DT_PUTPAGE(mp); + + /* offset beyond eof ? */ + if (bn == 0) { + bn = -1; + goto out; + } + + /* get next parent page */ + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* update parent page stack frame */ + parent->bn = bn; + } + + /* get leaf page address */ + stbl = DT_GETSTBL(p); + xd = (pxd_t *) & p->slot[stbl[pn]]; + bn = addressPXD(xd); + + /* unpin parent page */ + DT_PUTPAGE(mp); + + /* + * get target leaf page + */ + c: + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* + * leaf page has been completed: + * start with 1st entry of next leaf page + */ + if (index >= p->header.nextindex) { + bn = le64_to_cpu(p->header.next); + + /* unpin leaf page */ + DT_PUTPAGE(mp); + + /* offset beyond eof ? */ + if (bn == 0) { + bn = -1; + goto out; + } + + /* get next leaf page */ + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* start with 1st entry of next leaf page */ + dtoffset->pn++; + dtoffset->index = 0; + } + + out: + /* return target leaf page pinned */ + btsp = btstack->top; + btsp->bn = bn; + btsp->index = dtoffset->index; + btsp->mp = mp; + + return 0; +} + + +/* + * dtCompare() + * + * function: compare search key with an internal entry + * + * return: + * < 0 if k is < record + * = 0 if k is = record + * > 0 if k is > record + */ +static int dtCompare(component_t * key, /* search key */ + dtpage_t * p, /* directory page */ + int si) +{ /* entry slot index */ + wchar_t *kname, *name; + int klen, namlen, len, rc; + idtentry_t *ih; + dtslot_t *t; + + /* + * force the left-most key on internal pages, at any level of + * the tree, to be less than any search key. + * this obviates having to update the leftmost key on an internal + * page when the user inserts a new key in the tree smaller than + * anything that has been stored. + * + * (? if/when dtSearch() narrows down to 1st entry (index = 0), + * at any internal page at any level of the tree, + * it descends to child of the entry anyway - + * ? make the entry as min size dummy entry) + * + * if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & BT_LEAF)) + * return (1); + */ + + kname = key->name; + klen = key->namlen; + + ih = (idtentry_t *) & p->slot[si]; + si = ih->next; + name = ih->name; + namlen = ih->namlen; + len = min(namlen, DTIHDRDATALEN); + + /* compare with head/only segment */ + len = min(klen, len); + if ((rc = UniStrncmp_le(kname, name, len))) + return rc; + + klen -= len; + namlen -= len; + + /* compare with additional segment(s) */ + kname += len; + while (klen > 0 && namlen > 0) { + /* compare with next name segment */ + t = (dtslot_t *) & p->slot[si]; + len = min(namlen, DTSLOTDATALEN); + len = min(klen, len); + name = t->name; + if ((rc = UniStrncmp_le(kname, name, len))) + return rc; + + klen -= len; + namlen -= len; + kname += len; + si = t->next; + } + + return (klen - namlen); +} + + + + +/* + * ciCompare() + * + * function: compare search key with an (leaf/internal) entry + * + * return: + * < 0 if k is < record + * = 0 if k is = record + * > 0 if k is > record + */ +static int ciCompare(component_t * key, /* search key */ + dtpage_t * p, /* directory page */ + int si, /* entry slot index */ + int flag) +{ + wchar_t *kname, *name, x; + int klen, namlen, len, rc; + ldtentry_t *lh; + idtentry_t *ih; + dtslot_t *t; + int i; + + /* + * force the left-most key on internal pages, at any level of + * the tree, to be less than any search key. + * this obviates having to update the leftmost key on an internal + * page when the user inserts a new key in the tree smaller than + * anything that has been stored. + * + * (? if/when dtSearch() narrows down to 1st entry (index = 0), + * at any internal page at any level of the tree, + * it descends to child of the entry anyway - + * ? make the entry as min size dummy entry) + * + * if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & BT_LEAF)) + * return (1); + */ + + kname = key->name; + klen = key->namlen; + + /* + * leaf page entry + */ + if (p->header.flag & BT_LEAF) { + lh = (ldtentry_t *) & p->slot[si]; + si = lh->next; + name = lh->name; + namlen = lh->namlen; + if (flag & JFS_DIR_INDEX) + len = min(namlen, DTLHDRDATALEN); + else + len = min(namlen, DTLHDRDATALEN_LEGACY); + } + /* + * internal page entry + */ + else { + ih = (idtentry_t *) & p->slot[si]; + si = ih->next; + name = ih->name; + namlen = ih->namlen; + len = min(namlen, DTIHDRDATALEN); + } + + /* compare with head/only segment */ + len = min(klen, len); + for (i = 0; i < len; i++, kname++, name++) { + /* only uppercase if case-insensitive support is on */ + if ((flag & JFS_OS2) == JFS_OS2) + x = UniToupper(le16_to_cpu(*name)); + else + x = le16_to_cpu(*name); + if ((rc = *kname - x)) + return rc; + } + + klen -= len; + namlen -= len; + + /* compare with additional segment(s) */ + while (klen > 0 && namlen > 0) { + /* compare with next name segment */ + t = (dtslot_t *) & p->slot[si]; + len = min(namlen, DTSLOTDATALEN); + len = min(klen, len); + name = t->name; + for (i = 0; i < len; i++, kname++, name++) { + /* only uppercase if case-insensitive support is on */ + if ((flag & JFS_OS2) == JFS_OS2) + x = UniToupper(le16_to_cpu(*name)); + else + x = le16_to_cpu(*name); + + if ((rc = *kname - x)) + return rc; + } + + klen -= len; + namlen -= len; + si = t->next; + } + + return (klen - namlen); +} + + +/* + * ciGetLeafPrefixKey() + * + * function: compute prefix of suffix compression + * from two adjacent leaf entries + * across page boundary + * + * return: + * Number of prefix bytes needed to distinguish b from a. + */ +static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp, + int ri, component_t * key, int flag) +{ + int klen, namlen; + wchar_t *pl, *pr, *kname; + wchar_t lname[JFS_NAME_MAX + 1]; + component_t lkey = { 0, lname }; + wchar_t rname[JFS_NAME_MAX + 1]; + component_t rkey = { 0, rname }; + + /* get left and right key */ + dtGetKey(lp, li, &lkey, flag); + lkey.name[lkey.namlen] = 0; + + if ((flag & JFS_OS2) == JFS_OS2) + ciToUpper(&lkey); + + dtGetKey(rp, ri, &rkey, flag); + rkey.name[rkey.namlen] = 0; + + + if ((flag & JFS_OS2) == JFS_OS2) + ciToUpper(&rkey); + + /* compute prefix */ + klen = 0; + kname = key->name; + namlen = min(lkey.namlen, rkey.namlen); + for (pl = lkey.name, pr = rkey.name; + namlen; pl++, pr++, namlen--, klen++, kname++) { + *kname = *pr; + if (*pl != *pr) { + key->namlen = klen + 1; + return; + } + } + + /* l->namlen <= r->namlen since l <= r */ + if (lkey.namlen < rkey.namlen) { + *kname = *pr; + key->namlen = klen + 1; + } else /* l->namelen == r->namelen */ + key->namlen = klen; + + return; +} + + + +/* + * dtGetKey() + * + * function: get key of the entry + */ +static void dtGetKey(dtpage_t * p, int i, /* entry index */ + component_t * key, int flag) +{ + int si; + s8 *stbl; + ldtentry_t *lh; + idtentry_t *ih; + dtslot_t *t; + int namlen, len; + wchar_t *name, *kname; + + /* get entry */ + stbl = DT_GETSTBL(p); + si = stbl[i]; + if (p->header.flag & BT_LEAF) { + lh = (ldtentry_t *) & p->slot[si]; + si = lh->next; + namlen = lh->namlen; + name = lh->name; + if (flag & JFS_DIR_INDEX) + len = min(namlen, DTLHDRDATALEN); + else + len = min(namlen, DTLHDRDATALEN_LEGACY); + } else { + ih = (idtentry_t *) & p->slot[si]; + si = ih->next; + namlen = ih->namlen; + name = ih->name; + len = min(namlen, DTIHDRDATALEN); + } + + key->namlen = namlen; + kname = key->name; + + /* + * move head/only segment + */ + UniStrncpy_le(kname, name, len); + + /* + * move additional segment(s) + */ + while (si >= 0) { + /* get next segment */ + t = &p->slot[si]; + kname += len; + namlen -= len; + len = min(namlen, DTSLOTDATALEN); + UniStrncpy_le(kname, t->name, len); + + si = t->next; + } +} + + +/* + * dtInsertEntry() + * + * function: allocate free slot(s) and + * write a leaf/internal entry + * + * return: entry slot index + */ +static void dtInsertEntry(dtpage_t * p, int index, component_t * key, + ddata_t * data, dtlock_t ** dtlock) +{ + dtslot_t *h, *t; + ldtentry_t *lh = 0; + idtentry_t *ih = 0; + int hsi, fsi, klen, len, nextindex; + wchar_t *kname, *name; + s8 *stbl; + pxd_t *xd; + dtlock_t *dtlck = *dtlock; + lv_t *lv; + int xsi, n; + s64 bn = 0; + metapage_t *mp = 0; + + klen = key->namlen; + kname = key->name; + + /* allocate a free slot */ + hsi = fsi = p->header.freelist; + h = &p->slot[fsi]; + p->header.freelist = h->next; + --p->header.freecnt; + + /* open new linelock */ + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + + lv = (lv_t *) & dtlck->lv[dtlck->index]; + lv->offset = hsi; + + /* write head/only segment */ + if (p->header.flag & BT_LEAF) { + lh = (ldtentry_t *) h; + lh->next = h->next; + lh->inumber = data->leaf.ino; /* little-endian */ + lh->namlen = klen; + name = lh->name; + if (data->leaf.ip) { + len = min(klen, DTLHDRDATALEN); + if (!(p->header.flag & BT_ROOT)) + bn = addressPXD(&p->header.self); + lh->index = cpu_to_le32(add_index(data->leaf.tid, + data->leaf.ip, + bn, index)); + } else + len = min(klen, DTLHDRDATALEN_LEGACY); + } else { + ih = (idtentry_t *) h; + ih->next = h->next; + xd = (pxd_t *) ih; + *xd = data->xd; + ih->namlen = klen; + name = ih->name; + len = min(klen, DTIHDRDATALEN); + } + + UniStrncpy_le(name, kname, len); + + n = 1; + xsi = hsi; + + /* write additional segment(s) */ + t = h; + klen -= len; + while (klen) { + /* get free slot */ + fsi = p->header.freelist; + t = &p->slot[fsi]; + p->header.freelist = t->next; + --p->header.freecnt; + + /* is next slot contiguous ? */ + if (fsi != xsi + 1) { + /* close current linelock */ + lv->length = n; + dtlck->index++; + + /* open new linelock */ + if (dtlck->index < dtlck->maxcnt) + lv++; + else { + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[0]; + } + + lv->offset = fsi; + n = 0; + } + + kname += len; + len = min(klen, DTSLOTDATALEN); + UniStrncpy_le(t->name, kname, len); + + n++; + xsi = fsi; + klen -= len; + } + + /* close current linelock */ + lv->length = n; + dtlck->index++; + + *dtlock = dtlck; + + /* terminate last/only segment */ + if (h == t) { + /* single segment entry */ + if (p->header.flag & BT_LEAF) + lh->next = -1; + else + ih->next = -1; + } else + /* multi-segment entry */ + t->next = -1; + + /* if insert into middle, shift right succeeding entries in stbl */ + stbl = DT_GETSTBL(p); + nextindex = p->header.nextindex; + if (index < nextindex) { + memmove(stbl + index + 1, stbl + index, nextindex - index); + + if ((p->header.flag & BT_LEAF) && data->leaf.ip) { + /* + * Need to update slot number for entries that moved + * in the stbl + */ + mp = 0; + for (n = index + 1; n <= nextindex; n++) { + lh = (ldtentry_t *) & (p->slot[stbl[n]]); + modify_index(data->leaf.tid, data->leaf.ip, + le32_to_cpu(lh->index), bn, n, + &mp); + } + if (mp) + release_metapage(mp); + } + } + + stbl[index] = hsi; + + /* advance next available entry index of stbl */ + ++p->header.nextindex; +} + + +/* + * dtMoveEntry() + * + * function: move entries from split/left page to new/right page + * + * nextindex of dst page and freelist/freecnt of both pages + * are updated. + */ +static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp, + dtlock_t ** sdtlock, dtlock_t ** ddtlock, + int do_index) +{ + int ssi, next; /* src slot index */ + int di; /* dst entry index */ + int dsi; /* dst slot index */ + s8 *sstbl, *dstbl; /* sorted entry table */ + int snamlen, len; + ldtentry_t *slh, *dlh = 0; + idtentry_t *sih, *dih = 0; + dtslot_t *h, *s, *d; + dtlock_t *sdtlck = *sdtlock, *ddtlck = *ddtlock; + lv_t *slv, *dlv; + int xssi, ns, nd; + int sfsi; + + sstbl = (s8 *) & sp->slot[sp->header.stblindex]; + dstbl = (s8 *) & dp->slot[dp->header.stblindex]; + + dsi = dp->header.freelist; /* first (whole page) free slot */ + sfsi = sp->header.freelist; + + /* linelock destination entry slot */ + dlv = (lv_t *) & ddtlck->lv[ddtlck->index]; + dlv->offset = dsi; + + /* linelock source entry slot */ + slv = (lv_t *) & sdtlck->lv[sdtlck->index]; + slv->offset = sstbl[si]; + xssi = slv->offset - 1; + + /* + * move entries + */ + ns = nd = 0; + for (di = 0; si < sp->header.nextindex; si++, di++) { + ssi = sstbl[si]; + dstbl[di] = dsi; + + /* is next slot contiguous ? */ + if (ssi != xssi + 1) { + /* close current linelock */ + slv->length = ns; + sdtlck->index++; + + /* open new linelock */ + if (sdtlck->index < sdtlck->maxcnt) + slv++; + else { + sdtlck = (dtlock_t *) txLinelock(sdtlck); + slv = (lv_t *) & sdtlck->lv[0]; + } + + slv->offset = ssi; + ns = 0; + } + + /* + * move head/only segment of an entry + */ + /* get dst slot */ + h = d = &dp->slot[dsi]; + + /* get src slot and move */ + s = &sp->slot[ssi]; + if (sp->header.flag & BT_LEAF) { + /* get source entry */ + slh = (ldtentry_t *) s; + dlh = (ldtentry_t *) h; + snamlen = slh->namlen; + + if (do_index) { + len = min(snamlen, DTLHDRDATALEN); + dlh->index = slh->index; /* little-endian */ + } else + len = min(snamlen, DTLHDRDATALEN_LEGACY); + + memcpy(dlh, slh, 6 + len * 2); + + next = slh->next; + + /* update dst head/only segment next field */ + dsi++; + dlh->next = dsi; + } else { + sih = (idtentry_t *) s; + snamlen = sih->namlen; + + len = min(snamlen, DTIHDRDATALEN); + dih = (idtentry_t *) h; + memcpy(dih, sih, 10 + len * 2); + next = sih->next; + + dsi++; + dih->next = dsi; + } + + /* free src head/only segment */ + s->next = sfsi; + s->cnt = 1; + sfsi = ssi; + + ns++; + nd++; + xssi = ssi; + + /* + * move additional segment(s) of the entry + */ + snamlen -= len; + while ((ssi = next) >= 0) { + /* is next slot contiguous ? */ + if (ssi != xssi + 1) { + /* close current linelock */ + slv->length = ns; + sdtlck->index++; + + /* open new linelock */ + if (sdtlck->index < sdtlck->maxcnt) + slv++; + else { + sdtlck = + (dtlock_t *) + txLinelock(sdtlck); + slv = (lv_t *) & sdtlck->lv[0]; + } + + slv->offset = ssi; + ns = 0; + } + + /* get next source segment */ + s = &sp->slot[ssi]; + + /* get next destination free slot */ + d++; + + len = min(snamlen, DTSLOTDATALEN); + UniStrncpy(d->name, s->name, len); + + ns++; + nd++; + xssi = ssi; + + dsi++; + d->next = dsi; + + /* free source segment */ + next = s->next; + s->next = sfsi; + s->cnt = 1; + sfsi = ssi; + + snamlen -= len; + } /* end while */ + + /* terminate dst last/only segment */ + if (h == d) { + /* single segment entry */ + if (dp->header.flag & BT_LEAF) + dlh->next = -1; + else + dih->next = -1; + } else + /* multi-segment entry */ + d->next = -1; + } /* end for */ + + /* close current linelock */ + slv->length = ns; + sdtlck->index++; + *sdtlock = sdtlck; + + dlv->length = nd; + ddtlck->index++; + *ddtlock = ddtlck; + + /* update source header */ + sp->header.freelist = sfsi; + sp->header.freecnt += nd; + + /* update destination header */ + dp->header.nextindex = di; + + dp->header.freelist = dsi; + dp->header.freecnt -= nd; +} + + +/* + * dtDeleteEntry() + * + * function: free a (leaf/internal) entry + * + * log freelist header, stbl, and each segment slot of entry + * (even though last/only segment next field is modified, + * physical image logging requires all segment slots of + * the entry logged to avoid applying previous updates + * to the same slots) + */ +static void dtDeleteEntry(dtpage_t * p, int fi, dtlock_t ** dtlock) +{ + int fsi; /* free entry slot index */ + s8 *stbl; + dtslot_t *t; + int si, freecnt; + dtlock_t *dtlck = *dtlock; + lv_t *lv; + int xsi, n; + + /* get free entry slot index */ + stbl = DT_GETSTBL(p); + fsi = stbl[fi]; + + /* open new linelock */ + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + + lv->offset = fsi; + + /* get the head/only segment */ + t = &p->slot[fsi]; + if (p->header.flag & BT_LEAF) + si = ((ldtentry_t *) t)->next; + else + si = ((idtentry_t *) t)->next; + t->next = si; + t->cnt = 1; + + n = freecnt = 1; + xsi = fsi; + + /* find the last/only segment */ + while (si >= 0) { + /* is next slot contiguous ? */ + if (si != xsi + 1) { + /* close current linelock */ + lv->length = n; + dtlck->index++; + + /* open new linelock */ + if (dtlck->index < dtlck->maxcnt) + lv++; + else { + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[0]; + } + + lv->offset = si; + n = 0; + } + + n++; + xsi = si; + freecnt++; + + t = &p->slot[si]; + t->cnt = 1; + si = t->next; + } + + /* close current linelock */ + lv->length = n; + dtlck->index++; + + *dtlock = dtlck; + + /* update freelist */ + t->next = p->header.freelist; + p->header.freelist = fsi; + p->header.freecnt += freecnt; + + /* if delete from middle, + * shift left the succedding entries in the stbl + */ + si = p->header.nextindex; + if (fi < si - 1) + memmove(&stbl[fi], &stbl[fi + 1], si - fi - 1); + + p->header.nextindex--; +} + + +/* + * dtTruncateEntry() + * + * function: truncate a (leaf/internal) entry + * + * log freelist header, stbl, and each segment slot of entry + * (even though last/only segment next field is modified, + * physical image logging requires all segment slots of + * the entry logged to avoid applying previous updates + * to the same slots) + */ +static void dtTruncateEntry(dtpage_t * p, int ti, dtlock_t ** dtlock) +{ + int tsi; /* truncate entry slot index */ + s8 *stbl; + dtslot_t *t; + int si, freecnt; + dtlock_t *dtlck = *dtlock; + lv_t *lv; + int fsi, xsi, n; + + /* get free entry slot index */ + stbl = DT_GETSTBL(p); + tsi = stbl[ti]; + + /* open new linelock */ + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + + lv->offset = tsi; + + /* get the head/only segment */ + t = &p->slot[tsi]; + ASSERT(p->header.flag & BT_INTERNAL); + ((idtentry_t *) t)->namlen = 0; + si = ((idtentry_t *) t)->next; + ((idtentry_t *) t)->next = -1; + + n = 1; + freecnt = 0; + fsi = si; + xsi = tsi; + + /* find the last/only segment */ + while (si >= 0) { + /* is next slot contiguous ? */ + if (si != xsi + 1) { + /* close current linelock */ + lv->length = n; + dtlck->index++; + + /* open new linelock */ + if (dtlck->index < dtlck->maxcnt) + lv++; + else { + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[0]; + } + + lv->offset = si; + n = 0; + } + + n++; + xsi = si; + freecnt++; + + t = &p->slot[si]; + t->cnt = 1; + si = t->next; + } + + /* close current linelock */ + lv->length = n; + dtlck->index++; + + *dtlock = dtlck; + + /* update freelist */ + if (freecnt == 0) + return; + t->next = p->header.freelist; + p->header.freelist = fsi; + p->header.freecnt += freecnt; +} + + +/* + * dtLinelockFreelist() + */ +static void dtLinelockFreelist(dtpage_t * p, /* directory page */ + int m, /* max slot index */ + dtlock_t ** dtlock) +{ + int fsi; /* free entry slot index */ + dtslot_t *t; + int si; + dtlock_t *dtlck = *dtlock; + lv_t *lv; + int xsi, n; + + /* get free entry slot index */ + fsi = p->header.freelist; + + /* open new linelock */ + if (dtlck->index >= dtlck->maxcnt) + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[dtlck->index]; + + lv->offset = fsi; + + n = 1; + xsi = fsi; + + t = &p->slot[fsi]; + si = t->next; + + /* find the last/only segment */ + while (si < m && si >= 0) { + /* is next slot contiguous ? */ + if (si != xsi + 1) { + /* close current linelock */ + lv->length = n; + dtlck->index++; + + /* open new linelock */ + if (dtlck->index < dtlck->maxcnt) + lv++; + else { + dtlck = (dtlock_t *) txLinelock(dtlck); + lv = (lv_t *) & dtlck->lv[0]; + } + + lv->offset = si; + n = 0; + } + + n++; + xsi = si; + + t = &p->slot[si]; + si = t->next; + } + + /* close current linelock */ + lv->length = n; + dtlck->index++; + + *dtlock = dtlck; +} + + +/* + * NAME: dtModify + * + * FUNCTION: Modify the inode number part of a directory entry + * + * PARAMETERS: + * tid - Transaction id + * ip - Inode of parent directory + * key - Name of entry to be modified + * orig_ino - Original inode number expected in entry + * new_ino - New inode number to put into entry + * flag - JFS_RENAME + * + * RETURNS: + * ESTALE - If entry found does not match orig_ino passed in + * ENOENT - If no entry can be found to match key + * 0 - If successfully modified entry + */ +int dtModify(tid_t tid, struct inode *ip, + component_t * key, ino_t * orig_ino, ino_t new_ino, int flag) +{ + int rc; + s64 bn; + metapage_t *mp; + dtpage_t *p; + int index; + btstack_t btstack; + tlock_t *tlck; + dtlock_t *dtlck; + lv_t *lv; + s8 *stbl; + int entry_si; /* entry slot index */ + ldtentry_t *entry; + + /* + * search for the entry to modify: + * + * dtSearch() returns (leaf page pinned, index at which to modify). + */ + if ((rc = dtSearch(ip, key, orig_ino, &btstack, flag))) + return rc; + + /* retrieve search result */ + DT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the leaf page of named entry + */ + tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY); + dtlck = (dtlock_t *) & tlck->lock; + + /* get slot index of the entry */ + stbl = DT_GETSTBL(p); + entry_si = stbl[index]; + + /* linelock entry */ + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + lv->offset = entry_si; + lv->length = 1; + dtlck->index++; + + /* get the head/only segment */ + entry = (ldtentry_t *) & p->slot[entry_si]; + + /* substitute the inode number of the entry */ + entry->inumber = cpu_to_le32(new_ino); + + /* unpin the leaf page */ + DT_PUTPAGE(mp); + + return 0; +} + +#ifdef _JFS_DEBUG_DTREE +/* + * dtDisplayTree() + * + * function: traverse forward + */ +int dtDisplayTree(struct inode *ip) +{ + int rc; + metapage_t *mp; + dtpage_t *p; + s64 bn, pbn; + int index, lastindex, v, h; + pxd_t *xd; + btstack_t btstack; + btframe_t *btsp; + btframe_t *parent; + u8 *stbl; + int psize = 256; + + printk("display B+-tree.\n"); + + /* clear stack */ + btsp = btstack.stack; + + /* + * start with root + * + * root resides in the inode + */ + bn = 0; + v = h = 0; + + /* + * first access of each page: + */ + newPage: + DT_GETPAGE(ip, bn, mp, psize, p, rc); + if (rc) + return rc; + + /* process entries forward from first index */ + index = 0; + lastindex = p->header.nextindex - 1; + + if (p->header.flag & BT_INTERNAL) { + /* + * first access of each internal page + */ + printf("internal page "); + dtDisplayPage(ip, bn, p); + + goto getChild; + } else { /* (p->header.flag & BT_LEAF) */ + + /* + * first access of each leaf page + */ + printf("leaf page "); + dtDisplayPage(ip, bn, p); + + /* + * process leaf page entries + * + for ( ; index <= lastindex; index++) + { + } + */ + + /* unpin the leaf page */ + DT_PUTPAGE(mp); + } + + /* + * go back up to the parent page + */ + getParent: + /* pop/restore parent entry for the current child page */ + if ((parent = (btsp == btstack.stack ? NULL : --btsp)) == NULL) + /* current page must have been root */ + return; + + /* + * parent page scan completed + */ + if ((index = parent->index) == (lastindex = parent->lastindex)) { + /* go back up to the parent page */ + goto getParent; + } + + /* + * parent page has entries remaining + */ + /* get back the parent page */ + bn = parent->bn; + /* v = parent->level; */ + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* get next parent entry */ + index++; + + /* + * internal page: go down to child page of current entry + */ + getChild: + /* push/save current parent entry for the child page */ + btsp->bn = pbn = bn; + btsp->index = index; + btsp->lastindex = lastindex; + /* btsp->level = v; */ + /* btsp->node = h; */ + ++btsp; + + /* get current entry for the child page */ + stbl = DT_GETSTBL(p); + xd = (pxd_t *) & p->slot[stbl[index]]; + + /* + * first access of each internal entry: + */ + + /* get child page */ + bn = addressPXD(xd); + psize = lengthPXD(xd) << ip->i_ipmnt->i_l2bsize; + + printk("traverse down 0x%Lx[%d]->0x%Lx\n", pbn, index, bn); + v++; + h = index; + + /* release parent page */ + DT_PUTPAGE(mp); + + /* process the child page */ + goto newPage; +} + + +/* + * dtDisplayPage() + * + * function: display page + */ +int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p) +{ + int rc; + metapage_t *mp; + ldtentry_t *lh; + idtentry_t *ih; + pxd_t *xd; + int i, j; + u8 *stbl; + wchar_t name[JFS_NAME_MAX + 1]; + component_t key = { 0, name }; + int freepage = 0; + + if (p == NULL) { + freepage = 1; + DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + } + + /* display page control */ + printk("bn:0x%Lx flag:0x%08x nextindex:%d\n", + bn, p->header.flag, p->header.nextindex); + + /* display entries */ + stbl = DT_GETSTBL(p); + for (i = 0, j = 1; i < p->header.nextindex; i++, j++) { + dtGetKey(p, i, &key, JFS_SBI(ip->i_sb)->mntflag); + key.name[key.namlen] = '\0'; + if (p->header.flag & BT_LEAF) { + lh = (ldtentry_t *) & p->slot[stbl[i]]; + printf("\t[%d] %s:%d", i, key.name, + le32_to_cpu(lh->inumber)); + } else { + ih = (idtentry_t *) & p->slot[stbl[i]]; + xd = (pxd_t *) ih; + bn = addressPXD(xd); + printf("\t[%d] %s:0x%Lx", i, key.name, bn); + } + + if (j == 4) { + printf("\n"); + j = 0; + } + } + + printf("\n"); + + if (freepage) + DT_PUTPAGE(mp); + + return 0; +} +#endif /* _JFS_DEBUG_DTREE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_dtree.h linux.20pre2-ac1/fs/jfs/jfs_dtree.h --- linux.20pre2/fs/jfs/jfs_dtree.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_dtree.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,282 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 _H_JFS_DTREE +#define _H_JFS_DTREE + +/* + * jfs_dtree.h: directory B+-tree manager + */ + +#include "jfs_btree.h" + +typedef union { + struct { + tid_t tid; + struct inode *ip; + u32 ino; + } leaf; + pxd_t xd; +} ddata_t; + + +/* + * entry segment/slot + * + * an entry consists of type dependent head/only segment/slot and + * additional segments/slots linked vi next field; + * N.B. last/only segment of entry is terminated by next = -1; + */ +/* + * directory page slot + */ +typedef struct { + s8 next; /* 1: */ + s8 cnt; /* 1: */ + wchar_t name[15]; /* 30: */ +} dtslot_t; /* (32) */ + + +#define DATASLOTSIZE 16 +#define L2DATASLOTSIZE 4 +#define DTSLOTSIZE 32 +#define L2DTSLOTSIZE 5 +#define DTSLOTHDRSIZE 2 +#define DTSLOTDATASIZE 30 +#define DTSLOTDATALEN 15 + +/* + * internal node entry head/only segment + */ +typedef struct { + pxd_t xd; /* 8: child extent descriptor */ + + s8 next; /* 1: */ + u8 namlen; /* 1: */ + wchar_t name[11]; /* 22: 2-byte aligned */ +} idtentry_t; /* (32) */ + +#define DTIHDRSIZE 10 +#define DTIHDRDATALEN 11 + +/* compute number of slots for entry */ +#define NDTINTERNAL(klen) ( ((4 + (klen)) + (15 - 1)) / 15 ) + + +/* + * leaf node entry head/only segment + * + * For legacy filesystems, name contains 13 wchars -- no index field + */ +typedef struct { + u32 inumber; /* 4: 4-byte aligned */ + s8 next; /* 1: */ + u8 namlen; /* 1: */ + wchar_t name[11]; /* 22: 2-byte aligned */ + u32 index; /* 4: index into dir_table */ +} ldtentry_t; /* (32) */ + +#define DTLHDRSIZE 6 +#define DTLHDRDATALEN_LEGACY 13 /* Old (OS/2) format */ +#define DTLHDRDATALEN 11 + +/* + * dir_table used for directory traversal during readdir + */ + +/* + * Keep persistent index for directory entries + */ +#define DO_INDEX(INODE) (JFS_SBI((INODE)->i_sb)->mntflag & JFS_DIR_INDEX) + +/* + * Maximum entry in inline directory table + */ +#define MAX_INLINE_DIRTABLE_ENTRY 13 + +typedef struct dir_table_slot { + u8 rsrvd; /* 1: */ + u8 flag; /* 1: 0 if free */ + u8 slot; /* 1: slot within leaf page of entry */ + u8 addr1; /* 1: upper 8 bits of leaf page address */ + u32 addr2; /* 4: lower 32 bits of leaf page address -OR- + index of next entry when this entry was deleted */ +} dir_table_slot_t; /* (8) */ + +/* + * flag values + */ +#define DIR_INDEX_VALID 1 +#define DIR_INDEX_FREE 0 + +#define DTSaddress(dir_table_slot, address64)\ +{\ + (dir_table_slot)->addr1 = ((u64)address64) >> 32;\ + (dir_table_slot)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\ +} + +#define addressDTS(dts)\ + ( ((s64)((dts)->addr1)) << 32 | __le32_to_cpu((dts)->addr2) ) + +/* compute number of slots for entry */ +#define NDTLEAF_LEGACY(klen) ( ((2 + (klen)) + (15 - 1)) / 15 ) +#define NDTLEAF NDTINTERNAL + + +/* + * directory root page (in-line in on-disk inode): + * + * cf. dtpage_t below. + */ +typedef union { + struct { + dasd_t DASD; /* 16: DASD limit/usage info F226941 */ + + u8 flag; /* 1: */ + u8 nextindex; /* 1: next free entry in stbl */ + s8 freecnt; /* 1: free count */ + s8 freelist; /* 1: freelist header */ + + u32 idotdot; /* 4: parent inode number */ + + s8 stbl[8]; /* 8: sorted entry index table */ + } header; /* (32) */ + + dtslot_t slot[9]; +} dtroot_t; + +#define PARENT(IP) \ + (le32_to_cpu(JFS_IP(IP)->i_dtroot.header.idotdot)) + +#define DTROOTMAXSLOT 9 + +#define dtEmpty(IP) (JFS_IP(IP)->i_dtroot.header.nextindex == 0) + + +/* + * directory regular page: + * + * entry slot array of 32 byte slot + * + * sorted entry slot index table (stbl): + * contiguous slots at slot specified by stblindex, + * 1-byte per entry + * 512 byte block: 16 entry tbl (1 slot) + * 1024 byte block: 32 entry tbl (1 slot) + * 2048 byte block: 64 entry tbl (2 slot) + * 4096 byte block: 128 entry tbl (4 slot) + * + * data area: + * 512 byte block: 16 - 2 = 14 slot + * 1024 byte block: 32 - 2 = 30 slot + * 2048 byte block: 64 - 3 = 61 slot + * 4096 byte block: 128 - 5 = 123 slot + * + * N.B. index is 0-based; index fields refer to slot index + * except nextindex which refers to entry index in stbl; + * end of entry stot list or freelist is marked with -1. + */ +typedef union { + struct { + s64 next; /* 8: next sibling */ + s64 prev; /* 8: previous sibling */ + + u8 flag; /* 1: */ + u8 nextindex; /* 1: next entry index in stbl */ + s8 freecnt; /* 1: */ + s8 freelist; /* 1: slot index of head of freelist */ + + u8 maxslot; /* 1: number of slots in page slot[] */ + u8 stblindex; /* 1: slot index of start of stbl */ + u8 rsrvd[2]; /* 2: */ + + pxd_t self; /* 8: self pxd */ + } header; /* (32) */ + + dtslot_t slot[128]; +} dtpage_t; + +#define DTPAGEMAXSLOT 128 + +#define DT8THPGNODEBYTES 512 +#define DT8THPGNODETSLOTS 1 +#define DT8THPGNODESLOTS 16 + +#define DTQTRPGNODEBYTES 1024 +#define DTQTRPGNODETSLOTS 1 +#define DTQTRPGNODESLOTS 32 + +#define DTHALFPGNODEBYTES 2048 +#define DTHALFPGNODETSLOTS 2 +#define DTHALFPGNODESLOTS 64 + +#define DTFULLPGNODEBYTES 4096 +#define DTFULLPGNODETSLOTS 4 +#define DTFULLPGNODESLOTS 128 + +#define DTENTRYSTART 1 + +/* get sorted entry table of the page */ +#define DT_GETSTBL(p) ( ((p)->header.flag & BT_ROOT) ?\ + ((dtroot_t *)(p))->header.stbl : \ + (s8 *)&(p)->slot[(p)->header.stblindex] ) + +/* + * Flags for dtSearch + */ +#define JFS_CREATE 1 +#define JFS_LOOKUP 2 +#define JFS_REMOVE 3 +#define JFS_RENAME 4 + +#define DIRENTSIZ(namlen) \ + ( (sizeof(struct dirent) - 2*(JFS_NAME_MAX+1) + 2*((namlen)+1) + 3) &~ 3 ) + +/* + * Maximum file offset for directories. + */ +#define DIREND INT_MAX + +/* + * external declarations + */ +extern void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot); + +extern int dtSearch(struct inode *ip, component_t * key, + ino_t * data, btstack_t * btstack, int flag); + +extern int dtInsert(tid_t tid, struct inode *ip, + component_t * key, ino_t * ino, btstack_t * btstack); + +extern int dtDelete(tid_t tid, + struct inode *ip, component_t * key, ino_t * data, int flag); + +extern int dtRelocate(tid_t tid, + struct inode *ip, s64 lmxaddr, pxd_t * opxd, s64 nxaddr); + +extern int dtModify(tid_t tid, struct inode *ip, + component_t * key, ino_t * orig_ino, ino_t new_ino, int flag); + +extern int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir); + +#ifdef _JFS_DEBUG_DTREE +extern int dtDisplayTree(struct inode *ip); + +extern int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p); +#endif /* _JFS_DEBUG_DTREE */ + +#endif /* !_H_JFS_DTREE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_extendfs.h linux.20pre2-ac1/fs/jfs/jfs_extendfs.h --- linux.20pre2/fs/jfs/jfs_extendfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_extendfs.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,36 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2001 + * + * 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 _H_JFS_EXTENDFS +#define _H_JFS_EXTENDFS + +/* + * extendfs parameter list + */ +typedef struct { + u32 flag; /* 4: */ + u8 dev; /* 1: */ + u8 pad[3]; /* 3: */ + s64 LVSize; /* 8: LV size in LV block */ + s64 FSSize; /* 8: FS size in LV block */ + s32 LogSize; /* 4: inlinelog size in LV block */ +} extendfs_t; /* (28) */ + +/* plist flag */ +#define EXTENDFS_QUERY 0x00000001 + +#endif /* _H_JFS_EXTENDFS */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_extent.c linux.20pre2-ac1/fs/jfs/jfs_extent.c --- linux.20pre2/fs/jfs/jfs_extent.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_extent.c 2002-08-06 17:59:43.000000000 +0100 @@ -0,0 +1,633 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 "jfs_incore.h" +#include "jfs_dmap.h" +#include "jfs_extent.h" +#include "jfs_debug.h" + +/* + * forward references + */ +static int extBalloc(struct inode *, s64, s64 *, s64 *); +static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *); +int extRecord(struct inode *, xad_t *); +static s64 extRoundDown(s64 nb); + +/* + * external references + */ +extern int dbExtend(struct inode *, s64, s64, s64); +extern int jfs_commit_inode(struct inode *, int); + + +#define DPD(a) (printk("(a): %d\n",(a))) +#define DPC(a) (printk("(a): %c\n",(a))) +#define DPL1(a) \ +{ \ + if ((a) >> 32) \ + printk("(a): %x%08x ",(a)); \ + else \ + printk("(a): %x ",(a) << 32); \ +} +#define DPL(a) \ +{ \ + if ((a) >> 32) \ + printk("(a): %x%08x\n",(a)); \ + else \ + printk("(a): %x\n",(a) << 32); \ +} + +#define DPD1(a) (printk("(a): %d ",(a))) +#define DPX(a) (printk("(a): %08x\n",(a))) +#define DPX1(a) (printk("(a): %08x ",(a))) +#define DPS(a) (printk("%s\n",(a))) +#define DPE(a) (printk("\nENTERING: %s\n",(a))) +#define DPE1(a) (printk("\nENTERING: %s",(a))) +#define DPS1(a) (printk(" %s ",(a))) + + +/* + * NAME: extAlloc() + * + * FUNCTION: allocate an extent for a specified page range within a + * file. + * + * PARAMETERS: + * ip - the inode of the file. + * xlen - requested extent length. + * pno - the starting page number with the file. + * xp - pointer to an xad. on entry, xad describes an + * extent that is used as an allocation hint if the + * xaddr of the xad is non-zero. on successful exit, + * the xad describes the newly allocated extent. + * abnr - boolean_t indicating whether the newly allocated extent + * should be marked as allocated but not recorded. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + * ENOSPC - insufficient disk resources. + */ +int +extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) +{ + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + s64 nxlen, nxaddr, xoff, hint, xaddr = 0; + int rc, nbperpage; + int xflag; + + /* This blocks if we are low on resources */ + txBeginAnon(ip->i_sb); + + /* Avoid race with jfs_commit_inode() */ + down(&JFS_IP(ip)->commit_sem); + + /* validate extent length */ + if (xlen > MAXXLEN) + xlen = MAXXLEN; + + /* get the number of blocks per page */ + nbperpage = sbi->nbperpage; + + /* get the page's starting extent offset */ + xoff = pno << sbi->l2nbperpage; + + /* check if an allocation hint was provided */ + if ((hint = addressXAD(xp))) { + /* get the size of the extent described by the hint */ + nxlen = lengthXAD(xp); + + /* check if the hint is for the portion of the file + * immediately previous to the current allocation + * request and if hint extent has the same abnr + * value as the current request. if so, we can + * extend the hint extent to include the current + * extent if we can allocate the blocks immediately + * following the hint extent. + */ + if (offsetXAD(xp) + nxlen == xoff && + abnr == ((xp->flag & XAD_NOTRECORDED) ? TRUE : FALSE)) + xaddr = hint + nxlen; + + /* adjust the hint to the last block of the extent */ + hint += (nxlen - 1); + } + + /* allocate the disk blocks for the extent. initially, extBalloc() + * will try to allocate disk blocks for the requested size (xlen). + * if this fails (xlen contigious free blocks not avaliable), it'll + * try to allocate a smaller number of blocks (producing a smaller + * extent), with this smaller number of blocks consisting of the + * requested number of blocks rounded down to the next smaller + * power of 2 number (i.e. 16 -> 8). it'll continue to round down + * and retry the allocation until the number of blocks to allocate + * is smaller than the number of blocks per page. + */ + nxlen = xlen; + if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) { + up(&JFS_IP(ip)->commit_sem); + return (rc); + } + + /* determine the value of the extent flag */ + xflag = (abnr == TRUE) ? XAD_NOTRECORDED : 0; + + /* if we can extend the hint extent to cover the current request, + * extend it. otherwise, insert a new extent to + * cover the current request. + */ + if (xaddr && xaddr == nxaddr) + rc = xtExtend(0, ip, xoff, (int) nxlen, 0); + else + rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0); + + /* if the extend or insert failed, + * free the newly allocated blocks and return the error. + */ + if (rc) { + dbFree(ip, nxaddr, nxlen); + up(&JFS_IP(ip)->commit_sem); + return (rc); + } + + /* update the number of blocks allocated to the file */ + ip->i_blocks += LBLK2PBLK(ip->i_sb, nxlen); + + /* set the results of the extent allocation */ + XADaddress(xp, nxaddr); + XADlength(xp, nxlen); + XADoffset(xp, xoff); + xp->flag = xflag; + + mark_inode_dirty(ip); + + up(&JFS_IP(ip)->commit_sem); + /* + * COMMIT_SyncList flags an anonymous tlock on page that is on + * sync list. + * We need to commit the inode to get the page written disk. + */ + if (test_and_clear_cflag(COMMIT_Synclist,ip)) + jfs_commit_inode(ip, 0); + + return (0); +} + + +/* + * NAME: extRealloc() + * + * FUNCTION: extend the allocation of a file extent containing a + * partial back last page. + * + * PARAMETERS: + * ip - the inode of the file. + * cp - cbuf for the partial backed last page. + * xlen - request size of the resulting extent. + * xp - pointer to an xad. on successful exit, the xad + * describes the newly allocated extent. + * abnr - boolean_t indicating whether the newly allocated extent + * should be marked as allocated but not recorded. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + * ENOSPC - insufficient disk resources. + */ +int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr) +{ + struct super_block *sb = ip->i_sb; + s64 xaddr, xlen, nxaddr, delta, xoff; + s64 ntail, nextend, ninsert; + int rc, nbperpage = JFS_SBI(sb)->nbperpage; + int xflag; + + /* This blocks if we are low on resources */ + txBeginAnon(ip->i_sb); + + down(&JFS_IP(ip)->commit_sem); + /* validate extent length */ + if (nxlen > MAXXLEN) + nxlen = MAXXLEN; + + /* get the extend (partial) page's disk block address and + * number of blocks. + */ + xaddr = addressXAD(xp); + xlen = lengthXAD(xp); + xoff = offsetXAD(xp); + + /* if the extend page is abnr and if the request is for + * the extent to be allocated and recorded, + * make the page allocated and recorded. + */ + if ((xp->flag & XAD_NOTRECORDED) && !abnr) { + xp->flag = 0; + if ((rc = xtUpdate(0, ip, xp))) + goto exit; + } + + /* try to allocated the request number of blocks for the + * extent. dbRealloc() first tries to satisfy the request + * by extending the allocation in place. otherwise, it will + * try to allocate a new set of blocks large enough for the + * request. in satisfying a request, dbReAlloc() may allocate + * less than what was request but will always allocate enough + * space as to satisfy the extend page. + */ + if ((rc = extBrealloc(ip, xaddr, xlen, &nxlen, &nxaddr))) + goto exit; + + delta = nxlen - xlen; + + /* check if the extend page is not abnr but the request is abnr + * and the allocated disk space is for more than one page. if this + * is the case, there is a miss match of abnr between the extend page + * and the one or more pages following the extend page. as a result, + * two extents will have to be manipulated. the first will be that + * of the extent of the extend page and will be manipulated thru + * an xtExtend() or an xtTailgate(), depending upon whether the + * disk allocation occurred as an inplace extension. the second + * extent will be manipulated (created) through an xtInsert() and + * will be for the pages following the extend page. + */ + if (abnr && (!(xp->flag & XAD_NOTRECORDED)) && (nxlen > nbperpage)) { + ntail = nbperpage; + nextend = ntail - xlen; + ninsert = nxlen - nbperpage; + + xflag = XAD_NOTRECORDED; + } else { + ntail = nxlen; + nextend = delta; + ninsert = 0; + + xflag = xp->flag; + } + + /* if we were able to extend the disk allocation in place, + * extend the extent. otherwise, move the extent to a + * new disk location. + */ + if (xaddr == nxaddr) { + /* extend the extent */ + if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) { + dbFree(ip, xaddr + xlen, delta); + goto exit; + } + } else { + /* + * move the extent to a new location: + * + * xtTailgate() accounts for relocated tail extent; + */ + if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) { + dbFree(ip, nxaddr, nxlen); + goto exit; + } + } + + + /* check if we need to also insert a new extent */ + if (ninsert) { + /* perform the insert. if it fails, free the blocks + * to be inserted and make it appear that we only did + * the xtExtend() or xtTailgate() above. + */ + xaddr = nxaddr + ntail; + if (xtInsert (0, ip, xflag, xoff + ntail, (int) ninsert, + &xaddr, 0)) { + dbFree(ip, xaddr, (s64) ninsert); + delta = nextend; + nxlen = ntail; + xflag = 0; + } + } + + /* update the inode with the number of blocks allocated */ + ip->i_blocks += LBLK2PBLK(sb, delta); + + /* set the return results */ + XADaddress(xp, nxaddr); + XADlength(xp, nxlen); + XADoffset(xp, xoff); + xp->flag = xflag; + + mark_inode_dirty(ip); +exit: + up(&JFS_IP(ip)->commit_sem); + return (rc); +} + + +/* + * NAME: extHint() + * + * FUNCTION: produce an extent allocation hint for a file offset. + * + * PARAMETERS: + * ip - the inode of the file. + * offset - file offset for which the hint is needed. + * xp - pointer to the xad that is to be filled in with + * the hint. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + */ +int extHint(struct inode *ip, s64 offset, xad_t * xp) +{ + struct super_block *sb = ip->i_sb; + xadlist_t xadl; + lxdlist_t lxdl; + lxd_t lxd; + s64 prev; + int rc, nbperpage = JFS_SBI(sb)->nbperpage; + + /* init the hint as "no hint provided" */ + XADaddress(xp, 0); + + /* determine the starting extent offset of the page previous + * to the page containing the offset. + */ + prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage; + + /* if the offsets in the first page of the file, + * no hint provided. + */ + if (prev < 0) + return (0); + + /* prepare to lookup the previous page's extent info */ + lxdl.maxnlxd = 1; + lxdl.nlxd = 1; + lxdl.lxd = &lxd; + LXDoffset(&lxd, prev) + LXDlength(&lxd, nbperpage); + + xadl.maxnxad = 1; + xadl.nxad = 0; + xadl.xad = xp; + + /* perform the lookup */ + if ((rc = xtLookupList(ip, &lxdl, &xadl, 0))) + return (rc); + + /* check if not extent exists for the previous page. + * this is possible for sparse files. + */ + if (xadl.nxad == 0) { +// assert(ISSPARSE(ip)); + return (0); + } + + /* only preserve the abnr flag within the xad flags + * of the returned hint. + */ + xp->flag &= XAD_NOTRECORDED; + + assert(xadl.nxad == 1); + assert(lengthXAD(xp) == nbperpage); + + return (0); +} + + +/* + * NAME: extRecord() + * + * FUNCTION: change a page with a file from not recorded to recorded. + * + * PARAMETERS: + * ip - inode of the file. + * cp - cbuf of the file page. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + * ENOSPC - insufficient disk resources. + */ +int extRecord(struct inode *ip, xad_t * xp) +{ + int rc; + + txBeginAnon(ip->i_sb); + + down(&JFS_IP(ip)->commit_sem); + + /* update the extent */ + rc = xtUpdate(0, ip, xp); + + up(&JFS_IP(ip)->commit_sem); + return (rc); +} + + +/* + * NAME: extFill() + * + * FUNCTION: allocate disk space for a file page that represents + * a file hole. + * + * PARAMETERS: + * ip - the inode of the file. + * cp - cbuf of the file page represent the hole. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + * ENOSPC - insufficient disk resources. + */ +int extFill(struct inode *ip, xad_t * xp) +{ + int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage; + s64 blkno = offsetXAD(xp) >> ip->i_blksize; + +// assert(ISSPARSE(ip)); + + /* initialize the extent allocation hint */ + XADaddress(xp, 0); + + /* allocate an extent to fill the hole */ + if ((rc = extAlloc(ip, nbperpage, blkno, xp, FALSE))) + return (rc); + + assert(lengthPXD(xp) == nbperpage); + + return (0); +} + + +/* + * NAME: extBalloc() + * + * FUNCTION: allocate disk blocks to form an extent. + * + * initially, we will try to allocate disk blocks for the + * requested size (nblocks). if this fails (nblocks + * contigious free blocks not avaliable), we'll try to allocate + * a smaller number of blocks (producing a smaller extent), with + * this smaller number of blocks consisting of the requested + * number of blocks rounded down to the next smaller power of 2 + * number (i.e. 16 -> 8). we'll continue to round down and + * retry the allocation until the number of blocks to allocate + * is smaller than the number of blocks per page. + * + * PARAMETERS: + * ip - the inode of the file. + * hint - disk block number to be used as an allocation hint. + * *nblocks - pointer to an s64 value. on entry, this value specifies + * the desired number of block to be allocated. on successful + * exit, this value is set to the number of blocks actually + * allocated. + * blkno - pointer to a block address that is filled in on successful + * return with the starting block number of the newly + * allocated block range. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + * ENOSPC - insufficient disk resources. + */ +static int +extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) +{ + s64 nb, nblks, daddr, max; + int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage; + bmap_t *mp = JFS_SBI(ip->i_sb)->bmap; + + /* get the number of blocks to initially attempt to allocate. + * we'll first try the number of blocks requested unless this + * number is greater than the maximum number of contigious free + * blocks in the map. in that case, we'll start off with the + * maximum free. + */ + max = (s64) 1 << mp->db_maxfreebud; + if (*nblocks >= max && *nblocks > nbperpage) + nb = nblks = (max > nbperpage) ? max : nbperpage; + else + nb = nblks = *nblocks; + + /* try to allocate blocks */ + while ((rc = dbAlloc(ip, hint, nb, &daddr))) { + /* if something other than an out of space error, + * stop and return this error. + */ + if (rc != ENOSPC) + return (rc); + + /* decrease the allocation request size */ + nb = min(nblks, extRoundDown(nb)); + + /* give up if we cannot cover a page */ + if (nb < nbperpage) + return (rc); + } + + *nblocks = nb; + *blkno = daddr; + + return (0); +} + + +/* + * NAME: extBrealloc() + * + * FUNCTION: attempt to extend an extent's allocation. + * + * initially, we will try to extend the extent's allocation + * in place. if this fails, we'll try to move the extent + * to a new set of blocks. if moving the extent, we initially + * will try to allocate disk blocks for the requested size + * (nnew). if this fails (nnew contigious free blocks not + * avaliable), we'll try to allocate a smaller number of + * blocks (producing a smaller extent), with this smaller + * number of blocks consisting of the requested number of + * blocks rounded down to the next smaller power of 2 + * number (i.e. 16 -> 8). we'll continue to round down and + * retry the allocation until the number of blocks to allocate + * is smaller than the number of blocks per page. + * + * PARAMETERS: + * ip - the inode of the file. + * blkno - starting block number of the extents current allocation. + * nblks - number of blocks within the extents current allocation. + * newnblks - pointer to a s64 value. on entry, this value is the + * the new desired extent size (number of blocks). on + * successful exit, this value is set to the extent's actual + * new size (new number of blocks). + * newblkno - the starting block number of the extents new allocation. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + * ENOSPC - insufficient disk resources. + */ +static int +extBrealloc(struct inode *ip, + s64 blkno, s64 nblks, s64 * newnblks, s64 * newblkno) +{ + int rc; + + /* try to extend in place */ + if ((rc = dbExtend(ip, blkno, nblks, *newnblks - nblks)) == 0) { + *newblkno = blkno; + return (0); + } else { + if (rc != ENOSPC) + return (rc); + } + + /* in place extension not possible. + * try to move the extent to a new set of blocks. + */ + return (extBalloc(ip, blkno, newnblks, newblkno)); +} + + +/* + * NAME: extRoundDown() + * + * FUNCTION: round down a specified number of blocks to the next + * smallest power of 2 number. + * + * PARAMETERS: + * nb - the inode of the file. + * + * RETURN VALUES: + * next smallest power of 2 number. + */ +static s64 extRoundDown(s64 nb) +{ + int i; + u64 m, k; + + for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) { + if (m & nb) + break; + } + + i = 63 - i; + k = (u64) 1 << i; + k = ((k - 1) & nb) ? k : k >> 1; + + return (k); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_extent.h linux.20pre2-ac1/fs/jfs/jfs_extent.h --- linux.20pre2/fs/jfs/jfs_extent.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_extent.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,31 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2001 + * + * 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 _H_JFS_EXTENT +#define _H_JFS_EXTENT + +/* get block allocation allocation hint as location of disk inode */ +#define INOHINT(ip) \ + (addressPXD(&(JFS_IP(ip)->ixpxd)) + lengthPXD(&(JFS_IP(ip)->ixpxd)) - 1) + +extern int extAlloc(struct inode *, s64, s64, xad_t *, boolean_t); +extern int extFill(struct inode *, xad_t *); +extern int extHint(struct inode *, s64, xad_t *); +extern int extRealloc(struct inode *, s64, xad_t *, boolean_t); +extern int extRecord(struct inode *, xad_t *); + +#endif /* _H_JFS_EXTENT */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_filsys.h linux.20pre2-ac1/fs/jfs/jfs_filsys.h --- linux.20pre2/fs/jfs/jfs_filsys.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_filsys.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,272 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2001 + * + * 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 _H_JFS_FILSYS +#define _H_JFS_FILSYS + +/* + * jfs_filsys.h + * + * file system (implementation-dependent) constants + * + * refer to for system wide implementation-dependent constants + */ + +/* + * file system option (superblock flag) + */ +/* platform option (conditional compilation) */ +#define JFS_AIX 0x80000000 /* AIX support */ +/* POSIX name/directory support */ + +#define JFS_OS2 0x40000000 /* OS/2 support */ +/* case-insensitive name/directory support */ + +#define JFS_DFS 0x20000000 /* DCE DFS LFS support */ + +#define JFS_LINUX 0x10000000 /* Linux support */ +/* case-sensitive name/directory support */ + +/* directory option */ +#define JFS_UNICODE 0x00000001 /* unicode name */ + +/* commit option */ +#define JFS_COMMIT 0x00000f00 /* commit option mask */ +#define JFS_GROUPCOMMIT 0x00000100 /* group (of 1) commit */ +#define JFS_LAZYCOMMIT 0x00000200 /* lazy commit */ +#define JFS_TMPFS 0x00000400 /* temporary file system - + * do not log/commit: + */ + +/* log logical volume option */ +#define JFS_INLINELOG 0x00000800 /* inline log within file system */ +#define JFS_INLINEMOVE 0x00001000 /* inline log being moved */ + +/* Secondary aggregate inode table */ +#define JFS_BAD_SAIT 0x00010000 /* current secondary ait is bad */ + +/* sparse regular file support */ +#define JFS_SPARSE 0x00020000 /* sparse regular file */ + +/* DASD Limits F226941 */ +#define JFS_DASD_ENABLED 0x00040000 /* DASD limits enabled */ +#define JFS_DASD_PRIME 0x00080000 /* Prime DASD usage on boot */ + +/* big endian flag */ +#define JFS_SWAP_BYTES 0x00100000 /* running on big endian computer */ + +/* Directory index */ +#define JFS_DIR_INDEX 0x00200000 /* Persistant index for */ + /* directory entries */ + + +/* + * buffer cache configuration + */ +/* page size */ +#ifdef PSIZE +#undef PSIZE +#endif +#define PSIZE 4096 /* page size (in byte) */ +#define L2PSIZE 12 /* log2(PSIZE) */ +#define POFFSET 4095 /* offset within page */ + +/* buffer page size */ +#define BPSIZE PSIZE + +/* + * fs fundamental size + * + * PSIZE >= file system block size >= PBSIZE >= DISIZE + */ +#define PBSIZE 512 /* physical block size (in byte) */ +#define L2PBSIZE 9 /* log2(PBSIZE) */ + +#define DISIZE 512 /* on-disk inode size (in byte) */ +#define L2DISIZE 9 /* log2(DISIZE) */ + +#define IDATASIZE 256 /* inode inline data size */ +#define IXATTRSIZE 128 /* inode inline extended attribute size */ + +#define XTPAGE_SIZE 4096 +#define log2_PAGESIZE 12 + +#define IAG_SIZE 4096 +#define IAG_EXTENT_SIZE 4096 +#define INOSPERIAG 4096 /* number of disk inodes per iag */ +#define L2INOSPERIAG 12 /* l2 number of disk inodes per iag */ +#define INOSPEREXT 32 /* number of disk inode per extent */ +#define L2INOSPEREXT 5 /* l2 number of disk inode per extent */ +#define IXSIZE (DISIZE * INOSPEREXT) /* inode extent size */ +#define INOSPERPAGE 8 /* number of disk inodes per 4K page */ +#define L2INOSPERPAGE 3 /* log2(INOSPERPAGE) */ + +#define IAGFREELIST_LWM 64 + +#define INODE_EXTENT_SIZE IXSIZE /* inode extent size */ +#define NUM_INODE_PER_EXTENT INOSPEREXT +#define NUM_INODE_PER_IAG INOSPERIAG + +#define MINBLOCKSIZE 512 +#define MAXBLOCKSIZE 4096 +#define MAXFILESIZE ((s64)1 << 52) + +#define JFS_LINK_MAX 65535 /* nlink_t is unsigned short */ + +/* Minimum number of bytes supported for a JFS partition */ +#define MINJFS (0x1000000) +#define MINJFSTEXT "16" + +/* + * file system block size -> physical block size + */ +#define LBOFFSET(x) ((x) & (PBSIZE - 1)) +#define LBNUMBER(x) ((x) >> L2PBSIZE) +#define LBLK2PBLK(sb,b) ((b) << (sb->s_blocksize_bits - L2PBSIZE)) +#define PBLK2LBLK(sb,b) ((b) >> (sb->s_blocksize_bits - L2PBSIZE)) +/* size in byte -> last page number */ +#define SIZE2PN(size) ( ((s64)((size) - 1)) >> (L2PSIZE) ) +/* size in byte -> last file system block number */ +#define SIZE2BN(size, l2bsize) ( ((s64)((size) - 1)) >> (l2bsize) ) + +/* + * fixed physical block address (physical block size = 512 byte) + * + * NOTE: since we can't guarantee a physical block size of 512 bytes the use of + * these macros should be removed and the byte offset macros used instead. + */ +#define SUPER1_B 64 /* primary superblock */ +#define AIMAP_B (SUPER1_B + 8) /* 1st extent of aggregate inode map */ +#define AITBL_B (AIMAP_B + 16) /* + * 1st extent of aggregate inode table + */ +#define SUPER2_B (AITBL_B + 32) /* 2ndary superblock pbn */ +#define BMAP_B (SUPER2_B + 8) /* block allocation map */ + +/* + * SIZE_OF_SUPER defines the total amount of space reserved on disk for the + * superblock. This is not the same as the superblock structure, since all of + * this space is not currently being used. + */ +#define SIZE_OF_SUPER PSIZE + +/* + * SIZE_OF_AG_TABLE defines the amount of space reserved to hold the AG table + */ +#define SIZE_OF_AG_TABLE PSIZE + +/* + * SIZE_OF_MAP_PAGE defines the amount of disk space reserved for each page of + * the inode allocation map (to hold iag) + */ +#define SIZE_OF_MAP_PAGE PSIZE + +/* + * fixed byte offset address + */ +#define SUPER1_OFF 0x8000 /* primary superblock */ +#define AIMAP_OFF (SUPER1_OFF + SIZE_OF_SUPER) + /* + * Control page of aggregate inode map + * followed by 1st extent of map + */ +#define AITBL_OFF (AIMAP_OFF + (SIZE_OF_MAP_PAGE << 1)) + /* + * 1st extent of aggregate inode table + */ +#define SUPER2_OFF (AITBL_OFF + INODE_EXTENT_SIZE) + /* + * secondary superblock + */ +#define BMAP_OFF (SUPER2_OFF + SIZE_OF_SUPER) + /* + * block allocation map + */ + +/* + * The following macro is used to indicate the number of reserved disk blocks at + * the front of an aggregate, in terms of physical blocks. This value is + * currently defined to be 32K. This turns out to be the same as the primary + * superblock's address, since it directly follows the reserved blocks. + */ +#define AGGR_RSVD_BLOCKS SUPER1_B + +/* + * The following macro is used to indicate the number of reserved bytes at the + * front of an aggregate. This value is currently defined to be 32K. This + * turns out to be the same as the primary superblock's byte offset, since it + * directly follows the reserved blocks. + */ +#define AGGR_RSVD_BYTES SUPER1_OFF + +/* + * The following macro defines the byte offset for the first inode extent in + * the aggregate inode table. This allows us to find the self inode to find the + * rest of the table. Currently this value is 44K. + */ +#define AGGR_INODE_TABLE_START AITBL_OFF + +/* + * fixed reserved inode number + */ +/* aggregate inode */ +#define AGGR_RESERVED_I 0 /* aggregate inode (reserved) */ +#define AGGREGATE_I 1 /* aggregate inode map inode */ +#define BMAP_I 2 /* aggregate block allocation map inode */ +#define LOG_I 3 /* aggregate inline log inode */ +#define BADBLOCK_I 4 /* aggregate bad block inode */ +#define FILESYSTEM_I 16 /* 1st/only fileset inode in ait: + * fileset inode map inode + */ + +/* per fileset inode */ +#define FILESET_RSVD_I 0 /* fileset inode (reserved) */ +#define FILESET_EXT_I 1 /* fileset inode extension */ +#define ROOT_I 2 /* fileset root inode */ +#define ACL_I 3 /* fileset ACL inode */ + +#define FILESET_OBJECT_I 4 /* the first fileset inode available for a file + * or directory or link... + */ +#define FIRST_FILESET_INO 16 /* the first aggregate inode which describes + * an inode. (To fsck this is also the first + * inode in part 2 of the agg inode table.) + */ + +/* + * directory configuration + */ +#define JFS_NAME_MAX 255 +#define JFS_PATH_MAX BPSIZE + + +/* + * file system state (superblock state) + */ +#define FM_CLEAN 0x00000000 /* file system is unmounted and clean */ +#define FM_MOUNT 0x00000001 /* file system is mounted cleanly */ +#define FM_DIRTY 0x00000002 /* file system was not unmounted and clean + * when mounted or + * commit failure occurred while being mounted: + * fsck() must be run to repair + */ +#define FM_LOGREDO 0x00000004 /* log based recovery (logredo()) failed: + * fsck() must be run to repair + */ +#define FM_EXTENDFS 0x00000008 /* file system extendfs() in progress */ + +#endif /* _H_JFS_FILSYS */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_imap.c linux.20pre2-ac1/fs/jfs/jfs_imap.c --- linux.20pre2/fs/jfs/jfs_imap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_imap.c 2002-08-06 18:01:05.000000000 +0100 @@ -0,0 +1,3197 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 + */ + +/* + * jfs_imap.c: inode allocation map manager + * + * Serialization: + * Each AG has a simple lock which is used to control the serialization of + * the AG level lists. This lock should be taken first whenever an AG + * level list will be modified or accessed. + * + * Each IAG is locked by obtaining the buffer for the IAG page. + * + * There is also a inode lock for the inode map inode. A read lock needs to + * be taken whenever an IAG is read from the map or the global level + * information is read. A write lock needs to be taken whenever the global + * level information is modified or an atomic operation needs to be used. + * + * If more than one IAG is read at one time, the read lock may not + * be given up until all of the IAG's are read. Otherwise, a deadlock + * may occur when trying to obtain the read lock while another thread + * holding the read lock is waiting on the IAG already being held. + * + * The control page of the inode map is read into memory by diMount(). + * Thereafter it should only be modified in memory and then it will be + * written out when the filesystem is unmounted by diUnmount(). + */ + +#include +#include +#include "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_dinode.h" +#include "jfs_dmap.h" +#include "jfs_imap.h" +#include "jfs_metapage.h" +#include "jfs_superblock.h" +#include "jfs_debug.h" + +/* + * imap locks + */ +/* iag free list lock */ +#define IAGFREE_LOCK_INIT(imap) init_MUTEX(&imap->im_freelock) +#define IAGFREE_LOCK(imap) down(&imap->im_freelock) +#define IAGFREE_UNLOCK(imap) up(&imap->im_freelock) + +/* per ag iag list locks */ +#define AG_LOCK_INIT(imap,index) init_MUTEX(&(imap->im_aglock[index])) +#define AG_LOCK(imap,agno) down(&imap->im_aglock[agno]) +#define AG_UNLOCK(imap,agno) up(&imap->im_aglock[agno]) + +/* + * external references + */ +extern struct address_space_operations jfs_aops; + +/* + * forward references + */ +static int diAllocAG(imap_t *, int, boolean_t, struct inode *); +static int diAllocAny(imap_t *, int, boolean_t, struct inode *); +static int diAllocBit(imap_t *, iag_t *, int); +static int diAllocExt(imap_t *, int, struct inode *); +static int diAllocIno(imap_t *, int, struct inode *); +static int diFindFree(u32, int); +static int diNewExt(imap_t *, iag_t *, int); +static int diNewIAG(imap_t *, int *, int, metapage_t **); +static void duplicateIXtree(struct super_block *, s64, int, s64 *); + +static int diIAGRead(imap_t * imap, int, metapage_t **); +static int copy_from_dinode(dinode_t *, struct inode *); +static void copy_to_dinode(dinode_t *, struct inode *); + +/* + * debug code for double-checking inode map + */ +/* #define _JFS_DEBUG_IMAP 1 */ + +#ifdef _JFS_DEBUG_IMAP +#define DBG_DIINIT(imap) DBGdiInit(imap) +#define DBG_DIALLOC(imap, ino) DBGdiAlloc(imap, ino) +#define DBG_DIFREE(imap, ino) DBGdiFree(imap, ino) + +static void *DBGdiInit(imap_t * imap); +static void DBGdiAlloc(imap_t * imap, ino_t ino); +static void DBGdiFree(imap_t * imap, ino_t ino); +#else +#define DBG_DIINIT(imap) +#define DBG_DIALLOC(imap, ino) +#define DBG_DIFREE(imap, ino) +#endif /* _JFS_DEBUG_IMAP */ + +/* + * NAME: diMount() + * + * FUNCTION: initialize the incore inode map control structures for + * a fileset or aggregate init time. + * + * the inode map's control structure (dinomap_t) is + * brought in from disk and placed in virtual memory. + * + * PARAMETERS: + * ipimap - pointer to inode map inode for the aggregate or fileset. + * + * RETURN VALUES: + * 0 - success + * ENOMEM - insufficient free virtual memory. + * EIO - i/o error. + */ +int diMount(struct inode *ipimap) +{ + imap_t *imap; + metapage_t *mp; + int index; + dinomap_t *dinom_le; + + /* + * allocate/initialize the in-memory inode map control structure + */ + /* allocate the in-memory inode map control structure. */ + imap = (imap_t *) kmalloc(sizeof(imap_t), GFP_KERNEL); + if (imap == NULL) { + jERROR(1, ("diMount: kmalloc returned NULL!\n")); + return (ENOMEM); + } + + /* read the on-disk inode map control structure. */ + + mp = read_metapage(ipimap, + IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage, + PSIZE, 0); + if (mp == NULL) { + kfree(imap); + return (EIO); + } + + /* copy the on-disk version to the in-memory version. */ + dinom_le = (dinomap_t *) mp->data; + imap->im_freeiag = le32_to_cpu(dinom_le->in_freeiag); + imap->im_nextiag = le32_to_cpu(dinom_le->in_nextiag); + atomic_set(&imap->im_numinos, le32_to_cpu(dinom_le->in_numinos)); + atomic_set(&imap->im_numfree, le32_to_cpu(dinom_le->in_numfree)); + imap->im_nbperiext = le32_to_cpu(dinom_le->in_nbperiext); + imap->im_l2nbperiext = le32_to_cpu(dinom_le->in_l2nbperiext); + for (index = 0; index < MAXAG; index++) { + imap->im_agctl[index].inofree = + le32_to_cpu(dinom_le->in_agctl[index].inofree); + imap->im_agctl[index].extfree = + le32_to_cpu(dinom_le->in_agctl[index].extfree); + imap->im_agctl[index].numinos = + le32_to_cpu(dinom_le->in_agctl[index].numinos); + imap->im_agctl[index].numfree = + le32_to_cpu(dinom_le->in_agctl[index].numfree); + } + + /* release the buffer. */ + release_metapage(mp); + + /* + * allocate/initialize inode allocation map locks + */ + /* allocate and init iag free list lock */ + IAGFREE_LOCK_INIT(imap); + + /* allocate and init ag list locks */ + for (index = 0; index < MAXAG; index++) { + AG_LOCK_INIT(imap, index); + } + + /* bind the inode map inode and inode map control structure + * to each other. + */ + imap->im_ipimap = ipimap; + JFS_IP(ipimap)->i_imap = imap; + +// DBG_DIINIT(imap); + + return (0); +} + + +/* + * NAME: diUnmount() + * + * FUNCTION: write to disk the incore inode map control structures for + * a fileset or aggregate at unmount time. + * + * PARAMETERS: + * ipimap - pointer to inode map inode for the aggregate or fileset. + * + * RETURN VALUES: + * 0 - success + * ENOMEM - insufficient free virtual memory. + * EIO - i/o error. + */ +int diUnmount(struct inode *ipimap, int mounterror) +{ + imap_t *imap = JFS_IP(ipimap)->i_imap; + + /* + * update the on-disk inode map control structure + */ + + if (!(mounterror || isReadOnly(ipimap))) + diSync(ipimap); + + /* + * Invalidate the page cache buffers + */ + truncate_inode_pages(ipimap->i_mapping, 0); + + /* + * free in-memory control structure + */ + kfree(imap); + + return (0); +} + + +/* + * diSync() + */ +int diSync(struct inode *ipimap) +{ + dinomap_t *dinom_le; + imap_t *imp = JFS_IP(ipimap)->i_imap; + metapage_t *mp; + int index; + + /* + * write imap global conrol page + */ + /* read the on-disk inode map control structure */ + mp = get_metapage(ipimap, + IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage, + PSIZE, 0); + if (mp == NULL) { + jERROR(1,("diSync: get_metapage failed!\n")); + return EIO; + } + + /* copy the in-memory version to the on-disk version */ + //memcpy(mp->data, &imp->im_imap,sizeof(dinomap_t)); + dinom_le = (dinomap_t *) mp->data; + dinom_le->in_freeiag = cpu_to_le32(imp->im_freeiag); + dinom_le->in_nextiag = cpu_to_le32(imp->im_nextiag); + dinom_le->in_numinos = cpu_to_le32(atomic_read(&imp->im_numinos)); + dinom_le->in_numfree = cpu_to_le32(atomic_read(&imp->im_numfree)); + dinom_le->in_nbperiext = cpu_to_le32(imp->im_nbperiext); + dinom_le->in_l2nbperiext = cpu_to_le32(imp->im_l2nbperiext); + for (index = 0; index < MAXAG; index++) { + dinom_le->in_agctl[index].inofree = + cpu_to_le32(imp->im_agctl[index].inofree); + dinom_le->in_agctl[index].extfree = + cpu_to_le32(imp->im_agctl[index].extfree); + dinom_le->in_agctl[index].numinos = + cpu_to_le32(imp->im_agctl[index].numinos); + dinom_le->in_agctl[index].numfree = + cpu_to_le32(imp->im_agctl[index].numfree); + } + + /* write out the control structure */ + write_metapage(mp); + + /* + * write out dirty pages of imap + */ + fsync_inode_data_buffers(ipimap); + + diWriteSpecial(ipimap, 0); + + return (0); +} + + +/* + * NAME: diRead() + * + * FUNCTION: initialize an incore inode from disk. + * + * on entry, the specifed incore inode should itself + * specify the disk inode number corresponding to the + * incore inode (i.e. i_number should be initialized). + * + * this routine handles incore inode initialization for + * both "special" and "regular" inodes. special inodes + * are those required early in the mount process and + * require special handling since much of the file system + * is not yet initialized. these "special" inodes are + * identified by a NULL inode map inode pointer and are + * actually initialized by a call to diReadSpecial(). + * + * for regular inodes, the iag describing the disk inode + * is read from disk to determine the inode extent address + * for the disk inode. with the inode extent address in + * hand, the page of the extent that contains the disk + * inode is read and the disk inode is copied to the + * incore inode. + * + * PARAMETERS: + * ip - pointer to incore inode to be initialized from disk. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + * ENOMEM - insufficient memory + * + */ +int diRead(struct inode *ip) +{ + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + int iagno, ino, extno, rc; + struct inode *ipimap; + dinode_t *dp; + iag_t *iagp; + metapage_t *mp; + s64 blkno, agstart; + imap_t *imap; + int block_offset; + int inodes_left; + uint pageno; + int rel_inode; + + jFYI(1, ("diRead: ino = %ld\n", ip->i_ino)); + + ipimap = sbi->ipimap; + JFS_IP(ip)->ipimap = ipimap; + + /* determine the iag number for this inode (number) */ + iagno = INOTOIAG(ip->i_ino); + + /* read the iag */ + imap = JFS_IP(ipimap)->i_imap; + IREAD_LOCK(ipimap); + rc = diIAGRead(imap, iagno, &mp); + IREAD_UNLOCK(ipimap); + if (rc) { + jERROR(1, ("diRead: diIAGRead returned %d\n", rc)); + return (rc); + } + + iagp = (iag_t *) mp->data; + + /* determine inode extent that holds the disk inode */ + ino = ip->i_ino & (INOSPERIAG - 1); + extno = ino >> L2INOSPEREXT; + + if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) || + (addressPXD(&iagp->inoext[extno]) == 0)) { + jERROR(1, ("diRead: Bad inoext: 0x%lx, 0x%lx\n", + (ulong) addressPXD(&iagp->inoext[extno]), + (ulong) lengthPXD(&iagp->inoext[extno]))); + release_metapage(mp); + updateSuper(ip->i_sb, FM_DIRTY); + return ESTALE; + } + + /* get disk block number of the page within the inode extent + * that holds the disk inode. + */ + blkno = INOPBLK(&iagp->inoext[extno], ino, sbi->l2nbperpage); + + /* get the ag for the iag */ + agstart = le64_to_cpu(iagp->agstart); + + release_metapage(mp); + + rel_inode = (ino & (INOSPERPAGE - 1)); + pageno = blkno >> sbi->l2nbperpage; + + if ((block_offset = ((u32) blkno & (sbi->nbperpage - 1)))) { + /* + * OS/2 didn't always align inode extents on page boundaries + */ + inodes_left = + (sbi->nbperpage - block_offset) << sbi->l2niperblk; + + if (rel_inode < inodes_left) + rel_inode += block_offset << sbi->l2niperblk; + else { + pageno += 1; + rel_inode -= inodes_left; + } + } + + /* read the page of disk inode */ + mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1); + if (mp == 0) { + jERROR(1, ("diRead: read_metapage failed\n")); + return EIO; + } + + /* locate the the disk inode requested */ + dp = (dinode_t *) mp->data; + dp += rel_inode; + + if (ip->i_ino != le32_to_cpu(dp->di_number)) { + jERROR(1, ("diRead: i_ino != di_number\n")); + updateSuper(ip->i_sb, FM_DIRTY); + rc = EIO; + } else if (le32_to_cpu(dp->di_nlink) == 0) { + jERROR(1, + ("diRead: di_nlink is zero. ino=%ld\n", ip->i_ino)); + updateSuper(ip->i_sb, FM_DIRTY); + rc = ESTALE; + } else + /* copy the disk inode to the in-memory inode */ + rc = copy_from_dinode(dp, ip); + + release_metapage(mp); + + /* set the ag for the inode */ + JFS_IP(ip)->agno = BLKTOAG(agstart, sbi); + + return (rc); +} + + +/* + * NAME: diReadSpecial() + * + * FUNCTION: initialize a 'special' inode from disk. + * + * this routines handles aggregate level inodes. The + * inode cache cannot differentiate between the + * aggregate inodes and the filesystem inodes, so we + * handle these here. We don't actually use the aggregate + * inode map, since these inodes are at a fixed location + * and in some cases the aggregate inode map isn't initialized + * yet. + * + * PARAMETERS: + * sb - filesystem superblock + * inum - aggregate inode number + * secondary - 1 if secondary aggregate inode table + * + * RETURN VALUES: + * new inode - success + * NULL - i/o error. + */ +struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + uint address; + dinode_t *dp; + struct inode *ip; + metapage_t *mp; + int rc; + + ip = new_inode(sb); + if (ip == NULL) { + jERROR(1, + ("diReadSpecial: new_inode returned NULL!\n")); + return ip; + } + + rc = alloc_jfs_inode(ip); + if (rc) { + make_bad_inode(ip); + iput(ip); + return NULL; + } + + if (secondary) { + address = addressPXD(&sbi->ait2) >> sbi->l2nbperpage; + JFS_IP(ip)->ipimap = sbi->ipaimap2; + } else { + address = AITBL_OFF >> L2PSIZE; + JFS_IP(ip)->ipimap = sbi->ipaimap; + } + + ASSERT(inum < INOSPEREXT); + + ip->i_ino = inum; + + address += inum >> 3; /* 8 inodes per 4K page */ + + /* read the page of fixed disk inode (AIT) in raw mode */ + jEVENT(0, + ("Reading aggregate inode %d from block %d\n", (uint) inum, + address)); + mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1); + if (mp == NULL) { + ip->i_sb = NULL; + ip->i_nlink = 1; /* Don't want iput() deleting it */ + iput(ip); + return (NULL); + } + + /* get the pointer to the disk inode of interest */ + dp = (dinode_t *) (mp->data); + dp += inum % 8; /* 8 inodes per 4K page */ + + /* copy on-disk inode to in-memory inode */ + if ((copy_from_dinode(dp, ip)) != 0) { + /* handle bad return by returning NULL for ip */ + ip->i_sb = NULL; + ip->i_nlink = 1; /* Don't want iput() deleting it */ + iput(ip); + /* release the page */ + release_metapage(mp); + return (NULL); + + } + + ip->i_mapping->a_ops = &jfs_aops; + ip->i_mapping->gfp_mask = GFP_NOFS; + + if ((inum == FILESYSTEM_I) && (JFS_IP(ip)->ipimap == sbi->ipaimap)) { + sbi->gengen = le32_to_cpu(dp->di_gengen); + sbi->inostamp = le32_to_cpu(dp->di_inostamp); + } + + /* release the page */ + release_metapage(mp); + + return (ip); +} + +/* + * NAME: diWriteSpecial() + * + * FUNCTION: Write the special inode to disk + * + * PARAMETERS: + * ip - special inode + * secondary - 1 if secondary aggregate inode table + * + * RETURN VALUES: none + */ + +void diWriteSpecial(struct inode *ip, int secondary) +{ + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + uint address; + dinode_t *dp; + ino_t inum = ip->i_ino; + metapage_t *mp; + + ip->i_state &= ~I_DIRTY; + + if (secondary) + address = addressPXD(&sbi->ait2) >> sbi->l2nbperpage; + else + address = AITBL_OFF >> L2PSIZE; + + ASSERT(inum < INOSPEREXT); + + address += inum >> 3; /* 8 inodes per 4K page */ + + /* read the page of fixed disk inode (AIT) in raw mode */ + jEVENT(0, + ("Reading aggregate inode %d from block %d\n", (uint) inum, + address)); + mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1); + if (mp == NULL) { + jERROR(1, + ("diWriteSpecial: failed to read aggregate inode extent!\n")); + return; + } + + /* get the pointer to the disk inode of interest */ + dp = (dinode_t *) (mp->data); + dp += inum % 8; /* 8 inodes per 4K page */ + + /* copy on-disk inode to in-memory inode */ + copy_to_dinode(dp, ip); + memcpy(&dp->di_xtroot, &JFS_IP(ip)->i_xtroot, 288); + + if (inum == FILESYSTEM_I) + dp->di_gengen = cpu_to_le32(sbi->gengen); + + /* write the page */ + write_metapage(mp); +} + +/* + * NAME: diFreeSpecial() + * + * FUNCTION: Free allocated space for special inode + */ +void diFreeSpecial(struct inode *ip) +{ + if (ip == NULL) { + jERROR(1, ("diFreeSpecial called with NULL ip!\n")); + return; + } + fsync_inode_data_buffers(ip); + truncate_inode_pages(ip->i_mapping, 0); + iput(ip); +} + + + +/* + * NAME: diWrite() + * + * FUNCTION: write the on-disk inode portion of the in-memory inode + * to its corresponding on-disk inode. + * + * on entry, the specifed incore inode should itself + * specify the disk inode number corresponding to the + * incore inode (i.e. i_number should be initialized). + * + * the inode contains the inode extent address for the disk + * inode. with the inode extent address in hand, the + * page of the extent that contains the disk inode is + * read and the disk inode portion of the incore inode + * is copied to the disk inode. + * + * PARAMETERS: + * tid - transacation id + * ip - pointer to incore inode to be written to the inode extent. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + */ +int diWrite(tid_t tid, struct inode *ip) +{ + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + int rc = 0; + s32 ino; + dinode_t *dp; + s64 blkno; + int block_offset; + int inodes_left; + metapage_t *mp; + uint pageno; + int rel_inode; + int dioffset; + struct inode *ipimap; + uint type; + lid_t lid; + tlock_t *ditlck, *tlck; + linelock_t *dilinelock, *ilinelock; + lv_t *lv; + int n; + + ipimap = jfs_ip->ipimap; + + ino = ip->i_ino & (INOSPERIAG - 1); + + assert(lengthPXD(&(jfs_ip->ixpxd)) == + JFS_IP(ipimap)->i_imap->im_nbperiext); + assert(addressPXD(&(jfs_ip->ixpxd))); + + /* + * read the page of disk inode containing the specified inode: + */ + /* compute the block address of the page */ + blkno = INOPBLK(&(jfs_ip->ixpxd), ino, sbi->l2nbperpage); + + rel_inode = (ino & (INOSPERPAGE - 1)); + pageno = blkno >> sbi->l2nbperpage; + + if ((block_offset = ((u32) blkno & (sbi->nbperpage - 1)))) { + /* + * OS/2 didn't always align inode extents on page boundaries + */ + inodes_left = + (sbi->nbperpage - block_offset) << sbi->l2niperblk; + + if (rel_inode < inodes_left) + rel_inode += block_offset << sbi->l2niperblk; + else { + pageno += 1; + rel_inode -= inodes_left; + } + } + /* read the page of disk inode */ + retry: + mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1); + if (mp == 0) + return (EIO); + + /* get the pointer to the disk inode */ + dp = (dinode_t *) mp->data; + dp += rel_inode; + + dioffset = (ino & (INOSPERPAGE - 1)) << L2DISIZE; + + /* + * acquire transaction lock on the on-disk inode; + * N.B. tlock is acquired on ipimap not ip; + */ + if ((ditlck = + txLock(tid, ipimap, mp, tlckINODE | tlckENTRY)) == NULL) + goto retry; + dilinelock = (linelock_t *) & ditlck->lock; + + /* + * copy btree root from in-memory inode to on-disk inode + * + * (tlock is taken from inline B+-tree root in in-memory + * inode when the B+-tree root is updated, which is pointed + * by jfs_ip->blid as well as being on tx tlock list) + * + * further processing of btree root is based on the copy + * in in-memory inode, where txLog() will log from, and, + * for xtree root, txUpdateMap() will update map and reset + * XAD_NEW bit; + */ + + if (S_ISDIR(ip->i_mode) && (lid = jfs_ip->xtlid)) { + /* + * This is the special xtree inside the directory for storing + * the directory table + */ + xtpage_t *p, *xp; + xad_t *xad; + + jfs_ip->xtlid = 0; + tlck = lid_to_tlock(lid); + assert(tlck->type & tlckXTREE); + tlck->type |= tlckBTROOT; + tlck->mp = mp; + ilinelock = (linelock_t *) & tlck->lock; + + /* + * copy xtree root from inode to dinode: + */ + p = &jfs_ip->i_xtroot; + xp = (xtpage_t *) &dp->di_dirtable; + lv = (lv_t *) & ilinelock->lv; + for (n = 0; n < ilinelock->index; n++, lv++) { + memcpy(&xp->xad[lv->offset], &p->xad[lv->offset], + lv->length << L2XTSLOTSIZE); + } + + /* reset on-disk (metadata page) xtree XAD_NEW bit */ + xad = &xp->xad[XTENTRYSTART]; + for (n = XTENTRYSTART; + n < le16_to_cpu(xp->header.nextindex); n++, xad++) + if (xad->flag & (XAD_NEW | XAD_EXTENDED)) + xad->flag &= ~(XAD_NEW | XAD_EXTENDED); + } + + if ((lid = jfs_ip->blid) == 0) + goto inlineData; + jfs_ip->blid = 0; + + tlck = lid_to_tlock(lid); + type = tlck->type; + tlck->type |= tlckBTROOT; + tlck->mp = mp; + ilinelock = (linelock_t *) & tlck->lock; + + /* + * regular file: 16 byte (XAD slot) granularity + */ + if (type & tlckXTREE) { + xtpage_t *p, *xp; + xad_t *xad; + + /* + * copy xtree root from inode to dinode: + */ + p = &jfs_ip->i_xtroot; + xp = &dp->di_xtroot; + lv = (lv_t *) & ilinelock->lv; + for (n = 0; n < ilinelock->index; n++, lv++) { + memcpy(&xp->xad[lv->offset], &p->xad[lv->offset], + lv->length << L2XTSLOTSIZE); + } + + /* reset on-disk (metadata page) xtree XAD_NEW bit */ + xad = &xp->xad[XTENTRYSTART]; + for (n = XTENTRYSTART; + n < le16_to_cpu(xp->header.nextindex); n++, xad++) + if (xad->flag & (XAD_NEW | XAD_EXTENDED)) + xad->flag &= ~(XAD_NEW | XAD_EXTENDED); + } + /* + * directory: 32 byte (directory entry slot) granularity + */ + else if (type & tlckDTREE) { + dtpage_t *p, *xp; + + /* + * copy dtree root from inode to dinode: + */ + p = (dtpage_t *) &jfs_ip->i_dtroot; + xp = (dtpage_t *) & dp->di_dtroot; + lv = (lv_t *) & ilinelock->lv; + for (n = 0; n < ilinelock->index; n++, lv++) { + memcpy(&xp->slot[lv->offset], &p->slot[lv->offset], + lv->length << L2DTSLOTSIZE); + } + } else { + jERROR(1, ("diWrite: UFO tlock\n")); + } + + inlineData: + /* + * copy inline symlink from in-memory inode to on-disk inode + */ + if (S_ISLNK(ip->i_mode) && ip->i_size < IDATASIZE) { + lv = (lv_t *) & dilinelock->lv[dilinelock->index]; + lv->offset = (dioffset + 2 * 128) >> L2INODESLOTSIZE; + lv->length = 2; + memcpy(&dp->di_fastsymlink, jfs_ip->i_inline, IDATASIZE); + dilinelock->index++; + } +#ifdef _STILL_TO_PORT + /* + * copy inline data from in-memory inode to on-disk inode: + * 128 byte slot granularity + */ + if (test_cflag(COMMIT_Inlineea, ip)) + lv = (lv_t *) & dilinelock->lv[dilinelock->index]; + lv->offset = (dioffset + 3 * 128) >> L2INODESLOTSIZE; + lv->length = 1; + memcpy(&dp->di_inlineea, &ip->i_inlineea, INODESLOTSIZE); + dilinelock->index++; + + clear_cflag(COMMIT_Inlineea, ip); + } +#endif /* _STILL_TO_PORT */ + + /* + * lock/copy inode base: 128 byte slot granularity + */ +// baseDinode: + lv = (lv_t *) & dilinelock->lv[dilinelock->index]; + lv->offset = dioffset >> L2INODESLOTSIZE; + copy_to_dinode(dp, ip); + if (test_and_clear_cflag(COMMIT_Dirtable, ip)) { + lv->length = 2; + memcpy(&dp->di_dirtable, &jfs_ip->i_dirtable, 96); + } else + lv->length = 1; + dilinelock->index++; + +#ifdef _JFS_FASTDASD + /* + * We aren't logging changes to the DASD used in directory inodes, + * but we need to write them to disk. If we don't unmount cleanly, + * mount will recalculate the DASD used. + */ + if (S_ISDIR(ip->i_mode) + && (ip->i_ipmnt->i_mntflag & JFS_DASD_ENABLED)) + bcopy(&ip->i_DASD, &dp->di_DASD, sizeof(dasd_t)); +#endif /* _JFS_FASTDASD */ + + /* release the buffer holding the updated on-disk inode. + * the buffer will be later written by commit processing. + */ + write_metapage(mp); + + return (rc); +} + + +/* + * NAME: diFree(ip) + * + * FUNCTION: free a specified inode from the inode working map + * for a fileset or aggregate. + * + * if the inode to be freed represents the first (only) + * free inode within the iag, the iag will be placed on + * the ag free inode list. + * + * freeing the inode will cause the inode extent to be + * freed if the inode is the only allocated inode within + * the extent. in this case all the disk resource backing + * up the inode extent will be freed. in addition, the iag + * will be placed on the ag extent free list if the extent + * is the first free extent in the iag. if freeing the + * extent also means that no free inodes will exist for + * the iag, the iag will also be removed from the ag free + * inode list. + * + * the iag describing the inode will be freed if the extent + * is to be freed and it is the only backed extent within + * the iag. in this case, the iag will be removed from the + * ag free extent list and ag free inode list and placed on + * the inode map's free iag list. + * + * a careful update approach is used to provide consistency + * in the face of updates to multiple buffers. under this + * approach, all required buffers are obtained before making + * any updates and are held until all updates are complete. + * + * PARAMETERS: + * ip - inode to be freed. + * + * RETURN VALUES: + * 0 - success + * EIO - i/o error. + */ +int diFree(struct inode *ip) +{ + int rc; + ino_t inum = ip->i_ino; + iag_t *iagp, *aiagp, *biagp, *ciagp, *diagp; + metapage_t *mp, *amp, *bmp, *cmp, *dmp; + int iagno, ino, extno, bitno, sword, agno; + int back, fwd; + u32 bitmap, mask; + struct inode *ipimap = JFS_SBI(ip->i_sb)->ipimap; + imap_t *imap = JFS_IP(ipimap)->i_imap; + s64 xaddr; + s64 xlen; + pxd_t freepxd; + tid_t tid; + struct inode *iplist[3]; + tlock_t *tlck; + pxdlock_t *pxdlock; + + /* + * This is just to suppress compiler warnings. The same logic that + * references these variables is used to initialize them. + */ + aiagp = biagp = ciagp = diagp = NULL; + + /* get the iag number containing the inode. + */ + iagno = INOTOIAG(inum); + + /* make sure that the iag is contained within + * the map. + */ + //assert(iagno < imap->im_nextiag); + if (iagno >= imap->im_nextiag) { + jERROR(1, ("diFree: inum = %d, iagno = %d, nextiag = %d\n", + (uint) inum, iagno, imap->im_nextiag)); + dump_mem("imap", imap, 32); + updateSuper(ip->i_sb, FM_DIRTY); + return EIO; + } + + /* get the allocation group for this ino. + */ + agno = JFS_IP(ip)->agno; + + /* Lock the AG specific inode map information + */ + AG_LOCK(imap, agno); + + /* Obtain read lock in imap inode. Don't release it until we have + * read all of the IAG's that we are going to. + */ + IREAD_LOCK(ipimap); + + /* read the iag. + */ + if ((rc = diIAGRead(imap, iagno, &mp))) { + IREAD_UNLOCK(ipimap); + AG_UNLOCK(imap, agno); + return (rc); + } + iagp = (iag_t *) mp->data; + + /* get the inode number and extent number of the inode within + * the iag and the inode number within the extent. + */ + ino = inum & (INOSPERIAG - 1); + extno = ino >> L2INOSPEREXT; + bitno = ino & (INOSPEREXT - 1); + mask = HIGHORDER >> bitno; + + assert(le32_to_cpu(iagp->wmap[extno]) & mask); +#ifdef _STILL_TO_PORT + assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0); +#endif /* _STILL_TO_PORT */ + assert(addressPXD(&iagp->inoext[extno])); + + /* compute the bitmap for the extent reflecting the freed inode. + */ + bitmap = le32_to_cpu(iagp->wmap[extno]) & ~mask; + + if (imap->im_agctl[agno].numfree > imap->im_agctl[agno].numinos) { + jERROR(1,("diFree: numfree > numinos\n")); + release_metapage(mp); + IREAD_UNLOCK(ipimap); + AG_UNLOCK(imap, agno); + updateSuper(ip->i_sb, FM_DIRTY); + return EIO; + } + /* + * inode extent still has some inodes or below low water mark: + * keep the inode extent; + */ + if (bitmap || + imap->im_agctl[agno].numfree < 96 || + (imap->im_agctl[agno].numfree < 288 && + (((imap->im_agctl[agno].numfree * 100) / + imap->im_agctl[agno].numinos) <= 25))) { + /* if the iag currently has no free inodes (i.e., + * the inode being freed is the first free inode of iag), + * insert the iag at head of the inode free list for the ag. + */ + if (iagp->nfreeinos == 0) { + /* check if there are any iags on the ag inode + * free list. if so, read the first one so that + * we can link the current iag onto the list at + * the head. + */ + if ((fwd = imap->im_agctl[agno].inofree) >= 0) { + /* read the iag that currently is the head + * of the list. + */ + if ((rc = diIAGRead(imap, fwd, &))) { + IREAD_UNLOCK(ipimap); + AG_UNLOCK(imap, agno); + release_metapage(mp); + return (rc); + } + aiagp = (iag_t *) amp->data; + + /* make current head point back to the iag. + */ + aiagp->inofreeback = cpu_to_le32(iagno); + + write_metapage(amp); + } + + /* iag points forward to current head and iag + * becomes the new head of the list. + */ + iagp->inofreefwd = + cpu_to_le32(imap->im_agctl[agno].inofree); + iagp->inofreeback = -1; + imap->im_agctl[agno].inofree = iagno; + } + IREAD_UNLOCK(ipimap); + + /* update the free inode summary map for the extent if + * freeing the inode means the extent will now have free + * inodes (i.e., the inode being freed is the first free + * inode of extent), + */ + if (iagp->wmap[extno] == ONES) { + sword = extno >> L2EXTSPERSUM; + bitno = extno & (EXTSPERSUM - 1); + iagp->inosmap[sword] &= + cpu_to_le32(~(HIGHORDER >> bitno)); + } + + /* update the bitmap. + */ + iagp->wmap[extno] = cpu_to_le32(bitmap); + DBG_DIFREE(imap, inum); + + /* update the free inode counts at the iag, ag and + * map level. + */ + iagp->nfreeinos = + cpu_to_le32(le32_to_cpu(iagp->nfreeinos) + 1); + imap->im_agctl[agno].numfree += 1; + atomic_inc(&imap->im_numfree); + + /* release the AG inode map lock + */ + AG_UNLOCK(imap, agno); + + /* write the iag */ + write_metapage(mp); + + return (0); + } + + + /* + * inode extent has become free and above low water mark: + * free the inode extent; + */ + + /* + * prepare to update iag list(s) (careful update step 1) + */ + amp = bmp = cmp = dmp = NULL; + fwd = back = -1; + + /* check if the iag currently has no free extents. if so, + * it will be placed on the head of the ag extent free list. + */ + if (iagp->nfreeexts == 0) { + /* check if the ag extent free list has any iags. + * if so, read the iag at the head of the list now. + * this (head) iag will be updated later to reflect + * the addition of the current iag at the head of + * the list. + */ + if ((fwd = imap->im_agctl[agno].extfree) >= 0) { + if ((rc = diIAGRead(imap, fwd, &))) + goto error_out; + aiagp = (iag_t *) amp->data; + } + } else { + /* iag has free extents. check if the addition of a free + * extent will cause all extents to be free within this + * iag. if so, the iag will be removed from the ag extent + * free list and placed on the inode map's free iag list. + */ + if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) { + /* in preparation for removing the iag from the + * ag extent free list, read the iags preceeding + * and following the iag on the ag extent free + * list. + */ + if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) { + if ((rc = diIAGRead(imap, fwd, &))) + goto error_out; + aiagp = (iag_t *) amp->data; + } + + if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) { + if ((rc = diIAGRead(imap, back, &bmp))) + goto error_out; + biagp = (iag_t *) bmp->data; + } + } + } + + /* remove the iag from the ag inode free list if freeing + * this extent cause the iag to have no free inodes. + */ + if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) { + int inofreeback = le32_to_cpu(iagp->inofreeback); + int inofreefwd = le32_to_cpu(iagp->inofreefwd); + + /* in preparation for removing the iag from the + * ag inode free list, read the iags preceeding + * and following the iag on the ag inode free + * list. before reading these iags, we must make + * sure that we already don't have them in hand + * from up above, since re-reading an iag (buffer) + * we are currently holding would cause a deadlock. + */ + if (inofreefwd >= 0) { + + if (inofreefwd == fwd) + ciagp = (iag_t *) amp->data; + else if (inofreefwd == back) + ciagp = (iag_t *) bmp->data; + else { + if ((rc = + diIAGRead(imap, inofreefwd, &cmp))) + goto error_out; + assert(cmp != NULL); + ciagp = (iag_t *) cmp->data; + } + assert(ciagp != NULL); + } + + if (inofreeback >= 0) { + if (inofreeback == fwd) + diagp = (iag_t *) amp->data; + else if (inofreeback == back) + diagp = (iag_t *) bmp->data; + else { + if ((rc = + diIAGRead(imap, inofreeback, &dmp))) + goto error_out; + assert(dmp != NULL); + diagp = (iag_t *) dmp->data; + } + assert(diagp != NULL); + } + } + + IREAD_UNLOCK(ipimap); + + /* + * invalidate any page of the inode extent freed from buffer cache; + */ + freepxd = iagp->inoext[extno]; + xaddr = addressPXD(&iagp->inoext[extno]); + xlen = lengthPXD(&iagp->inoext[extno]); + invalidate_metapages(JFS_SBI(ip->i_sb)->direct_inode, xaddr, xlen); + + /* + * update iag list(s) (careful update step 2) + */ + /* add the iag to the ag extent free list if this is the + * first free extent for the iag. + */ + if (iagp->nfreeexts == 0) { + if (fwd >= 0) + aiagp->extfreeback = cpu_to_le32(iagno); + + iagp->extfreefwd = + cpu_to_le32(imap->im_agctl[agno].extfree); + iagp->extfreeback = -1; + imap->im_agctl[agno].extfree = iagno; + } else { + /* remove the iag from the ag extent list if all extents + * are now free and place it on the inode map iag free list. + */ + if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) { + if (fwd >= 0) + aiagp->extfreeback = iagp->extfreeback; + + if (back >= 0) + biagp->extfreefwd = iagp->extfreefwd; + else + imap->im_agctl[agno].extfree = + le32_to_cpu(iagp->extfreefwd); + + iagp->extfreefwd = iagp->extfreeback = -1; + + IAGFREE_LOCK(imap); + iagp->iagfree = cpu_to_le32(imap->im_freeiag); + imap->im_freeiag = iagno; + IAGFREE_UNLOCK(imap); + } + } + + /* remove the iag from the ag inode free list if freeing + * this extent causes the iag to have no free inodes. + */ + if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) { + if ((int) le32_to_cpu(iagp->inofreefwd) >= 0) + ciagp->inofreeback = iagp->inofreeback; + + if ((int) le32_to_cpu(iagp->inofreeback) >= 0) + diagp->inofreefwd = iagp->inofreefwd; + else + imap->im_agctl[agno].inofree = + le32_to_cpu(iagp->inofreefwd); + + iagp->inofreefwd = iagp->inofreeback = -1; + } + + /* update the inode extent address and working map + * to reflect the free extent. + * the permanent map should have been updated already + * for the inode being freed. + */ + assert(iagp->pmap[extno] == 0); + iagp->wmap[extno] = 0; + DBG_DIFREE(imap, inum); + PXDlength(&iagp->inoext[extno], 0); + PXDaddress(&iagp->inoext[extno], 0); + + /* update the free extent and free inode summary maps + * to reflect the freed extent. + * the inode summary map is marked to indicate no inodes + * available for the freed extent. + */ + sword = extno >> L2EXTSPERSUM; + bitno = extno & (EXTSPERSUM - 1); + mask = HIGHORDER >> bitno; + iagp->inosmap[sword] |= cpu_to_le32(mask); + iagp->extsmap[sword] &= cpu_to_le32(~mask); + + /* update the number of free inodes and number of free extents + * for the iag. + */ + iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) - + (INOSPEREXT - 1)); + iagp->nfreeexts = cpu_to_le32(le32_to_cpu(iagp->nfreeexts) + 1); + + /* update the number of free inodes and backed inodes + * at the ag and inode map level. + */ + imap->im_agctl[agno].numfree -= (INOSPEREXT - 1); + imap->im_agctl[agno].numinos -= INOSPEREXT; + atomic_sub(INOSPEREXT - 1, &imap->im_numfree); + atomic_sub(INOSPEREXT, &imap->im_numinos); + + if (amp) + write_metapage(amp); + if (bmp) + write_metapage(bmp); + if (cmp) + write_metapage(cmp); + if (dmp) + write_metapage(dmp); + + /* + * start transaction to update block allocation map + * for the inode extent freed; + * + * N.B. AG_LOCK is released and iag will be released below, and + * other thread may allocate inode from/reusing the ixad freed + * BUT with new/different backing inode extent from the extent + * to be freed by the transaction; + */ + tid = txBegin(ipimap->i_sb, COMMIT_FORCE); + + /* acquire tlock of the iag page of the freed ixad + * to force the page NOHOMEOK (even though no data is + * logged from the iag page) until NOREDOPAGE|FREEXTENT log + * for the free of the extent is committed; + * write FREEXTENT|NOREDOPAGE log record + * N.B. linelock is overlaid as freed extent descriptor; + */ + tlck = txLock(tid, ipimap, mp, tlckINODE | tlckFREE); + pxdlock = (pxdlock_t *) & tlck->lock; + pxdlock->flag = mlckFREEPXD; + pxdlock->pxd = freepxd; + pxdlock->index = 1; + + write_metapage(mp); + + iplist[0] = ipimap; + + /* + * logredo needs the IAG number and IAG extent index in order + * to ensure that the IMap is consistent. The least disruptive + * way to pass these values through to the transaction manager + * is in the iplist array. + * + * It's not pretty, but it works. + */ + iplist[1] = (struct inode *) (size_t)iagno; + iplist[2] = (struct inode *) (size_t)extno; + + rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); // D233382 + + txEnd(tid); + + /* unlock the AG inode map information */ + AG_UNLOCK(imap, agno); + + return (0); + + error_out: + IREAD_UNLOCK(ipimap); + + if (amp) + release_metapage(amp); + if (bmp) + release_metapage(bmp); + if (cmp) + release_metapage(cmp); + if (dmp) + release_metapage(dmp); + + AG_UNLOCK(imap, agno); + + release_metapage(mp); + + return (rc); +} + +/* + * There are several places in the diAlloc* routines where we initialize + * the inode. + */ +static inline void +diInitInode(struct inode *ip, int iagno, int ino, int extno, iag_t * iagp) +{ + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + + ip->i_ino = (iagno << L2INOSPERIAG) + ino; + DBG_DIALLOC(JFS_IP(ipimap)->i_imap, ip->i_ino); + jfs_ip->ixpxd = iagp->inoext[extno]; + jfs_ip->agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi); +} + + +/* + * NAME: diAlloc(pip,dir,ip) + * + * FUNCTION: allocate a disk inode from the inode working map + * for a fileset or aggregate. + * + * PARAMETERS: + * pip - pointer to incore inode for the parent inode. + * dir - TRUE if the new disk inode is for a directory. + * ip - pointer to a new inode + * + * RETURN VALUES: + * 0 - success. + * ENOSPC - insufficient disk resources. + * EIO - i/o error. + */ +int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) +{ + int rc, ino, iagno, addext, extno, bitno, sword; + int nwords, rem, i, agno; + u32 mask, inosmap, extsmap; + struct inode *ipimap; + metapage_t *mp; + ino_t inum; + iag_t *iagp; + imap_t *imap; + + /* get the pointers to the inode map inode and the + * corresponding imap control structure. + */ + ipimap = JFS_SBI(pip->i_sb)->ipimap; + imap = JFS_IP(ipimap)->i_imap; + JFS_IP(ip)->ipimap = ipimap; + JFS_IP(ip)->fileset = FILESYSTEM_I; + + /* for a directory, the allocation policy is to start + * at the ag level using the preferred ag. + */ + if (dir == TRUE) { + agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap); + AG_LOCK(imap, agno); + goto tryag; + } + + /* for files, the policy starts off by trying to allocate from + * the same iag containing the parent disk inode: + * try to allocate the new disk inode close to the parent disk + * inode, using parent disk inode number + 1 as the allocation + * hint. (we use a left-to-right policy to attempt to avoid + * moving backward on the disk.) compute the hint within the + * file system and the iag. + */ + inum = pip->i_ino + 1; + ino = inum & (INOSPERIAG - 1); + + /* back off the the hint if it is outside of the iag */ + if (ino == 0) + inum = pip->i_ino; + + /* get the ag number of this iag */ + agno = JFS_IP(pip)->agno; + + /* lock the AG inode map information */ + AG_LOCK(imap, agno); + + /* Get read lock on imap inode */ + IREAD_LOCK(ipimap); + + /* get the iag number and read the iag */ + iagno = INOTOIAG(inum); + if ((rc = diIAGRead(imap, iagno, &mp))) { + IREAD_UNLOCK(ipimap); + return (rc); + } + iagp = (iag_t *) mp->data; + + /* determine if new inode extent is allowed to be added to the iag. + * new inode extent can be added to the iag if the ag + * has less than 32 free disk inodes and the iag has free extents. + */ + addext = (imap->im_agctl[agno].numfree < 32 && iagp->nfreeexts); + + /* + * try to allocate from the IAG + */ + /* check if the inode may be allocated from the iag + * (i.e. the inode has free inodes or new extent can be added). + */ + if (iagp->nfreeinos || addext) { + /* determine the extent number of the hint. + */ + extno = ino >> L2INOSPEREXT; + + /* check if the extent containing the hint has backed + * inodes. if so, try to allocate within this extent. + */ + if (addressPXD(&iagp->inoext[extno])) { + bitno = ino & (INOSPEREXT - 1); + if ((bitno = + diFindFree(le32_to_cpu(iagp->wmap[extno]), + bitno)) + < INOSPEREXT) { + ino = (extno << L2INOSPEREXT) + bitno; + + /* a free inode (bit) was found within this + * extent, so allocate it. + */ + rc = diAllocBit(imap, iagp, ino); + IREAD_UNLOCK(ipimap); + if (rc) { + assert(rc == EIO); + } else { + /* set the results of the allocation + * and write the iag. + */ + diInitInode(ip, iagno, ino, extno, + iagp); + mark_metapage_dirty(mp); + } + release_metapage(mp); + + /* free the AG lock and return. + */ + AG_UNLOCK(imap, agno); + return (rc); + } + + if (!addext) + extno = + (extno == + EXTSPERIAG - 1) ? 0 : extno + 1; + } + + /* + * no free inodes within the extent containing the hint. + * + * try to allocate from the backed extents following + * hint or, if appropriate (i.e. addext is true), allocate + * an extent of free inodes at or following the extent + * containing the hint. + * + * the free inode and free extent summary maps are used + * here, so determine the starting summary map position + * and the number of words we'll have to examine. again, + * the approach is to allocate following the hint, so we + * might have to initially ignore prior bits of the summary + * map that represent extents prior to the extent containing + * the hint and later revisit these bits. + */ + bitno = extno & (EXTSPERSUM - 1); + nwords = (bitno == 0) ? SMAPSZ : SMAPSZ + 1; + sword = extno >> L2EXTSPERSUM; + + /* mask any prior bits for the starting words of the + * summary map. + */ + mask = ONES << (EXTSPERSUM - bitno); + inosmap = le32_to_cpu(iagp->inosmap[sword]) | mask; + extsmap = le32_to_cpu(iagp->extsmap[sword]) | mask; + + /* scan the free inode and free extent summary maps for + * free resources. + */ + for (i = 0; i < nwords; i++) { + /* check if this word of the free inode summary + * map describes an extent with free inodes. + */ + if (~inosmap) { + /* an extent with free inodes has been + * found. determine the extent number + * and the inode number within the extent. + */ + rem = diFindFree(inosmap, 0); + extno = (sword << L2EXTSPERSUM) + rem; + rem = + diFindFree(le32_to_cpu + (iagp->wmap[extno]), 0); + assert(rem < INOSPEREXT); + + /* determine the inode number within the + * iag and allocate the inode from the + * map. + */ + ino = (extno << L2INOSPEREXT) + rem; + rc = diAllocBit(imap, iagp, ino); + IREAD_UNLOCK(ipimap); + if (rc) { + assert(rc == EIO); + } else { + /* set the results of the allocation + * and write the iag. + */ + diInitInode(ip, iagno, ino, extno, + iagp); + mark_metapage_dirty(mp); + } + release_metapage(mp); + + /* free the AG lock and return. + */ + AG_UNLOCK(imap, agno); + return (rc); + + } + + /* check if we may allocate an extent of free + * inodes and whether this word of the free + * extents summary map describes a free extent. + */ + if (addext && ~extsmap) { + /* a free extent has been found. determine + * the extent number. + */ + rem = diFindFree(extsmap, 0); + extno = (sword << L2EXTSPERSUM) + rem; + + /* allocate an extent of free inodes. + */ + if ((rc = diNewExt(imap, iagp, extno))) { + /* if there is no disk space for a + * new extent, try to allocate the + * disk inode from somewhere else. + */ + if (rc == ENOSPC) + break; + + assert(rc == EIO); + } else { + /* set the results of the allocation + * and write the iag. + */ + diInitInode(ip, iagno, + extno << L2INOSPEREXT, + extno, iagp); + mark_metapage_dirty(mp); + } + release_metapage(mp); + /* free the imap inode & the AG lock & return. + */ + IREAD_UNLOCK(ipimap); + AG_UNLOCK(imap, agno); + return (rc); + } + + /* move on to the next set of summary map words. + */ + sword = (sword == SMAPSZ - 1) ? 0 : sword + 1; + inosmap = le32_to_cpu(iagp->inosmap[sword]); + extsmap = le32_to_cpu(iagp->extsmap[sword]); + } + } + /* unlock imap inode */ + IREAD_UNLOCK(ipimap); + + /* nothing doing in this iag, so release it. */ + release_metapage(mp); + + tryag: + /* + * try to allocate anywhere within the same AG as the parent inode. + */ + rc = diAllocAG(imap, agno, dir, ip); + + AG_UNLOCK(imap, agno); + + if (rc != ENOSPC) + return (rc); + + /* + * try to allocate in any AG. + */ + return (diAllocAny(imap, agno, dir, ip)); +} + + +/* + * NAME: diAllocAG(imap,agno,dir,ip) + * + * FUNCTION: allocate a disk inode from the allocation group. + * + * this routine first determines if a new extent of free + * inodes should be added for the allocation group, with + * the current request satisfied from this extent. if this + * is the case, an attempt will be made to do just that. if + * this attempt fails or it has been determined that a new + * extent should not be added, an attempt is made to satisfy + * the request by allocating an existing (backed) free inode + * from the allocation group. + * + * PRE CONDITION: Already have the AG lock for this AG. + * + * PARAMETERS: + * imap - pointer to inode map control structure. + * agno - allocation group to allocate from. + * dir - TRUE if the new disk inode is for a directory. + * ip - pointer to the new inode to be filled in on successful return + * with the disk inode number allocated, its extent address + * and the start of the ag. + * + * RETURN VALUES: + * 0 - success. + * ENOSPC - insufficient disk resources. + * EIO - i/o error. + */ +static int +diAllocAG(imap_t * imap, int agno, boolean_t dir, struct inode *ip) +{ + int rc, addext, numfree, numinos; + + /* get the number of free and the number of backed disk + * inodes currently within the ag. + */ + numfree = imap->im_agctl[agno].numfree; + numinos = imap->im_agctl[agno].numinos; + + if (numfree > numinos) { + jERROR(1,("diAllocAG: numfree > numinos\n")); + updateSuper(ip->i_sb, FM_DIRTY); + return EIO; + } + + /* determine if we should allocate a new extent of free inodes + * within the ag: for directory inodes, add a new extent + * if there are a small number of free inodes or number of free + * inodes is a small percentage of the number of backed inodes. + */ + if (dir == TRUE) + addext = (numfree < 64 || + (numfree < 256 + && ((numfree * 100) / numinos) <= 20)); + else + addext = (numfree == 0); + + /* + * try to allocate a new extent of free inodes. + */ + if (addext) { + /* if free space is not avaliable for this new extent, try + * below to allocate a free and existing (already backed) + * inode from the ag. + */ + if ((rc = diAllocExt(imap, agno, ip)) != ENOSPC) + return (rc); + } + + /* + * try to allocate an existing free inode from the ag. + */ + return (diAllocIno(imap, agno, ip)); +} + + +/* + * NAME: diAllocAny(imap,agno,dir,iap) + * + * FUNCTION: allocate a disk inode from any other allocation group. + * + * this routine is called when an allocation attempt within + * the primary allocation group has failed. if attempts to + * allocate an inode from any allocation group other than the + * specified primary group. + * + * PARAMETERS: + * imap - pointer to inode map control structure. + * agno - primary allocation group (to avoid). + * dir - TRUE if the new disk inode is for a directory. + * ip - pointer to a new inode to be filled in on successful return + * with the disk inode number allocated, its extent address + * and the start of the ag. + * + * RETURN VALUES: + * 0 - success. + * ENOSPC - insufficient disk resources. + * EIO - i/o error. + */ +static int +diAllocAny(imap_t * imap, int agno, boolean_t dir, struct inode *ip) +{ + int ag, rc; + int maxag = JFS_SBI(imap->im_ipimap->i_sb)->bmap->db_maxag; + + + /* try to allocate from the ags following agno up to + * the maximum ag number. + */ + for (ag = agno + 1; ag <= maxag; ag++) { + AG_LOCK(imap, ag); + + rc = diAllocAG(imap, ag, dir, ip); + + AG_UNLOCK(imap, ag); + + if (rc != ENOSPC) + return (rc); + } + + /* try to allocate from the ags in front of agno. + */ + for (ag = 0; ag < agno; ag++) { + AG_LOCK(imap, ag); + + rc = diAllocAG(imap, ag, dir, ip); + + AG_UNLOCK(imap, ag); + + if (rc != ENOSPC) + return (rc); + } + + /* no free disk inodes. + */ + return (ENOSPC); +} + + +/* + * NAME: diAllocIno(imap,agno,ip) + * + * FUNCTION: allocate a disk inode from the allocation group's free + * inode list, returning an error if this free list is + * empty (i.e. no iags on the list). + * + * allocation occurs from the first iag on the list using + * the iag's free inode summary map to find the leftmost + * free inode in the iag. + * + * PRE CONDITION: Already have AG lock for this AG. + * + * PARAMETERS: + * imap - pointer to inode map control structure. + * agno - allocation group. + * ip - pointer to new inode to be filled in on successful return + * with the disk inode number allocated, its extent address + * and the start of the ag. + * + * RETURN VALUES: + * 0 - success. + * ENOSPC - insufficient disk resources. + * EIO - i/o error. + */ +static int diAllocIno(imap_t * imap, int agno, struct inode *ip) +{ + int iagno, ino, rc, rem, extno, sword; + metapage_t *mp; + iag_t *iagp; + + /* check if there are iags on the ag's free inode list. + */ + if ((iagno = imap->im_agctl[agno].inofree) < 0) + return (ENOSPC); + + /* obtain read lock on imap inode */ + IREAD_LOCK(imap->im_ipimap); + + /* read the iag at the head of the list. + */ + if ((rc = diIAGRead(imap, iagno, &mp))) { + IREAD_UNLOCK(imap->im_ipimap); + return (rc); + } + iagp = (iag_t *) mp->data; + + /* better be free inodes in this iag if it is on the + * list. + */ + //assert(iagp->nfreeinos); + if (!iagp->nfreeinos) { + jERROR(1, + ("diAllocIno: nfreeinos = 0, but iag on freelist\n")); + jERROR(1, (" agno = %d, iagno = %d\n", agno, iagno)); + dump_mem("iag", iagp, 64); + updateSuper(ip->i_sb, FM_DIRTY); + return EIO; + } + + /* scan the free inode summary map to find an extent + * with free inodes. + */ + for (sword = 0;; sword++) { + assert(sword < SMAPSZ); + + if (~iagp->inosmap[sword]) + break; + } + + /* found a extent with free inodes. determine + * the extent number. + */ + rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0); + assert(rem < EXTSPERSUM); + extno = (sword << L2EXTSPERSUM) + rem; + + /* find the first free inode in the extent. + */ + rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0); + assert(rem < INOSPEREXT); + + /* compute the inode number within the iag. + */ + ino = (extno << L2INOSPEREXT) + rem; + + /* allocate the inode. + */ + rc = diAllocBit(imap, iagp, ino); + IREAD_UNLOCK(imap->im_ipimap); + if (rc) { + release_metapage(mp); + return (rc); + } + + /* set the results of the allocation and write the iag. + */ + diInitInode(ip, iagno, ino, extno, iagp); + write_metapage(mp); + + return (0); +} + + +/* + * NAME: diAllocExt(imap,agno,ip) + * + * FUNCTION: add a new extent of free inodes to an iag, allocating + * an inode from this extent to satisfy the current allocation + * request. + * + * this routine first tries to find an existing iag with free + * extents through the ag free extent list. if list is not + * empty, the head of the list will be selected as the home + * of the new extent of free inodes. otherwise (the list is + * empty), a new iag will be allocated for the ag to contain + * the extent. + * + * once an iag has been selected, the free extent summary map + * is used to locate a free extent within the iag and diNewExt() + * is called to initialize the extent, with initialization + * including the allocation of the first inode of the extent + * for the purpose of satisfying this request. + * + * PARAMETERS: + * imap - pointer to inode map control structure. + * agno - allocation group number. + * ip - pointer to new inode to be filled in on successful return + * with the disk inode number allocated, its extent address + * and the start of the ag. + * + * RETURN VALUES: + * 0 - success. + * ENOSPC - insufficient disk resources. + * EIO - i/o error. + */ +static int diAllocExt(imap_t * imap, int agno, struct inode *ip) +{ + int rem, iagno, sword, extno, rc; + metapage_t *mp; + iag_t *iagp; + + /* check if the ag has any iags with free extents. if not, + * allocate a new iag for the ag. + */ + if ((iagno = imap->im_agctl[agno].extfree) < 0) { + /* If successful, diNewIAG will obtain the read lock on the + * imap inode. + */ + if ((rc = diNewIAG(imap, &iagno, agno, &mp))) { + return (rc); + } + iagp = (iag_t *) mp->data; + + /* set the ag number if this a brand new iag + */ + iagp->agstart = + cpu_to_le64(AGTOBLK(agno, imap->im_ipimap)); + } else { + /* read the iag. + */ + IREAD_LOCK(imap->im_ipimap); + if ((rc = diIAGRead(imap, iagno, &mp))) { + assert(0); + } + iagp = (iag_t *) mp->data; + } + + /* using the free extent summary map, find a free extent. + */ + for (sword = 0;; sword++) { + assert(sword < SMAPSZ); + if (~iagp->extsmap[sword]) + break; + } + + /* determine the extent number of the free extent. + */ + rem = diFindFree(le32_to_cpu(iagp->extsmap[sword]), 0); + assert(rem < EXTSPERSUM); + extno = (sword << L2EXTSPERSUM) + rem; + + /* initialize the new extent. + */ + rc = diNewExt(imap, iagp, extno); + IREAD_UNLOCK(imap->im_ipimap); + if (rc) { + /* something bad happened. if a new iag was allocated, + * place it back on the inode map's iag free list, and + * clear the ag number information. + */ + if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) { + IAGFREE_LOCK(imap); + iagp->iagfree = cpu_to_le32(imap->im_freeiag); + imap->im_freeiag = iagno; + IAGFREE_UNLOCK(imap); + } + write_metapage(mp); + return (rc); + } + + /* set the results of the allocation and write the iag. + */ + diInitInode(ip, iagno, extno << L2INOSPEREXT, extno, iagp); + + write_metapage(mp); + + return (0); +} + + +/* + * NAME: diAllocBit(imap,iagp,ino) + * + * FUNCTION: allocate a backed inode from an iag. + * + * this routine performs the mechanics of allocating a + * specified inode from a backed extent. + * + * if the inode to be allocated represents the last free + * inode within the iag, the iag will be removed from the + * ag free inode list. + * + * a careful update approach is used to provide consistency + * in the face of updates to multiple buffers. under this + * approach, all required buffers are obtained before making + * any updates and are held all are updates are complete. + * + * PRE CONDITION: Already have buffer lock on iagp. Already have AG lock on + * this AG. Must have read lock on imap inode. + * + * PARAMETERS: + * imap - pointer to inode map control structure. + * iagp - pointer to iag. + * ino - inode number to be allocated within the iag. + * + * RETURN VALUES: + * 0 - success. + * ENOSPC - insufficient disk resources. + * EIO - i/o error. + */ +static int diAllocBit(imap_t * imap, iag_t * iagp, int ino) +{ + int extno, bitno, agno, sword, rc; + metapage_t *amp, *bmp; + iag_t *aiagp = 0, *biagp = 0; + u32 mask; + + /* check if this is the last free inode within the iag. + * if so, it will have to be removed from the ag free + * inode list, so get the iags preceeding and following + * it on the list. + */ + if (iagp->nfreeinos == cpu_to_le32(1)) { + amp = bmp = NULL; + + if ((int) le32_to_cpu(iagp->inofreefwd) >= 0) { + if ((rc = + diIAGRead(imap, le32_to_cpu(iagp->inofreefwd), + &))) + return (rc); + aiagp = (iag_t *) amp->data; + } + + if ((int) le32_to_cpu(iagp->inofreeback) >= 0) { + if ((rc = + diIAGRead(imap, + le32_to_cpu(iagp->inofreeback), + &bmp))) { + if (amp) + release_metapage(amp); + return (rc); + } + biagp = (iag_t *) bmp->data; + } + } + + /* get the ag number, extent number, inode number within + * the extent. + */ + agno = BLKTOAG(le64_to_cpu(iagp->agstart), JFS_SBI(imap->im_ipimap->i_sb)); + extno = ino >> L2INOSPEREXT; + bitno = ino & (INOSPEREXT - 1); + + /* compute the mask for setting the map. + */ + mask = HIGHORDER >> bitno; + + /* the inode should be free and backed. + */ + assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0); + assert((le32_to_cpu(iagp->wmap[extno]) & mask) == 0); + assert(addressPXD(&iagp->inoext[extno]) != 0); + + /* mark the inode as allocated in the working map. + */ + iagp->wmap[extno] |= cpu_to_le32(mask); + + /* check if all inodes within the extent are now + * allocated. if so, update the free inode summary + * map to reflect this. + */ + if (iagp->wmap[extno] == ONES) { + sword = extno >> L2EXTSPERSUM; + bitno = extno & (EXTSPERSUM - 1); + iagp->inosmap[sword] |= cpu_to_le32(HIGHORDER >> bitno); + } + + /* if this was the last free inode in the iag, remove the + * iag from the ag free inode list. + */ + if (iagp->nfreeinos == cpu_to_le32(1)) { + if (amp) { + aiagp->inofreeback = iagp->inofreeback; + write_metapage(amp); + } + + if (bmp) { + biagp->inofreefwd = iagp->inofreefwd; + write_metapage(bmp); + } else { + imap->im_agctl[agno].inofree = + le32_to_cpu(iagp->inofreefwd); + } + iagp->inofreefwd = iagp->inofreeback = -1; + } + + /* update the free inode count at the iag, ag, inode + * map levels. + */ + iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) - 1); + imap->im_agctl[agno].numfree -= 1; + atomic_dec(&imap->im_numfree); + + return (0); +} + + +/* + * NAME: diNewExt(imap,iagp,extno) + * + * FUNCTION: initialize a new extent of inodes for an iag, allocating + * the first inode of the extent for use for the current + * allocation request. + * + * disk resources are allocated for the new extent of inodes + * and the inodes themselves are initialized to reflect their + * existence within the extent (i.e. their inode numbers and + * inode extent addresses are set) and their initial state + * (mode and link count are set to zero). + * + * if the iag is new, it is not yet on an ag extent free list + * but will now be placed on this list. + * + * if the allocation of the new extent causes the iag to + * have no free extent, the iag will be removed from the + * ag extent free list. + * + * if the iag has no free backed inodes, it will be placed + * on the ag free inode list, since the addition of the new + * extent will now cause it to have free inodes. + * + * a careful update approach is used to provide consistency + * (i.e. list consistency) in the face of updates to multiple + * buffers. under this approach, all required buffers are + * obtained before making any updates and are held until all + * updates are complete. + * + * PRE CONDITION: Already have buffer lock on iagp. Already have AG lock on + * this AG. Must have read lock on imap inode. + * + * PARAMETERS: + * imap - pointer to inode map control structure. + * iagp - pointer to iag. + * extno - extent number. + * + * RETURN VALUES: + * 0 - success. + * ENOSPC - insufficient disk resources. + * EIO - i/o error. + */ +static int diNewExt(imap_t * imap, iag_t * iagp, int extno) +{ + int agno, iagno, fwd, back, freei = 0, sword, rc; + iag_t *aiagp = 0, *biagp = 0, *ciagp = 0; + metapage_t *amp, *bmp, *cmp, *dmp; + struct inode *ipimap; + s64 blkno, hint; + int i, j; + u32 mask; + ino_t ino; + dinode_t *dp; + struct jfs_sb_info *sbi; + + /* better have free extents. + */ + assert(iagp->nfreeexts); + + /* get the inode map inode. + */ + ipimap = imap->im_ipimap; + sbi = JFS_SBI(ipimap->i_sb); + + amp = bmp = cmp = NULL; + + /* get the ag and iag numbers for this iag. + */ + agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi); + iagno = le32_to_cpu(iagp->iagnum); + + /* check if this is the last free extent within the + * iag. if so, the iag must be removed from the ag + * free extent list, so get the iags preceeding and + * following the iag on this list. + */ + if (iagp->nfreeexts == cpu_to_le32(1)) { + if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) { + if ((rc = diIAGRead(imap, fwd, &))) + return (rc); + aiagp = (iag_t *) amp->data; + } + + if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) { + if ((rc = diIAGRead(imap, back, &bmp))) + goto error_out; + biagp = (iag_t *) bmp->data; + } + } else { + /* the iag has free extents. if all extents are free + * (as is the case for a newly allocated iag), the iag + * must be added to the ag free extent list, so get + * the iag at the head of the list in preparation for + * adding this iag to this list. + */ + fwd = back = -1; + if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) { + if ((fwd = imap->im_agctl[agno].extfree) >= 0) { + if ((rc = diIAGRead(imap, fwd, &))) + goto error_out; + aiagp = (iag_t *) amp->data; + } + } + } + + /* check if the iag has no free inodes. if so, the iag + * will have to be added to the ag free inode list, so get + * the iag at the head of the list in preparation for + * adding this iag to this list. in doing this, we must + * check if we already have the iag at the head of + * the list in hand. + */ + if (iagp->nfreeinos == 0) { + freei = imap->im_agctl[agno].inofree; + + if (freei >= 0) { + if (freei == fwd) { + ciagp = aiagp; + } else if (freei == back) { + ciagp = biagp; + } else { + if ((rc = diIAGRead(imap, freei, &cmp))) + goto error_out; + ciagp = (iag_t *) cmp->data; + } + assert(ciagp != NULL); + } + } + + /* allocate disk space for the inode extent. + */ + if ((extno == 0) || (addressPXD(&iagp->inoext[extno - 1]) == 0)) + hint = ((s64) agno << sbi->bmap->db_agl2size) - 1; + else + hint = addressPXD(&iagp->inoext[extno - 1]) + + lengthPXD(&iagp->inoext[extno - 1]) - 1; + + if ((rc = dbAlloc(ipimap, hint, (s64) imap->im_nbperiext, &blkno))) + goto error_out; + + /* compute the inode number of the first inode within the + * extent. + */ + ino = (iagno << L2INOSPERIAG) + (extno << L2INOSPEREXT); + + /* initialize the inodes within the newly allocated extent a + * page at a time. + */ + for (i = 0; i < imap->im_nbperiext; i += sbi->nbperpage) { + /* get a buffer for this page of disk inodes. + */ + dmp = get_metapage(ipimap, blkno + i, PSIZE, 1); + if (dmp == NULL) { + rc = EIO; + goto error_out; + } + dp = (dinode_t *) dmp->data; + + /* initialize the inode number, mode, link count and + * inode extent address. + */ + for (j = 0; j < INOSPERPAGE; j++, dp++, ino++) { + dp->di_inostamp = cpu_to_le32(sbi->inostamp); + dp->di_number = cpu_to_le32(ino); + dp->di_fileset = cpu_to_le32(FILESYSTEM_I); + dp->di_mode = 0; + dp->di_nlink = 0; + PXDaddress(&(dp->di_ixpxd), blkno); + PXDlength(&(dp->di_ixpxd), imap->im_nbperiext); + } + write_metapage(dmp); + } + + /* if this is the last free extent within the iag, remove the + * iag from the ag free extent list. + */ + if (iagp->nfreeexts == cpu_to_le32(1)) { + if (fwd >= 0) + aiagp->extfreeback = iagp->extfreeback; + + if (back >= 0) + biagp->extfreefwd = iagp->extfreefwd; + else + imap->im_agctl[agno].extfree = + le32_to_cpu(iagp->extfreefwd); + + iagp->extfreefwd = iagp->extfreeback = -1; + } else { + /* if the iag has all free extents (newly allocated iag), + * add the iag to the ag free extent list. + */ + if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) { + if (fwd >= 0) + aiagp->extfreeback = cpu_to_le32(iagno); + + iagp->extfreefwd = cpu_to_le32(fwd); + iagp->extfreeback = -1; + imap->im_agctl[agno].extfree = iagno; + } + } + + /* if the iag has no free inodes, add the iag to the + * ag free inode list. + */ + if (iagp->nfreeinos == 0) { + if (freei >= 0) + ciagp->inofreeback = cpu_to_le32(iagno); + + iagp->inofreefwd = + cpu_to_le32(imap->im_agctl[agno].inofree); + iagp->inofreeback = -1; + imap->im_agctl[agno].inofree = iagno; + } + + /* initialize the extent descriptor of the extent. */ + PXDlength(&iagp->inoext[extno], imap->im_nbperiext); + PXDaddress(&iagp->inoext[extno], blkno); + + /* initialize the working and persistent map of the extent. + * the working map will be initialized such that + * it indicates the first inode of the extent is allocated. + */ + iagp->wmap[extno] = cpu_to_le32(HIGHORDER); + iagp->pmap[extno] = 0; + + /* update the free inode and free extent summary maps + * for the extent to indicate the extent has free inodes + * and no longer represents a free extent. + */ + sword = extno >> L2EXTSPERSUM; + mask = HIGHORDER >> (extno & (EXTSPERSUM - 1)); + iagp->extsmap[sword] |= cpu_to_le32(mask); + iagp->inosmap[sword] &= cpu_to_le32(~mask); + + /* update the free inode and free extent counts for the + * iag. + */ + iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) + + (INOSPEREXT - 1)); + iagp->nfreeexts = cpu_to_le32(le32_to_cpu(iagp->nfreeexts) - 1); + + /* update the free and backed inode counts for the ag. + */ + imap->im_agctl[agno].numfree += (INOSPEREXT - 1); + imap->im_agctl[agno].numinos += INOSPEREXT; + + /* update the free and backed inode counts for the inode map. + */ + atomic_add(INOSPEREXT - 1, &imap->im_numfree); + atomic_add(INOSPEREXT, &imap->im_numinos); + + /* write the iags. + */ + if (amp) + write_metapage(amp); + if (bmp) + write_metapage(bmp); + if (cmp) + write_metapage(cmp); + + return (0); + + error_out: + + /* release the iags. + */ + if (amp) + release_metapage(amp); + if (bmp) + release_metapage(bmp); + if (cmp) + release_metapage(cmp); + + return (rc); +} + + +/* + * NAME: diNewIAG(imap,iagnop,agno) + * + * FUNCTION: allocate a new iag for an allocation group. + * + * first tries to allocate the iag from the inode map + * iagfree list: + * if the list has free iags, the head of the list is removed + * and returned to satisfy the request. + * if the inode map's iag free list is empty, the inode map + * is extended to hold a new iag. this new iag is initialized + * and returned to satisfy the request. + * + * PARAMETERS: + * imap - pointer to inode map control structure. + * iagnop - pointer to an iag number set with the number of the + * newly allocated iag upon successful return. + * agno - allocation group number. + * bpp - Buffer pointer to be filled in with new IAG's buffer + * + * RETURN VALUES: + * 0 - success. + * ENOSPC - insufficient disk resources. + * EIO - i/o error. + * + * serialization: + * AG lock held on entry/exit; + * write lock on the map is held inside; + * read lock on the map is held on successful completion; + * + * note: new iag transaction: + * . synchronously write iag; + * . write log of xtree and inode of imap; + * . commit; + * . synchronous write of xtree (right to left, bottom to top); + * . at start of logredo(): init in-memory imap with one additional iag page; + * . at end of logredo(): re-read imap inode to determine + * new imap size; + */ +static int +diNewIAG(imap_t * imap, int *iagnop, int agno, metapage_t ** mpp) +{ + int rc; + int iagno, i, xlen; + struct inode *ipimap; + struct super_block *sb; + struct jfs_sb_info *sbi; + metapage_t *mp; + iag_t *iagp; + s64 xaddr = 0; + s64 blkno; + tid_t tid; +#ifdef _STILL_TO_PORT + xad_t xad; +#endif /* _STILL_TO_PORT */ + struct inode *iplist[1]; + + /* pick up pointers to the inode map and mount inodes */ + ipimap = imap->im_ipimap; + sb = ipimap->i_sb; + sbi = JFS_SBI(sb); + + /* acquire the free iag lock */ + IAGFREE_LOCK(imap); + + /* if there are any iags on the inode map free iag list, + * allocate the iag from the head of the list. + */ + if (imap->im_freeiag >= 0) { + /* pick up the iag number at the head of the list */ + iagno = imap->im_freeiag; + + /* determine the logical block number of the iag */ + blkno = IAGTOLBLK(iagno, sbi->l2nbperpage); + } else { + /* no free iags. the inode map will have to be extented + * to include a new iag. + */ + + /* acquire inode map lock */ + IWRITE_LOCK(ipimap); + + assert(ipimap->i_size >> L2PSIZE == imap->im_nextiag + 1); + + /* get the next avaliable iag number */ + iagno = imap->im_nextiag; + + /* make sure that we have not exceeded the maximum inode + * number limit. + */ + if (iagno > (MAXIAGS - 1)) { + /* release the inode map lock */ + IWRITE_UNLOCK(ipimap); + + rc = ENOSPC; + goto out; + } + + /* + * synchronously append new iag page. + */ + /* determine the logical address of iag page to append */ + blkno = IAGTOLBLK(iagno, sbi->l2nbperpage); + + /* Allocate extent for new iag page */ + xlen = sbi->nbperpage; + if ((rc = dbAlloc(ipimap, 0, (s64) xlen, &xaddr))) { + /* release the inode map lock */ + IWRITE_UNLOCK(ipimap); + + goto out; + } + + /* assign a buffer for the page */ + mp = get_metapage(ipimap, xaddr, PSIZE, 1); + //bp = bmAssign(ipimap, blkno, xaddr, PSIZE, bmREAD_PAGE); + if (!mp) { + /* Free the blocks allocated for the iag since it was + * not successfully added to the inode map + */ + dbFree(ipimap, xaddr, (s64) xlen); + + /* release the inode map lock */ + IWRITE_UNLOCK(ipimap); + + rc = EIO; + goto out; + } + iagp = (iag_t *) mp->data; + + /* init the iag */ + memset(iagp, 0, sizeof(iag_t)); + iagp->iagnum = cpu_to_le32(iagno); + iagp->inofreefwd = iagp->inofreeback = -1; + iagp->extfreefwd = iagp->extfreeback = -1; + iagp->iagfree = -1; + iagp->nfreeinos = 0; + iagp->nfreeexts = cpu_to_le32(EXTSPERIAG); + + /* initialize the free inode summary map (free extent + * summary map initialization handled by bzero). + */ + for (i = 0; i < SMAPSZ; i++) + iagp->inosmap[i] = ONES; + + flush_metapage(mp); +#ifdef _STILL_TO_PORT + /* synchronously write the iag page */ + if (bmWrite(bp)) { + /* Free the blocks allocated for the iag since it was + * not successfully added to the inode map + */ + dbFree(ipimap, xaddr, (s64) xlen); + + /* release the inode map lock */ + IWRITE_UNLOCK(ipimap); + + rc = EIO; + goto out; + } + + /* Now the iag is on disk */ + + /* + * start tyransaction of update of the inode map + * addressing structure pointing to the new iag page; + */ +#endif /* _STILL_TO_PORT */ + tid = txBegin(sb, COMMIT_FORCE); + + /* update the inode map addressing structure to point to it */ + if ((rc = + xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) { + /* Free the blocks allocated for the iag since it was + * not successfully added to the inode map + */ + dbFree(ipimap, xaddr, (s64) xlen); + + /* release the inode map lock */ + IWRITE_UNLOCK(ipimap); + + goto out; + } + + /* update the inode map's inode to reflect the extension */ + ipimap->i_size += PSIZE; + ipimap->i_blocks += LBLK2PBLK(sb, xlen); + + /* + * txCommit(COMMIT_FORCE) will synchronously write address + * index pages and inode after commit in careful update order + * of address index pages (right to left, bottom up); + */ + iplist[0] = ipimap; + rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); + + txEnd(tid); + + duplicateIXtree(sb, blkno, xlen, &xaddr); + + /* update the next avaliable iag number */ + imap->im_nextiag += 1; + + /* Add the iag to the iag free list so we don't lose the iag + * if a failure happens now. + */ + imap->im_freeiag = iagno; + + /* Until we have logredo working, we want the imap inode & + * control page to be up to date. + */ + diSync(ipimap); + + /* release the inode map lock */ + IWRITE_UNLOCK(ipimap); + } + + /* obtain read lock on map */ + IREAD_LOCK(ipimap); + + /* read the iag */ + if ((rc = diIAGRead(imap, iagno, &mp))) { + IREAD_UNLOCK(ipimap); + rc = EIO; + goto out; + } + iagp = (iag_t *) mp->data; + + /* remove the iag from the iag free list */ + imap->im_freeiag = le32_to_cpu(iagp->iagfree); + iagp->iagfree = -1; + + /* set the return iag number and buffer pointer */ + *iagnop = iagno; + *mpp = mp; + + out: + /* release the iag free lock */ + IAGFREE_UNLOCK(imap); + + return (rc); +} + +/* + * NAME: diIAGRead() + * + * FUNCTION: get the buffer for the specified iag within a fileset + * or aggregate inode map. + * + * PARAMETERS: + * imap - pointer to inode map control structure. + * iagno - iag number. + * bpp - point to buffer pointer to be filled in on successful + * exit. + * + * SERIALIZATION: + * must have read lock on imap inode + * (When called by diExtendFS, the filesystem is quiesced, therefore + * the read lock is unnecessary.) + * + * RETURN VALUES: + * 0 - success. + * EIO - i/o error. + */ +static int diIAGRead(imap_t * imap, int iagno, metapage_t ** mpp) +{ + struct inode *ipimap = imap->im_ipimap; + s64 blkno; + + /* compute the logical block number of the iag. */ + blkno = IAGTOLBLK(iagno, JFS_SBI(ipimap->i_sb)->l2nbperpage); + + /* read the iag. */ + *mpp = read_metapage(ipimap, blkno, PSIZE, 0); + if (*mpp == NULL) { + return (EIO); + } + + return (0); +} + +/* + * NAME: diFindFree() + * + * FUNCTION: find the first free bit in a word starting at + * the specified bit position. + * + * PARAMETERS: + * word - word to be examined. + * start - starting bit position. + * + * RETURN VALUES: + * bit position of first free bit in the word or 32 if + * no free bits were found. + */ +static int diFindFree(u32 word, int start) +{ + int bitno; + assert(start < 32); + /* scan the word for the first free bit. */ + for (word <<= start, bitno = start; bitno < 32; + bitno++, word <<= 1) { + if ((word & HIGHORDER) == 0) + break; + } + return (bitno); +} + +/* + * NAME: diUpdatePMap() + * + * FUNCTION: Update the persistent map in an IAG for the allocation or + * freeing of the specified inode. + * + * PRE CONDITIONS: Working map has already been updated for allocate. + * + * PARAMETERS: + * ipimap - Incore inode map inode + * inum - Number of inode to mark in permanent map + * is_free - If TRUE indicates inode should be marked freed, otherwise + * indicates inode should be marked allocated. + * + * RETURNS: 0 for success + */ +int +diUpdatePMap(struct inode *ipimap, + unsigned long inum, boolean_t is_free, tblock_t * tblk) +{ + int rc; + iag_t *iagp; + metapage_t *mp; + int iagno, ino, extno, bitno; + imap_t *imap; + u32 mask; + log_t *log; + int lsn, difft, diffp; + + imap = JFS_IP(ipimap)->i_imap; + /* get the iag number containing the inode */ + iagno = INOTOIAG(inum); + /* make sure that the iag is contained within the map */ + assert(iagno < imap->im_nextiag); + /* read the iag */ + IREAD_LOCK(ipimap); + rc = diIAGRead(imap, iagno, &mp); + IREAD_UNLOCK(ipimap); + if (rc) + return (rc); + iagp = (iag_t *) mp->data; + /* get the inode number and extent number of the inode within + * the iag and the inode number within the extent. + */ + ino = inum & (INOSPERIAG - 1); + extno = ino >> L2INOSPEREXT; + bitno = ino & (INOSPEREXT - 1); + mask = HIGHORDER >> bitno; + /* + * mark the inode free in persistent map: + */ + if (is_free == TRUE) { + /* The inode should have been allocated both in working + * map and in persistent map; + * the inode will be freed from working map at the release + * of last reference release; + */ +// assert(le32_to_cpu(iagp->wmap[extno]) & mask); + if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) { + jERROR(1, + ("diUpdatePMap: inode %ld not marked as allocated in wmap!\n", + inum)); + updateSuper(ipimap->i_sb, FM_DIRTY); + } +// assert(le32_to_cpu(iagp->pmap[extno]) & mask); + if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) { + jERROR(1, + ("diUpdatePMap: inode %ld not marked as allocated in pmap!\n", + inum)); + updateSuper(ipimap->i_sb, FM_DIRTY); + } + /* update the bitmap for the extent of the freed inode */ + iagp->pmap[extno] &= cpu_to_le32(~mask); + } + /* + * mark the inode allocated in persistent map: + */ + else { + /* The inode should be already allocated in the working map + * and should be free in persistent map; + */ + assert(le32_to_cpu(iagp->wmap[extno]) & mask); + assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0); + /* update the bitmap for the extent of the allocated inode */ + iagp->pmap[extno] |= cpu_to_le32(mask); + } + /* + * update iag lsn + */ + lsn = tblk->lsn; + log = JFS_SBI(tblk->sb)->log; + if (mp->lsn != 0) { + /* inherit older/smaller lsn */ + logdiff(difft, lsn, log); + logdiff(diffp, mp->lsn, log); + if (difft < diffp) { + mp->lsn = lsn; + /* move mp after tblock in logsync list */ + LOGSYNC_LOCK(log); + list_del(&mp->synclist); + list_add(&mp->synclist, &tblk->synclist); + LOGSYNC_UNLOCK(log); + } + /* inherit younger/larger clsn */ + LOGSYNC_LOCK(log); + assert(mp->clsn); + logdiff(difft, tblk->clsn, log); + logdiff(diffp, mp->clsn, log); + if (difft > diffp) + mp->clsn = tblk->clsn; + LOGSYNC_UNLOCK(log); + } else { + mp->log = log; + mp->lsn = lsn; + /* insert mp after tblock in logsync list */ + LOGSYNC_LOCK(log); + log->count++; + list_add(&mp->synclist, &tblk->synclist); + mp->clsn = tblk->clsn; + LOGSYNC_UNLOCK(log); + } +// bmLazyWrite(mp, log->flag & JFS_COMMIT); + write_metapage(mp); + return (0); +} + +/* + * diExtendFS() + * + * function: update imap for extendfs(); + * + * note: AG size has been increased s.t. each k old contiguous AGs are + * coalesced into a new AG; + */ +int diExtendFS(struct inode *ipimap, struct inode *ipbmap) +{ + int rc, rcx = 0; + imap_t *imap = JFS_IP(ipimap)->i_imap; + iag_t *iagp = 0, *hiagp = 0; + bmap_t *mp = JFS_SBI(ipbmap->i_sb)->bmap; + metapage_t *bp, *hbp; + int i, n, head; + int numinos, xnuminos = 0, xnumfree = 0; + s64 agstart; + + jEVENT(0, ("diExtendFS: nextiag:%d numinos:%d numfree:%d\n", + imap->im_nextiag, atomic_read(&imap->im_numinos), + atomic_read(&imap->im_numfree))); + + /* + * reconstruct imap + * + * coalesce contiguous k (newAGSize/oldAGSize) AGs; + * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn; + * note: new AG size = old AG size * (2**x). + */ + + /* init per AG control information im_agctl[] */ + for (i = 0; i < MAXAG; i++) { + imap->im_agctl[i].inofree = -1; /* free inode list */ + imap->im_agctl[i].extfree = -1; /* free extent list */ + imap->im_agctl[i].numinos = 0; /* number of backed inodes */ + imap->im_agctl[i].numfree = 0; /* number of free backed inodes */ + } + + /* + * process each iag_t page of the map. + * + * rebuild AG Free Inode List, AG Free Inode Extent List; + */ + for (i = 0; i < imap->im_nextiag; i++) { + if ((rc = diIAGRead(imap, i, &bp))) { + rcx = rc; + continue; + } + iagp = (iag_t *) bp->data; + assert(le32_to_cpu(iagp->iagnum) == i); + + /* leave free iag in the free iag list */ + if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) { + release_metapage(bp); + continue; + } + + /* agstart that computes to the same ag is treated as same; */ + agstart = le64_to_cpu(iagp->agstart); + /* iagp->agstart = agstart & ~(mp->db_agsize - 1); */ + n = agstart >> mp->db_agl2size; +/* +printf("diExtendFS: iag:%d agstart:%Ld agno:%d\n", i, agstart, n); +*/ + + /* compute backed inodes */ + numinos = (EXTSPERIAG - le32_to_cpu(iagp->nfreeexts)) + << L2INOSPEREXT; + if (numinos > 0) { + /* merge AG backed inodes */ + imap->im_agctl[n].numinos += numinos; + xnuminos += numinos; + } + + /* if any backed free inodes, insert at AG free inode list */ + if ((int) le32_to_cpu(iagp->nfreeinos) > 0) { + if ((head = imap->im_agctl[n].inofree) == -1) + iagp->inofreefwd = iagp->inofreeback = -1; + else { + if ((rc = diIAGRead(imap, head, &hbp))) { + rcx = rc; + goto nextiag; + } + hiagp = (iag_t *) hbp->data; + hiagp->inofreeback = + le32_to_cpu(iagp->iagnum); + iagp->inofreefwd = cpu_to_le32(head); + iagp->inofreeback = -1; + write_metapage(hbp); + } + + imap->im_agctl[n].inofree = + le32_to_cpu(iagp->iagnum); + + /* merge AG backed free inodes */ + imap->im_agctl[n].numfree += + le32_to_cpu(iagp->nfreeinos); + xnumfree += le32_to_cpu(iagp->nfreeinos); + } + + /* if any free extents, insert at AG free extent list */ + if (le32_to_cpu(iagp->nfreeexts) > 0) { + if ((head = imap->im_agctl[n].extfree) == -1) + iagp->extfreefwd = iagp->extfreeback = -1; + else { + if ((rc = diIAGRead(imap, head, &hbp))) { + rcx = rc; + goto nextiag; + } + hiagp = (iag_t *) hbp->data; + hiagp->extfreeback = iagp->iagnum; + iagp->extfreefwd = cpu_to_le32(head); + iagp->extfreeback = -1; + write_metapage(hbp); + } + + imap->im_agctl[n].extfree = + le32_to_cpu(iagp->iagnum); + } + + nextiag: + write_metapage(bp); + } + + ASSERT(xnuminos == atomic_read(&imap->im_numinos) && + xnumfree == atomic_read(&imap->im_numfree)); + + return rcx; +} + + +/* + * duplicateIXtree() + * + * serialization: IWRITE_LOCK held on entry/exit + * + * note: shadow page with regular inode (rel.2); + */ +static void +duplicateIXtree(struct super_block *sb, s64 blkno, int xlen, s64 * xaddr) +{ + int rc; + tid_t tid; + struct inode *ip; + metapage_t *mpsuper; + struct jfs_superblock *j_sb; + + /* if AIT2 ipmap2 is bad, do not try to update it */ + if (JFS_SBI(sb)->mntflag & JFS_BAD_SAIT) /* s_flag */ + return; + ip = diReadSpecial(sb, FILESYSTEM_I, 1); + if (ip == 0) { + JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT; + if ((rc = readSuper(sb, &mpsuper))) + return; + j_sb = (struct jfs_superblock *) (mpsuper->data); + j_sb->s_flag |= JFS_BAD_SAIT; + write_metapage(mpsuper); + return; + } + + /* start transaction */ + tid = txBegin(sb, COMMIT_FORCE); + /* update the inode map addressing structure to point to it */ + if ((rc = xtInsert(tid, ip, 0, blkno, xlen, xaddr, 0))) { + JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT; + txAbort(tid, 1); + goto cleanup; + + } + /* update the inode map's inode to reflect the extension */ + ip->i_size += PSIZE; + ip->i_blocks += LBLK2PBLK(sb, xlen); + rc = txCommit(tid, 1, &ip, COMMIT_FORCE); + cleanup: + txEnd(tid); + diFreeSpecial(ip); +} + +/* + * NAME: copy_from_dinode() + * + * FUNCTION: Copies inode info from disk inode to in-memory inode + * + * RETURN VALUES: + * 0 - success + * ENOMEM - insufficient memory + */ +static int copy_from_dinode(dinode_t * dip, struct inode *ip) +{ + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + + jfs_ip->fileset = le32_to_cpu(dip->di_fileset); + jfs_ip->mode2 = le32_to_cpu(dip->di_mode); + + ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff; + ip->i_nlink = le32_to_cpu(dip->di_nlink); + ip->i_uid = le32_to_cpu(dip->di_uid); + ip->i_gid = le32_to_cpu(dip->di_gid); + ip->i_size = le64_to_cpu(dip->di_size); + ip->i_atime = le32_to_cpu(dip->di_atime.tv_sec); + ip->i_mtime = le32_to_cpu(dip->di_mtime.tv_sec); + ip->i_ctime = le32_to_cpu(dip->di_ctime.tv_sec); + ip->i_blksize = ip->i_sb->s_blocksize; + ip->i_blocks = LBLK2PBLK(ip->i_sb, le64_to_cpu(dip->di_nblocks)); + ip->i_generation = le32_to_cpu(dip->di_gen); + + jfs_ip->ixpxd = dip->di_ixpxd; /* in-memory pxd's are little-endian */ + jfs_ip->acl = dip->di_acl; /* as are dxd's */ + jfs_ip->ea = dip->di_ea; + jfs_ip->next_index = le32_to_cpu(dip->di_next_index); + jfs_ip->otime = le32_to_cpu(dip->di_otime.tv_sec); + jfs_ip->acltype = le32_to_cpu(dip->di_acltype); + /* + * We may only need to do this for "special" inodes (dmap, imap) + */ + if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) + ip->i_rdev = to_kdev_t(le32_to_cpu(dip->di_rdev)); + else if (S_ISDIR(ip->i_mode)) { + memcpy(&jfs_ip->i_dirtable, &dip->di_dirtable, 384); + } else if (!S_ISFIFO(ip->i_mode)) { + memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288); + } + /* Zero the in-memory-only stuff */ + jfs_ip->cflag = 0; + jfs_ip->btindex = 0; + jfs_ip->btorder = 0; + jfs_ip->bxflag = 0; + jfs_ip->blid = 0; + jfs_ip->atlhead = 0; + jfs_ip->atltail = 0; + jfs_ip->xtlid = 0; + return (0); +} + +/* + * NAME: copy_to_dinode() + * + * FUNCTION: Copies inode info from in-memory inode to disk inode + */ +static void copy_to_dinode(dinode_t * dip, struct inode *ip) +{ + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + + dip->di_fileset = cpu_to_le32(jfs_ip->fileset); + dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp); + dip->di_number = cpu_to_le32(ip->i_ino); + dip->di_gen = cpu_to_le32(ip->i_generation); + dip->di_size = cpu_to_le64(ip->i_size); + dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks)); + dip->di_nlink = cpu_to_le32(ip->i_nlink); + dip->di_uid = cpu_to_le32(ip->i_uid); + dip->di_gid = cpu_to_le32(ip->i_gid); + /* + * mode2 is only needed for storing the higher order bits. + * Trust i_mode for the lower order ones + */ + dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | ip->i_mode); + dip->di_atime.tv_sec = cpu_to_le32(ip->i_atime); + dip->di_atime.tv_nsec = 0; + dip->di_ctime.tv_sec = cpu_to_le32(ip->i_ctime); + dip->di_ctime.tv_nsec = 0; + dip->di_mtime.tv_sec = cpu_to_le32(ip->i_mtime); + dip->di_mtime.tv_nsec = 0; + dip->di_ixpxd = jfs_ip->ixpxd; /* in-memory pxd's are little-endian */ + dip->di_acl = jfs_ip->acl; /* as are dxd's */ + dip->di_ea = jfs_ip->ea; + dip->di_next_index = cpu_to_le32(jfs_ip->next_index); + dip->di_otime.tv_sec = cpu_to_le32(jfs_ip->otime); + dip->di_otime.tv_nsec = 0; + dip->di_acltype = cpu_to_le32(jfs_ip->acltype); + + if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) + dip->di_rdev = cpu_to_le32(kdev_t_to_nr(ip->i_rdev)); +} + +#ifdef _JFS_DEBUG_IMAP +/* + * DBGdiInit() + */ +static void *DBGdiInit(imap_t * imap) +{ + u32 *dimap; + int size; + size = 64 * 1024; + if ((dimap = (u32 *) xmalloc(size, L2PSIZE, kernel_heap)) == NULL) + assert(0); + bzero((void *) dimap, size); + imap->im_DBGdimap = dimap; +} + +/* + * DBGdiAlloc() + */ +static void DBGdiAlloc(imap_t * imap, ino_t ino) +{ + u32 *dimap = imap->im_DBGdimap; + int w, b; + u32 m; + w = ino >> 5; + b = ino & 31; + m = 0x80000000 >> b; + assert(w < 64 * 256); + if (dimap[w] & m) { + printk("DEBUG diAlloc: duplicate alloc ino:0x%x\n", ino); + } + dimap[w] |= m; +} + +/* + * DBGdiFree() + */ +static void DBGdiFree(imap_t * imap, ino_t ino) +{ + u32 *dimap = imap->im_DBGdimap; + int w, b; + u32 m; + w = ino >> 5; + b = ino & 31; + m = 0x80000000 >> b; + assert(w < 64 * 256); + if ((dimap[w] & m) == 0) { + printk("DEBUG diFree: duplicate free ino:0x%x\n", ino); + } + dimap[w] &= ~m; +} + +static void dump_cp(imap_t * ipimap, char *function, int line) +{ + printk("\n* ********* *\nControl Page %s %d\n", function, line); + printk("FreeIAG %d\tNextIAG %d\n", ipimap->im_freeiag, + ipimap->im_nextiag); + printk("NumInos %d\tNumFree %d\n", + atomic_read(&ipimap->im_numinos), + atomic_read(&ipimap->im_numfree)); + printk("AG InoFree %d\tAG ExtFree %d\n", + ipimap->im_agctl[0].inofree, ipimap->im_agctl[0].extfree); + printk("AG NumInos %d\tAG NumFree %d\n", + ipimap->im_agctl[0].numinos, ipimap->im_agctl[0].numfree); +} + +static void dump_iag(iag_t * iag, char *function, int line) +{ + printk("\n* ********* *\nIAG %s %d\n", function, line); + printk("IagNum %d\tIAG Free %d\n", le32_to_cpu(iag->iagnum), + le32_to_cpu(iag->iagfree)); + printk("InoFreeFwd %d\tInoFreeBack %d\n", + le32_to_cpu(iag->inofreefwd), + le32_to_cpu(iag->inofreeback)); + printk("ExtFreeFwd %d\tExtFreeBack %d\n", + le32_to_cpu(iag->extfreefwd), + le32_to_cpu(iag->extfreeback)); + printk("NFreeInos %d\tNFreeExts %d\n", le32_to_cpu(iag->nfreeinos), + le32_to_cpu(iag->nfreeexts)); +} +#endif /* _JFS_DEBUG_IMAP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_imap.h linux.20pre2-ac1/fs/jfs/jfs_imap.h --- linux.20pre2/fs/jfs/jfs_imap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_imap.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,157 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 _H_JFS_IMAP +#define _H_JFS_IMAP + +#include "jfs_txnmgr.h" + +/* + * jfs_imap.h: disk inode manager + */ + +#define EXTSPERIAG 128 /* number of disk inode extent per iag */ +#define IMAPBLKNO 0 /* lblkno of dinomap within inode map */ +#define SMAPSZ 4 /* number of words per summary map */ +#define EXTSPERSUM 32 /* number of extents per summary map entry */ +#define L2EXTSPERSUM 5 /* l2 number of extents per summary map */ +#define PGSPERIEXT 4 /* number of 4K pages per dinode extent */ +#define MAXIAGS ((1<<20)-1) /* maximum number of iags */ +#define MAXAG 128 /* maximum number of allocation groups */ + +#define AMAPSIZE 512 /* bytes in the IAG allocation maps */ +#define SMAPSIZE 16 /* bytes in the IAG summary maps */ + +/* convert inode number to iag number */ +#define INOTOIAG(ino) ((ino) >> L2INOSPERIAG) + +/* convert iag number to logical block number of the iag page */ +#define IAGTOLBLK(iagno,l2nbperpg) (((iagno) + 1) << (l2nbperpg)) + +/* get the starting block number of the 4K page of an inode extent + * that contains ino. + */ +#define INOPBLK(pxd,ino,l2nbperpg) (addressPXD((pxd)) + \ + ((((ino) & (INOSPEREXT-1)) >> L2INOSPERPAGE) << (l2nbperpg))) + +/* + * inode allocation map: + * + * inode allocation map consists of + * . the inode map control page and + * . inode allocation group pages (per 4096 inodes) + * which are addressed by standard JFS xtree. + */ +/* + * inode allocation group page (per 4096 inodes of an AG) + */ +typedef struct { + s64 agstart; /* 8: starting block of ag */ + s32 iagnum; /* 4: inode allocation group number */ + s32 inofreefwd; /* 4: ag inode free list forward */ + s32 inofreeback; /* 4: ag inode free list back */ + s32 extfreefwd; /* 4: ag inode extent free list forward */ + s32 extfreeback; /* 4: ag inode extent free list back */ + s32 iagfree; /* 4: iag free list */ + + /* summary map: 1 bit per inode extent */ + s32 inosmap[SMAPSZ]; /* 16: sum map of mapwords w/ free inodes; + * note: this indicates free and backed + * inodes, if the extent is not backed the + * value will be 1. if the extent is + * backed but all inodes are being used the + * value will be 1. if the extent is + * backed but at least one of the inodes is + * free the value will be 0. + */ + s32 extsmap[SMAPSZ]; /* 16: sum map of mapwords w/ free extents */ + s32 nfreeinos; /* 4: number of free inodes */ + s32 nfreeexts; /* 4: number of free extents */ + /* (72) */ + u8 pad[1976]; /* 1976: pad to 2048 bytes */ + /* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */ + u32 wmap[EXTSPERIAG]; /* 512: working allocation map */ + u32 pmap[EXTSPERIAG]; /* 512: persistent allocation map */ + pxd_t inoext[EXTSPERIAG]; /* 1024: inode extent addresses */ +} iag_t; /* (4096) */ + +/* + * per AG control information (in inode map control page) + */ +typedef struct { + s32 inofree; /* 4: free inode list anchor */ + s32 extfree; /* 4: free extent list anchor */ + s32 numinos; /* 4: number of backed inodes */ + s32 numfree; /* 4: number of free inodes */ +} iagctl_t; /* (16) */ + +/* + * per fileset/aggregate inode map control page + */ +typedef struct { + s32 in_freeiag; /* 4: free iag list anchor */ + s32 in_nextiag; /* 4: next free iag number */ + s32 in_numinos; /* 4: num of backed inodes */ + s32 in_numfree; /* 4: num of free backed inodes */ + s32 in_nbperiext; /* 4: num of blocks per inode extent */ + s32 in_l2nbperiext; /* 4: l2 of in_nbperiext */ + s32 in_diskblock; /* 4: for standalone test driver */ + s32 in_maxag; /* 4: for standalone test driver */ + u8 pad[2016]; /* 2016: pad to 2048 */ + iagctl_t in_agctl[MAXAG]; /* 2048: AG control information */ +} dinomap_t; /* (4096) */ + + +/* + * In-core inode map control page + */ +typedef struct inomap { + dinomap_t im_imap; /* 4096: inode allocation control */ + struct inode *im_ipimap; /* 4: ptr to inode for imap */ + struct semaphore im_freelock; /* 4: iag free list lock */ + struct semaphore im_aglock[MAXAG]; /* 512: per AG locks */ + u32 *im_DBGdimap; + atomic_t im_numinos; /* num of backed inodes */ + atomic_t im_numfree; /* num of free backed inodes */ +} imap_t; + +#define im_freeiag im_imap.in_freeiag +#define im_nextiag im_imap.in_nextiag +#define im_agctl im_imap.in_agctl +#define im_nbperiext im_imap.in_nbperiext +#define im_l2nbperiext im_imap.in_l2nbperiext + +/* for standalone testdriver + */ +#define im_diskblock im_imap.in_diskblock +#define im_maxag im_imap.in_maxag + +extern int diFree(struct inode *); +extern int diAlloc(struct inode *, boolean_t, struct inode *); +extern int diSync(struct inode *); +/* external references */ +extern int diUpdatePMap(struct inode *ipimap, unsigned long inum, + boolean_t is_free, tblock_t * tblk); +extern int diExtendFS(struct inode *ipimap, struct inode *ipbmap); +extern int diMount(struct inode *); +extern int diUnmount(struct inode *, int); +extern int diRead(struct inode *); +extern struct inode *diReadSpecial(struct super_block *, ino_t, int); +extern void diWriteSpecial(struct inode *, int); +extern void diFreeSpecial(struct inode *); +extern int diWrite(tid_t tid, struct inode *); +#endif /* _H_JFS_IMAP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_incore.h linux.20pre2-ac1/fs/jfs/jfs_incore.h --- linux.20pre2/fs/jfs/jfs_incore.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_incore.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,181 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 _H_JFS_INCORE +#define _H_JFS_INCORE + +#include +#include +#include +#include "jfs_types.h" +#include "jfs_xtree.h" +#include "jfs_dtree.h" + +/* + * JFS magic number + */ +#define JFS_SUPER_MAGIC 0x3153464a /* "JFS1" */ + +/* + * JFS-private inode information + */ +struct jfs_inode_info { + struct inode *inode; /* pointer back to fs-independent inode */ + int fileset; /* fileset number (always 16)*/ + uint mode2; /* jfs-specific mode */ + pxd_t ixpxd; /* inode extent descriptor */ + dxd_t acl; /* dxd describing acl */ + dxd_t ea; /* dxd describing ea */ + time_t otime; /* time created */ + uint next_index; /* next available directory entry index */ + int acltype; /* Type of ACL */ + short btorder; /* access order */ + short btindex; /* btpage entry index*/ + struct inode *ipimap; /* inode map */ + long cflag; /* commit flags */ + u16 bxflag; /* xflag of pseudo buffer? */ + unchar agno; /* ag number */ + unchar pad; /* pad */ + lid_t blid; /* lid of pseudo buffer? */ + lid_t atlhead; /* anonymous tlock list head */ + lid_t atltail; /* anonymous tlock list tail */ + struct list_head anon_inode_list; /* inodes having anonymous txns */ + struct list_head mp_list; /* metapages in inode's address space */ + /* + * rdwrlock serializes xtree between reads & writes and synchronizes + * changes to special inodes. It's use would be redundant on + * directories since the i_sem taken in the VFS is sufficient. + */ + struct rw_semaphore rdwrlock; + /* + * commit_sem serializes transaction processing on an inode. + * It must be taken after beginning a transaction (txBegin), since + * dirty inodes may be committed while a new transaction on the + * inode is blocked in txBegin or TxBeginAnon + */ + struct semaphore commit_sem; + lid_t xtlid; /* lid of xtree lock on directory */ + union { + struct { + xtpage_t _xtroot; /* 288: xtree root */ + struct inomap *_imap; /* 4: inode map header */ + } file; + struct { + dir_table_slot_t _table[12]; /* 96: directory index */ + dtroot_t _dtroot; /* 288: dtree root */ + } dir; + struct { + unchar _unused[16]; /* 16: */ + dxd_t _dxd; /* 16: */ + unchar _inline[128]; /* 128: inline symlink */ + } link; + } u; +}; +#define i_xtroot u.file._xtroot +#define i_imap u.file._imap +#define i_dirtable u.dir._table +#define i_dtroot u.dir._dtroot +#define i_inline u.link._inline + + +#define IREAD_LOCK(ip) down_read(&JFS_IP(ip)->rdwrlock) +#define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock) +#define IWRITE_LOCK(ip) down_write(&JFS_IP(ip)->rdwrlock) +#define IWRITE_UNLOCK(ip) up_write(&JFS_IP(ip)->rdwrlock) + +/* + * cflag + */ +enum cflags { + COMMIT_New, /* never committed inode */ + COMMIT_Nolink, /* inode committed with zero link count */ + COMMIT_Inlineea, /* commit inode inline EA */ + COMMIT_Freewmap, /* free WMAP at iClose() */ + COMMIT_Dirty, /* Inode is really dirty */ + COMMIT_Holdlock, /* Hold the IWRITE_LOCK until commit is done */ + COMMIT_Dirtable, /* commit changes to di_dirtable */ + COMMIT_Stale, /* data extent is no longer valid */ + COMMIT_Synclist, /* metadata pages on group commit synclist */ +}; + +#define set_cflag(flag, ip) set_bit(flag, &(JFS_IP(ip)->cflag)) +#define clear_cflag(flag, ip) clear_bit(flag, &(JFS_IP(ip)->cflag)) +#define test_cflag(flag, ip) test_bit(flag, &(JFS_IP(ip)->cflag)) +#define test_and_clear_cflag(flag, ip) \ + test_and_clear_bit(flag, &(JFS_IP(ip)->cflag)) +/* + * JFS-private superblock information. + */ +struct jfs_sb_info { + unsigned long mntflag; /* 4: aggregate attributes */ + struct inode *ipbmap; /* 4: block map inode */ + struct inode *ipaimap; /* 4: aggregate inode map inode */ + struct inode *ipaimap2; /* 4: secondary aimap inode */ + struct inode *ipimap; /* 4: aggregate inode map inode */ + struct jfs_log *log; /* 4: log */ + short bsize; /* 2: logical block size */ + short l2bsize; /* 2: log2 logical block size */ + short nbperpage; /* 2: blocks per page */ + short l2nbperpage; /* 2: log2 blocks per page */ + short l2niperblk; /* 2: log2 inodes per page */ + kdev_t logdev; /* 2: external log device */ + uint aggregate; /* volume identifier in log record */ + pxd_t logpxd; /* 8: pxd describing log */ + pxd_t fsckpxd; /* 8: pxd describing fsck wkspc */ + pxd_t ait2; /* 8: pxd describing AIT copy */ + char uuid[16]; /* 16: 128-bit uuid for volume */ + char loguuid[16]; /* 16: 128-bit uuid for log */ + /* Formerly in ipimap */ + uint gengen; /* 4: inode generation generator*/ + uint inostamp; /* 4: shows inode belongs to fileset*/ + + /* Formerly in ipbmap */ + struct bmap *bmap; /* 4: incore bmap descriptor */ + struct nls_table *nls_tab; /* 4: current codepage */ + struct inode *direct_inode; /* 4: inode for physical I/O */ + struct address_space *direct_mapping; /* 4: mapping for physical I/O */ + uint state; /* 4: mount/recovery state */ +}; + +static inline struct jfs_inode_info *JFS_IP(struct inode *inode) +{ + return inode->u.generic_ip; +} + +static inline struct jfs_sb_info *JFS_SBI(struct super_block *sb) +{ + return sb->u.generic_sbp; +} + +static inline int isReadOnly(struct inode *inode) +{ + if (JFS_SBI(inode->i_sb)->log) + return 0; + return 1; +} + +/* + * Allocating and freeing the structure + */ +extern kmem_cache_t *jfs_inode_cachep; +extern int alloc_jfs_inode(struct inode *); + +#define free_jfs_inode(inode) \ + kmem_cache_free(jfs_inode_cachep, (inode)->u.generic_ip) + +#endif /* _H_JFS_INCORE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_inode.c linux.20pre2-ac1/fs/jfs/jfs_inode.c --- linux.20pre2/fs/jfs/jfs_inode.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_inode.c 2002-08-06 17:59:43.000000000 +0100 @@ -0,0 +1,121 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_imap.h" +#include "jfs_dinode.h" +#include "jfs_debug.h" + +kmem_cache_t *jfs_inode_cachep; + +/* + * NAME: ialloc() + * + * FUNCTION: Allocate a new inode + * + */ +struct inode *ialloc(struct inode *parent, umode_t mode) +{ + struct super_block *sb = parent->i_sb; + struct inode *inode; + struct jfs_inode_info *jfs_inode; + int rc; + + inode = new_inode(sb); + if (!inode) { + jERROR(1, ("ialloc: new_inode returned NULL!\n")); + return inode; + } + + rc = alloc_jfs_inode(inode); + if (rc) { + make_bad_inode(inode); + iput(inode); + return NULL; + } + jfs_inode = JFS_IP(inode); + + rc = diAlloc(parent, S_ISDIR(mode), inode); + if (rc) { + jERROR(1, ("ialloc: diAlloc returned %d!\n", rc)); + free_jfs_inode(inode); + make_bad_inode(inode); + iput(inode); + return NULL; + } + + inode->i_uid = current->fsuid; + if (parent->i_mode & S_ISGID) { + inode->i_gid = parent->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else + inode->i_gid = current->fsgid; + + inode->i_mode = mode; + if (S_ISDIR(mode)) + jfs_inode->mode2 = IDIRECTORY | mode; + else + jfs_inode->mode2 = INLINEEA | ISPARSE | mode; + inode->i_blksize = sb->s_blocksize; + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + jfs_inode->otime = inode->i_ctime; + inode->i_generation = JFS_SBI(sb)->gengen++; + + jfs_inode->cflag = 0; + set_cflag(COMMIT_New, inode); + + /* Zero remaining fields */ + memset(&jfs_inode->acl, 0, sizeof(dxd_t)); + memset(&jfs_inode->ea, 0, sizeof(dxd_t)); + jfs_inode->next_index = 0; + jfs_inode->acltype = 0; + jfs_inode->btorder = 0; + jfs_inode->btindex = 0; + jfs_inode->bxflag = 0; + jfs_inode->blid = 0; + jfs_inode->atlhead = 0; + jfs_inode->atltail = 0; + jfs_inode->xtlid = 0; + + jFYI(1, ("ialloc returns inode = 0x%p\n", inode)); + + return inode; +} + +/* + * NAME: alloc_jfs_inode() + * + * FUNCTION: Allocate jfs portion of in-memory inode + * + */ +int alloc_jfs_inode(struct inode *inode) +{ + struct jfs_inode_info *jfs_inode; + + jfs_inode = kmem_cache_alloc(jfs_inode_cachep, GFP_NOFS); + inode->u.generic_ip = jfs_inode; + if (!jfs_inode) + return -ENOSPC; + jfs_inode->inode = inode; + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_inode.h linux.20pre2-ac1/fs/jfs/jfs_inode.h --- linux.20pre2/fs/jfs/jfs_inode.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_inode.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,23 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2001 + * + * 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 _H_JFS_INODE +#define _H_JFS_INODE + +extern struct inode *ialloc(struct inode *, umode_t); + +#endif /* _H_JFS_INODE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_lock.h linux.20pre2-ac1/fs/jfs/jfs_lock.h --- linux.20pre2/fs/jfs/jfs_lock.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_lock.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2001 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 _H_JFS_LOCK +#define _H_JFS_LOCK + +#include +#include + +/* + * jfs_lock.h + */ + +/* + * Conditional sleep where condition is protected by spinlock + * + * lock_cmd and unlock_cmd take and release the spinlock + */ +#define __SLEEP_COND(wq, cond, lock_cmd, unlock_cmd) \ +do { \ + DECLARE_WAITQUEUE(__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_UNINTERRUPTIBLE);\ + if (cond) \ + break; \ + unlock_cmd; \ + schedule(); \ + lock_cmd; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#endif /* _H_JFS_LOCK */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_logmgr.c linux.20pre2-ac1/fs/jfs/jfs_logmgr.c --- linux.20pre2/fs/jfs/jfs_logmgr.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_logmgr.c 2002-08-06 18:01:05.000000000 +0100 @@ -0,0 +1,2289 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 + */ + +/* + * jfs_logmgr.c: log manager + * + * for related information, see transaction manager (jfs_txnmgr.c), and + * recovery manager (jfs_logredo.c). + * + * note: for detail, RTFS. + * + * log buffer manager: + * special purpose buffer manager supporting log i/o requirements. + * per log serial pageout of logpage + * queuing i/o requests and redrive i/o at iodone + * maintain current logpage buffer + * no caching since append only + * appropriate jfs buffer cache buffers as needed + * + * group commit: + * transactions which wrote COMMIT records in the same in-memory + * log page during the pageout of previous/current log page(s) are + * committed together by the pageout of the page. + * + * TBD lazy commit: + * transactions are committed asynchronously when the log page + * containing it COMMIT is paged out when it becomes full; + * + * serialization: + * . a per log lock serialize log write. + * . a per log lock serialize group commit. + * . a per log lock serialize log open/close; + * + * TBD log integrity: + * careful-write (ping-pong) of last logpage to recover from crash + * in overwrite. + * detection of split (out-of-order) write of physical sectors + * of last logpage via timestamp at end of each sector + * with its mirror data array at trailer). + * + * alternatives: + * lsn - 64-bit monotonically increasing integer vs + * 32-bit lspn and page eor. + */ + +#include +#include +#include +#include +#include +#include +#include "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_metapage.h" +#include "jfs_txnmgr.h" +#include "jfs_debug.h" + + +/* + * lbuf's ready to be redriven. Protected by log_redrive_lock (jfsIO thread) + */ +static lbuf_t *log_redrive_list; +static spinlock_t log_redrive_lock = SPIN_LOCK_UNLOCKED; +DECLARE_WAIT_QUEUE_HEAD(jfs_IO_thread_wait); + + +/* + * log read/write serialization (per log) + */ +#define LOG_LOCK_INIT(log) init_MUTEX(&(log)->loglock) +#define LOG_LOCK(log) down(&((log)->loglock)) +#define LOG_UNLOCK(log) up(&((log)->loglock)) + + +/* + * log group commit serialization (per log) + */ + +#define LOGGC_LOCK_INIT(log) spin_lock_init(&(log)->gclock) +#define LOGGC_LOCK(log) spin_lock_irq(&(log)->gclock) +#define LOGGC_UNLOCK(log) spin_unlock_irq(&(log)->gclock) +#define LOGGC_WAKEUP(tblk) wake_up(&(tblk)->gcwait) + +/* + * log sync serialization (per log) + */ +#define LOGSYNC_DELTA(logsize) min((logsize)/8, 128*LOGPSIZE) +#define LOGSYNC_BARRIER(logsize) ((logsize)/4) +/* +#define LOGSYNC_DELTA(logsize) min((logsize)/4, 256*LOGPSIZE) +#define LOGSYNC_BARRIER(logsize) ((logsize)/2) +*/ + + +/* + * log buffer cache synchronization + */ +static spinlock_t jfsLCacheLock = SPIN_LOCK_UNLOCKED; + +#define LCACHE_LOCK(flags) spin_lock_irqsave(&jfsLCacheLock, flags) +#define LCACHE_UNLOCK(flags) spin_unlock_irqrestore(&jfsLCacheLock, flags) + +/* + * See __SLEEP_COND in jfs_locks.h + */ +#define LCACHE_SLEEP_COND(wq, cond, flags) \ +do { \ + if (cond) \ + break; \ + __SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \ +} while (0) + +#define LCACHE_WAKEUP(event) wake_up(event) + + +/* + * lbuf buffer cache (lCache) control + */ +/* log buffer manager pageout control (cumulative, inclusive) */ +#define lbmREAD 0x0001 +#define lbmWRITE 0x0002 /* enqueue at tail of write queue; + * init pageout if at head of queue; + */ +#define lbmRELEASE 0x0004 /* remove from write queue + * at completion of pageout; + * do not free/recycle it yet: + * caller will free it; + */ +#define lbmSYNC 0x0008 /* do not return to freelist + * when removed from write queue; + */ +#define lbmFREE 0x0010 /* return to freelist + * at completion of pageout; + * the buffer may be recycled; + */ +#define lbmDONE 0x0020 +#define lbmERROR 0x0040 +#define lbmGC 0x0080 /* lbmIODone to perform post-GC processing + * of log page + */ +#define lbmDIRECT 0x0100 + +/* + * external references + */ +extern void txLazyUnlock(tblock_t * tblk); +extern int jfs_stop_threads; +extern struct completion jfsIOwait; + +/* + * forward references + */ +static int lmWriteRecord(log_t * log, tblock_t * tblk, lrd_t * lrd, + tlock_t * tlck); + +static int lmNextPage(log_t * log); +static int lmLogFileSystem(log_t * log, char *uuid, int activate); + +static int lbmLogInit(log_t * log); +static void lbmLogShutdown(log_t * log); +static lbuf_t *lbmAllocate(log_t * log, int); +static void lbmFree(lbuf_t * bp); +static void lbmfree(lbuf_t * bp); +static int lbmRead(log_t * log, int pn, lbuf_t ** bpp); +static void lbmWrite(log_t * log, lbuf_t * bp, int flag, int cant_block); +static void lbmDirectWrite(log_t * log, lbuf_t * bp, int flag); +static int lbmIOWait(lbuf_t * bp, int flag); +static void lbmIODone(struct buffer_head *bh, int); + +void lbmStartIO(lbuf_t * bp); +void lmGCwrite(log_t * log, int cant_block); + + +/* + * statistics + */ +#ifdef CONFIG_JFS_STATISTICS +struct lmStat { + uint commit; /* # of commit */ + uint pagedone; /* # of page written */ + uint submitted; /* # of pages submitted */ +} lmStat; +#endif + + +/* + * NAME: lmLog() + * + * FUNCTION: write a log record; + * + * PARAMETER: + * + * RETURN: lsn - offset to the next log record to write (end-of-log); + * -1 - error; + * + * note: todo: log error handler + */ +int lmLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck) +{ + int lsn; + int diffp, difft; + metapage_t *mp = NULL; + + jFYI(1, ("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p\n", + log, tblk, lrd, tlck)); + + LOG_LOCK(log); + + /* log by (out-of-transaction) JFS ? */ + if (tblk == NULL) + goto writeRecord; + + /* log from page ? */ + if (tlck == NULL || + tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL) + goto writeRecord; + + /* + * initialize/update page/transaction recovery lsn + */ + lsn = log->lsn; + + LOGSYNC_LOCK(log); + + /* + * initialize page lsn if first log write of the page + */ + if (mp->lsn == 0) { + mp->log = log; + mp->lsn = lsn; + log->count++; + + /* insert page at tail of logsynclist */ + list_add_tail(&mp->synclist, &log->synclist); + } + + /* + * initialize/update lsn of tblock of the page + * + * transaction inherits oldest lsn of pages associated + * with allocation/deallocation of resources (their + * log records are used to reconstruct allocation map + * at recovery time: inode for inode allocation map, + * B+-tree index of extent descriptors for block + * allocation map); + * allocation map pages inherit transaction lsn at + * commit time to allow forwarding log syncpt past log + * records associated with allocation/deallocation of + * resources only after persistent map of these map pages + * have been updated and propagated to home. + */ + /* + * initialize transaction lsn: + */ + if (tblk->lsn == 0) { + /* inherit lsn of its first page logged */ + tblk->lsn = mp->lsn; + log->count++; + + /* insert tblock after the page on logsynclist */ + list_add(&tblk->synclist, &mp->synclist); + } + /* + * update transaction lsn: + */ + else { + /* inherit oldest/smallest lsn of page */ + logdiff(diffp, mp->lsn, log); + logdiff(difft, tblk->lsn, log); + if (diffp < difft) { + /* update tblock lsn with page lsn */ + tblk->lsn = mp->lsn; + + /* move tblock after page on logsynclist */ + list_del(&tblk->synclist); + list_add(&tblk->synclist, &mp->synclist); + } + } + + LOGSYNC_UNLOCK(log); + + /* + * write the log record + */ + writeRecord: + lsn = lmWriteRecord(log, tblk, lrd, tlck); + + /* + * forward log syncpt if log reached next syncpt trigger + */ + logdiff(diffp, lsn, log); + if (diffp >= log->nextsync) + lsn = lmLogSync(log, 0); + + /* update end-of-log lsn */ + log->lsn = lsn; + + LOG_UNLOCK(log); + + /* return end-of-log address */ + return lsn; +} + + +/* + * NAME: lmWriteRecord() + * + * FUNCTION: move the log record to current log page + * + * PARAMETER: cd - commit descriptor + * + * RETURN: end-of-log address + * + * serialization: LOG_LOCK() held on entry/exit + */ +static int +lmWriteRecord(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck) +{ + int lsn = 0; /* end-of-log address */ + lbuf_t *bp; /* dst log page buffer */ + logpage_t *lp; /* dst log page */ + caddr_t dst; /* destination address in log page */ + int dstoffset; /* end-of-log offset in log page */ + int freespace; /* free space in log page */ + caddr_t p; /* src meta-data page */ + caddr_t src; + int srclen; + int nbytes; /* number of bytes to move */ + int i; + int len; + linelock_t *linelock; + lv_t *lv; + lvd_t *lvd; + int l2linesize; + + len = 0; + + /* retrieve destination log page to write */ + bp = (lbuf_t *) log->bp; + lp = (logpage_t *) bp->l_ldata; + dstoffset = log->eor; + + /* any log data to write ? */ + if (tlck == NULL) + goto moveLrd; + + /* + * move log record data + */ + /* retrieve source meta-data page to log */ + if (tlck->flag & tlckPAGELOCK) { + p = (caddr_t) (tlck->mp->data); + linelock = (linelock_t *) & tlck->lock; + } + /* retrieve source in-memory inode to log */ + else if (tlck->flag & tlckINODELOCK) { + if (tlck->type & tlckDTREE) + p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot; + else + p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot; + linelock = (linelock_t *) & tlck->lock; + } +#ifdef _JFS_WIP + else if (tlck->flag & tlckINLINELOCK) { + + inlinelock = (inlinelock_t *) & tlck; + p = (caddr_t) & inlinelock->pxd; + linelock = (linelock_t *) & tlck; + } +#endif /* _JFS_WIP */ + else { + jERROR(2, ("lmWriteRecord: UFO tlck:0x%p\n", tlck)); + return 0; /* Probably should trap */ + } + l2linesize = linelock->l2linesize; + + moveData: + ASSERT(linelock->index <= linelock->maxcnt); + + lv = (lv_t *) & linelock->lv; + for (i = 0; i < linelock->index; i++, lv++) { + if (lv->length == 0) + continue; + + /* is page full ? */ + if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) { + /* page become full: move on to next page */ + lmNextPage(log); + + bp = log->bp; + lp = (logpage_t *) bp->l_ldata; + dstoffset = LOGPHDRSIZE; + } + + /* + * move log vector data + */ + src = (u8 *) p + (lv->offset << l2linesize); + srclen = lv->length << l2linesize; + len += srclen; + while (srclen > 0) { + freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset; + nbytes = min(freespace, srclen); + dst = (caddr_t) lp + dstoffset; + memcpy(dst, src, nbytes); + dstoffset += nbytes; + + /* is page not full ? */ + if (dstoffset < LOGPSIZE - LOGPTLRSIZE) + break; + + /* page become full: move on to next page */ + lmNextPage(log); + + bp = (lbuf_t *) log->bp; + lp = (logpage_t *) bp->l_ldata; + dstoffset = LOGPHDRSIZE; + + srclen -= nbytes; + src += nbytes; + } + + /* + * move log vector descriptor + */ + len += 4; + lvd = (lvd_t *) ((caddr_t) lp + dstoffset); + lvd->offset = cpu_to_le16(lv->offset); + lvd->length = cpu_to_le16(lv->length); + dstoffset += 4; + jFYI(1, + ("lmWriteRecord: lv offset:%d length:%d\n", + lv->offset, lv->length)); + } + + if ((i = linelock->next)) { + linelock = (linelock_t *) lid_to_tlock(i); + goto moveData; + } + + /* + * move log record descriptor + */ + moveLrd: + lrd->length = cpu_to_le16(len); + + src = (caddr_t) lrd; + srclen = LOGRDSIZE; + + while (srclen > 0) { + freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset; + nbytes = min(freespace, srclen); + dst = (caddr_t) lp + dstoffset; + memcpy(dst, src, nbytes); + + dstoffset += nbytes; + srclen -= nbytes; + + /* are there more to move than freespace of page ? */ + if (srclen) + goto pageFull; + + /* + * end of log record descriptor + */ + + /* update last log record eor */ + log->eor = dstoffset; + bp->l_eor = dstoffset; + lsn = (log->page << L2LOGPSIZE) + dstoffset; + + if (lrd->type & cpu_to_le16(LOG_COMMIT)) { + tblk->clsn = lsn; + jFYI(1, + ("wr: tclsn:0x%x, beor:0x%x\n", tblk->clsn, + bp->l_eor)); + + INCREMENT(lmStat.commit); /* # of commit */ + + /* + * enqueue tblock for group commit: + * + * enqueue tblock of non-trivial/synchronous COMMIT + * at tail of group commit queue + * (trivial/asynchronous COMMITs are ignored by + * group commit.) + */ + LOGGC_LOCK(log); + + /* init tblock gc state */ + tblk->flag = tblkGC_QUEUE; + tblk->bp = log->bp; + tblk->pn = log->page; + tblk->eor = log->eor; + init_waitqueue_head(&tblk->gcwait); + + /* enqueue transaction to commit queue */ + tblk->cqnext = NULL; + if (log->cqueue.head) { + log->cqueue.tail->cqnext = tblk; + log->cqueue.tail = tblk; + } else + log->cqueue.head = log->cqueue.tail = tblk; + + LOGGC_UNLOCK(log); + } + + jFYI(1, + ("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x\n", + le16_to_cpu(lrd->type), log->bp, log->page, + dstoffset)); + + /* page not full ? */ + if (dstoffset < LOGPSIZE - LOGPTLRSIZE) + return lsn; + + pageFull: + /* page become full: move on to next page */ + lmNextPage(log); + + bp = (lbuf_t *) log->bp; + lp = (logpage_t *) bp->l_ldata; + dstoffset = LOGPHDRSIZE; + src += nbytes; + } + + return lsn; +} + + +/* + * NAME: lmNextPage() + * + * FUNCTION: write current page and allocate next page. + * + * PARAMETER: log + * + * RETURN: 0 + * + * serialization: LOG_LOCK() held on entry/exit + */ +static int lmNextPage(log_t * log) +{ + logpage_t *lp; + int lspn; /* log sequence page number */ + int pn; /* current page number */ + lbuf_t *bp; + lbuf_t *nextbp; + tblock_t *tblk; + + jFYI(1, ("lmNextPage\n")); + + /* get current log page number and log sequence page number */ + pn = log->page; + bp = log->bp; + lp = (logpage_t *) bp->l_ldata; + lspn = le32_to_cpu(lp->h.page); + + LOGGC_LOCK(log); + + /* + * write or queue the full page at the tail of write queue + */ + /* get the tail tblk on commit queue */ + tblk = log->cqueue.tail; + + /* every tblk who has COMMIT record on the current page, + * and has not been committed, must be on commit queue + * since tblk is queued at commit queueu at the time + * of writing its COMMIT record on the page before + * page becomes full (even though the tblk thread + * who wrote COMMIT record may have been suspended + * currently); + */ + + /* is page bound with outstanding tail tblk ? */ + if (tblk && tblk->pn == pn) { + /* mark tblk for end-of-page */ + tblk->flag |= tblkGC_EOP; + + /* if page is not already on write queue, + * just enqueue (no lbmWRITE to prevent redrive) + * buffer to wqueue to ensure correct serial order + * of the pages since log pages will be added + * continuously (tblk bound with the page hasn't + * got around to init write of the page, either + * preempted or the page got filled by its COMMIT + * record); + * pages with COMMIT are paged out explicitly by + * tblk in lmGroupCommit(); + */ + if (bp->l_wqnext == NULL) { + /* bp->l_ceor = bp->l_eor; */ + /* lp->h.eor = lp->t.eor = bp->l_ceor; */ + lbmWrite(log, bp, 0, 0); + } + } + /* page is not bound with outstanding tblk: + * init write or mark it to be redriven (lbmWRITE) + */ + else { + /* finalize the page */ + bp->l_ceor = bp->l_eor; + lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); + lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0); + } + LOGGC_UNLOCK(log); + + /* + * allocate/initialize next page + */ + /* if log wraps, the first data page of log is 2 + * (0 never used, 1 is superblock). + */ + log->page = (pn == log->size - 1) ? 2 : pn + 1; + log->eor = LOGPHDRSIZE; /* ? valid page empty/full at logRedo() */ + + /* allocate/initialize next log page buffer */ + nextbp = lbmAllocate(log, log->page); + nextbp->l_eor = log->eor; + log->bp = nextbp; + + /* initialize next log page */ + lp = (logpage_t *) nextbp->l_ldata; + lp->h.page = lp->t.page = cpu_to_le32(lspn + 1); + lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE); + + jFYI(1, ("lmNextPage done\n")); + return 0; +} + + +/* + * NAME: lmGroupCommit() + * + * FUNCTION: group commit + * initiate pageout of the pages with COMMIT in the order of + * page number - redrive pageout of the page at the head of + * pageout queue until full page has been written. + * + * RETURN: + * + * NOTE: + * LOGGC_LOCK serializes log group commit queue, and + * transaction blocks on the commit queue. + * N.B. LOG_LOCK is NOT held during lmGroupCommit(). + */ +int lmGroupCommit(log_t * log, tblock_t * tblk) +{ + int rc = 0; + + LOGGC_LOCK(log); + + /* group committed already ? */ + if (tblk->flag & tblkGC_COMMITTED) { + if (tblk->flag & tblkGC_ERROR) + rc = EIO; + + LOGGC_UNLOCK(log); + return rc; + } + jFYI(1, + ("lmGroup Commit: tblk = 0x%p, gcrtc = %d\n", tblk, + log->gcrtc)); + + /* + * group commit pageout in progress + */ + if ((!(log->cflag & logGC_PAGEOUT)) && log->cqueue.head) { + /* + * only transaction in the commit queue: + * + * start one-transaction group commit as + * its group leader. + */ + log->cflag |= logGC_PAGEOUT; + + lmGCwrite(log, 0); + } + /* lmGCwrite gives up LOGGC_LOCK, check again */ + + if (tblk->flag & tblkGC_COMMITTED) { + if (tblk->flag & tblkGC_ERROR) + rc = EIO; + + LOGGC_UNLOCK(log); + return rc; + } + + /* upcount transaction waiting for completion + */ + log->gcrtc++; + + if (tblk->xflag & COMMIT_LAZY) { + tblk->flag |= tblkGC_LAZY; + LOGGC_UNLOCK(log); + return 0; + } + tblk->flag |= tblkGC_READY; + + __SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED), + LOGGC_LOCK(log), LOGGC_UNLOCK(log)); + + /* removed from commit queue */ + if (tblk->flag & tblkGC_ERROR) + rc = EIO; + + LOGGC_UNLOCK(log); + return rc; +} + +/* + * NAME: lmGCwrite() + * + * FUNCTION: group commit write + * initiate write of log page, building a group of all transactions + * with commit records on that page. + * + * RETURN: None + * + * NOTE: + * LOGGC_LOCK must be held by caller. + * N.B. LOG_LOCK is NOT held during lmGroupCommit(). + */ +void lmGCwrite(log_t * log, int cant_write) +{ + lbuf_t *bp; + logpage_t *lp; + int gcpn; /* group commit page number */ + tblock_t *tblk; + tblock_t *xtblk; + + /* + * build the commit group of a log page + * + * scan commit queue and make a commit group of all + * transactions with COMMIT records on the same log page. + */ + /* get the head tblk on the commit queue */ + tblk = xtblk = log->cqueue.head; + gcpn = tblk->pn; + + while (tblk && tblk->pn == gcpn) { + xtblk = tblk; + + /* state transition: (QUEUE, READY) -> COMMIT */ + tblk->flag |= tblkGC_COMMIT; + tblk = tblk->cqnext; + } + tblk = xtblk; /* last tblk of the page */ + + /* + * pageout to commit transactions on the log page. + */ + bp = (lbuf_t *) tblk->bp; + lp = (logpage_t *) bp->l_ldata; + /* is page already full ? */ + if (tblk->flag & tblkGC_EOP) { + /* mark page to free at end of group commit of the page */ + tblk->flag &= ~tblkGC_EOP; + tblk->flag |= tblkGC_FREE; + bp->l_ceor = bp->l_eor; + lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); + jEVENT(0, + ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn, + bp->l_ceor)); + lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC, + cant_write); + } + /* page is not yet full */ + else { + bp->l_ceor = tblk->eor; /* ? bp->l_ceor = bp->l_eor; */ + lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor); + jEVENT(0, + ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn, + bp->l_ceor)); + lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write); + } +} + +/* + * NAME: lmPostGC() + * + * FUNCTION: group commit post-processing + * Processes transactions after their commit records have been written + * to disk, redriving log I/O if necessary. + * + * RETURN: None + * + * NOTE: + * This routine is called a interrupt time by lbmIODone + */ +void lmPostGC(lbuf_t * bp) +{ + unsigned long flags; + log_t *log = bp->l_log; + logpage_t *lp; + tblock_t *tblk; + + //LOGGC_LOCK(log); + spin_lock_irqsave(&log->gclock, flags); + /* + * current pageout of group commit completed. + * + * remove/wakeup transactions from commit queue who were + * group committed with the current log page + */ + while ((tblk = log->cqueue.head) && (tblk->flag & tblkGC_COMMIT)) { + /* if transaction was marked GC_COMMIT then + * it has been shipped in the current pageout + * and made it to disk - it is committed. + */ + + if (bp->l_flag & lbmERROR) + tblk->flag |= tblkGC_ERROR; + + /* remove it from the commit queue */ + log->cqueue.head = tblk->cqnext; + if (log->cqueue.head == NULL) + log->cqueue.tail = NULL; + tblk->flag &= ~tblkGC_QUEUE; + tblk->cqnext = 0; + + jEVENT(0, + ("lmPostGC: tblk = 0x%p, flag = 0x%x\n", tblk, + tblk->flag)); + + if (!(tblk->xflag & COMMIT_FORCE)) + /* + * Hand tblk over to lazy commit thread + */ + txLazyUnlock(tblk); + else { + /* state transition: COMMIT -> COMMITTED */ + tblk->flag |= tblkGC_COMMITTED; + + if (tblk->flag & tblkGC_READY) { + log->gcrtc--; + LOGGC_WAKEUP(tblk); + } + } + + /* was page full before pageout ? + * (and this is the last tblk bound with the page) + */ + if (tblk->flag & tblkGC_FREE) + lbmFree(bp); + /* did page become full after pageout ? + * (and this is the last tblk bound with the page) + */ + else if (tblk->flag & tblkGC_EOP) { + /* finalize the page */ + lp = (logpage_t *) bp->l_ldata; + bp->l_ceor = bp->l_eor; + lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); + jEVENT(0, ("lmPostGC: calling lbmWrite\n")); + lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, + 1); + } + + } + + /* are there any transactions who have entered lnGroupCommit() + * (whose COMMITs are after that of the last log page written. + * They are waiting for new group commit (above at (SLEEP 1)): + * select the latest ready transaction as new group leader and + * wake her up to lead her group. + */ + if ((log->gcrtc > 0) && log->cqueue.head) + /* + * Call lmGCwrite with new group leader + */ + lmGCwrite(log, 1); + + /* no transaction are ready yet (transactions are only just + * queued (GC_QUEUE) and not entered for group commit yet). + * let the first transaction entering group commit + * will elect hetself as new group leader. + */ + else + log->cflag &= ~logGC_PAGEOUT; + + //LOGGC_UNLOCK(log); + spin_unlock_irqrestore(&log->gclock, flags); + return; +} + +/* + * NAME: lmLogSync() + * + * FUNCTION: write log SYNCPT record for specified log + * if new sync address is available + * (normally the case if sync() is executed by back-ground + * process). + * if not, explicitly run jfs_blogsync() to initiate + * getting of new sync address. + * calculate new value of i_nextsync which determines when + * this code is called again. + * + * this is called only from lmLog(). + * + * PARAMETER: ip - pointer to logs inode. + * + * RETURN: 0 + * + * serialization: LOG_LOCK() held on entry/exit + */ +int lmLogSync(log_t * log, int nosyncwait) +{ + int logsize; + int written; /* written since last syncpt */ + int free; /* free space left available */ + int delta; /* additional delta to write normally */ + int more; /* additional write granted */ + lrd_t lrd; + int lsn; + struct logsyncblk *lp; + + /* + * forward syncpt + */ + /* if last sync is same as last syncpt, + * invoke sync point forward processing to update sync. + */ + + if (log->sync == log->syncpt) { + LOGSYNC_LOCK(log); + /* ToDo: push dirty metapages out to disk */ +// bmLogSync(log); + + if (list_empty(&log->synclist)) + log->sync = log->lsn; + else { + lp = list_entry(log->synclist.next, + struct logsyncblk, synclist); + log->sync = lp->lsn; + } + LOGSYNC_UNLOCK(log); + + } + + /* if sync is different from last syncpt, + * write a SYNCPT record with syncpt = sync. + * reset syncpt = sync + */ + if (log->sync != log->syncpt) { + struct jfs_sb_info *sbi = JFS_SBI(log->sb); + /* + * We need to make sure all of the "written" metapages + * actually make it to disk + */ + fsync_inode_data_buffers(sbi->ipbmap); + fsync_inode_data_buffers(sbi->ipimap); + fsync_inode_data_buffers(sbi->direct_inode); + + lrd.logtid = 0; + lrd.backchain = 0; + lrd.type = cpu_to_le16(LOG_SYNCPT); + lrd.length = 0; + lrd.log.syncpt.sync = cpu_to_le32(log->sync); + lsn = lmWriteRecord(log, NULL, &lrd, NULL); + + log->syncpt = log->sync; + } else + lsn = log->lsn; + + /* + * setup next syncpt trigger (SWAG) + */ + logsize = log->logsize; + + logdiff(written, lsn, log); + free = logsize - written; + delta = LOGSYNC_DELTA(logsize); + more = min(free / 2, delta); + if (more < 2 * LOGPSIZE) { + jEVENT(1, + ("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n\n")); + /* + * log wrapping + * + * option 1 - panic ? No.! + * option 2 - shutdown file systems + * associated with log ? + * option 3 - extend log ? + */ + /* + * option 4 - second chance + * + * mark log wrapped, and continue. + * when all active transactions are completed, + * mark log vaild for recovery. + * if crashed during invalid state, log state + * implies invald log, forcing fsck(). + */ + /* mark log state log wrap in log superblock */ + /* log->state = LOGWRAP; */ + + /* reset sync point computation */ + log->syncpt = log->sync = lsn; + log->nextsync = delta; + } else + /* next syncpt trigger = written + more */ + log->nextsync = written + more; + + /* return if lmLogSync() from outside of transaction, e.g., sync() */ + if (nosyncwait) + return lsn; + + /* if number of bytes written from last sync point is more + * than 1/4 of the log size, stop new transactions from + * starting until all current transactions are completed + * by setting syncbarrier flag. + */ + if (written > LOGSYNC_BARRIER(logsize) && logsize > 32 * LOGPSIZE) { + set_bit(log_SYNCBARRIER, &log->flag); + jFYI(1, ("log barrier on: lsn=0x%x syncpt=0x%x\n", lsn, + log->syncpt)); + } + + return lsn; +} + + +/* + * NAME: lmLogOpen() + * + * FUNCTION: open the log on first open; + * insert filesystem in the active list of the log. + * + * PARAMETER: ipmnt - file system mount inode + * iplog - log inode (out) + * + * RETURN: + * + * serialization: + */ +int lmLogOpen(struct super_block *sb, log_t ** logptr) +{ + int rc; + struct block_device *bdev; + log_t *log; + + if (!(log = kmalloc(sizeof(log_t), GFP_KERNEL))) + return ENOMEM; + memset(log, 0, sizeof(log_t)); + init_waitqueue_head(&log->syncwait); + + log->sb = sb; /* This should be a list */ + + if (!(JFS_SBI(sb)->mntflag & JFS_INLINELOG)) + goto externalLog; + + /* + * in-line log in host file system + * + * file system to log have 1-to-1 relationship; + */ + + set_bit(log_INLINELOG, &log->flag); + log->bdev = sb->s_bdev; + log->base = addressPXD(&JFS_SBI(sb)->logpxd); + log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >> + (L2LOGPSIZE - sb->s_blocksize_bits); + log->l2bsize = sb->s_blocksize_bits; + ASSERT(L2LOGPSIZE >= sb->s_blocksize_bits); + + /* + * initialize log. + */ + if ((rc = lmLogInit(log))) + goto errout10; + goto out; + + /* + * external log as separate logical volume + * + * file systems to log may have n-to-1 relationship; + */ + externalLog: + + /* + * TODO: Check for already opened log devices + */ + + if (!(bdev = bdget(kdev_t_to_nr(JFS_SBI(sb)->logdev)))) { + rc = ENODEV; + goto errout10; + } + + if ((rc = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS))) { + rc = -rc; + goto errout10; + } + + log->bdev = bdev; + memcpy(log->uuid, JFS_SBI(sb)->loguuid, sizeof(log->uuid)); + + /* + * initialize log: + */ + if ((rc = lmLogInit(log))) + goto errout20; + + /* + * add file system to log active file system list + */ + if ((rc = lmLogFileSystem(log, JFS_SBI(sb)->uuid, 1))) + goto errout30; + + out: + jFYI(1, ("lmLogOpen: exit(0)\n")); + *logptr = log; + return 0; + + /* + * unwind on error + */ + errout30: /* unwind lbmLogInit() */ + lbmLogShutdown(log); + + errout20: /* close external log device */ + blkdev_put(bdev, BDEV_FS); + + errout10: /* free log descriptor */ + kfree(log); + + jFYI(1, ("lmLogOpen: exit(%d)\n", rc)); + return rc; +} + + +/* + * NAME: lmLogInit() + * + * FUNCTION: log initialization at first log open. + * + * logredo() (or logformat()) should have been run previously. + * initialize the log inode from log superblock. + * set the log state in the superblock to LOGMOUNT and + * write SYNCPT log record. + * + * PARAMETER: log - log structure + * + * RETURN: 0 - if ok + * EINVAL - bad log magic number or superblock dirty + * error returned from logwait() + * + * serialization: single first open thread + */ +int lmLogInit(log_t * log) +{ + int rc = 0; + lrd_t lrd; + logsuper_t *logsuper; + lbuf_t *bpsuper; + lbuf_t *bp; + logpage_t *lp; + int lsn; + + jFYI(1, ("lmLogInit: log:0x%p\n", log)); + + /* + * log inode is overlaid on generic inode where + * dinode have been zeroed out by iRead(); + */ + + /* + * initialize log i/o + */ + if ((rc = lbmLogInit(log))) + return rc; + + /* + * validate log superblock + */ + + + if (!test_bit(log_INLINELOG, &log->flag)) + log->l2bsize = 12; /* XXX kludge alert XXX */ + if ((rc = lbmRead(log, 1, &bpsuper))) + goto errout10; + + logsuper = (logsuper_t *) bpsuper->l_ldata; + + if (logsuper->magic != cpu_to_le32(LOGMAGIC)) { + jERROR(1, ("*** Log Format Error ! ***\n")); + rc = EINVAL; + goto errout20; + } + + /* logredo() should have been run successfully. */ + if (logsuper->state != cpu_to_le32(LOGREDONE)) { + jERROR(1, ("*** Log Is Dirty ! ***\n")); + rc = EINVAL; + goto errout20; + } + + /* initialize log inode from log superblock */ + if (test_bit(log_INLINELOG,&log->flag)) { + if (log->size != le32_to_cpu(logsuper->size)) { + rc = EINVAL; + goto errout20; + } + jFYI(0, + ("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x\n", + log, (unsigned long long) log->base, log->size)); + } else { + if (memcmp(logsuper->uuid, log->uuid, 16)) { + jERROR(1,("wrong uuid on JFS log device\n")); + goto errout20; + } + log->size = le32_to_cpu(logsuper->size); + log->l2bsize = le32_to_cpu(logsuper->l2bsize); + jFYI(0, + ("lmLogInit: external log:0x%p base:0x%Lx size:0x%x\n", + log, (unsigned long long) log->base, log->size)); + } + + log->page = le32_to_cpu(logsuper->end) / LOGPSIZE; + log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page); + + /* + * initialize for log append write mode + */ + /* establish current/end-of-log page/buffer */ + if ((rc = lbmRead(log, log->page, &bp))) + goto errout20; + + lp = (logpage_t *) bp->l_ldata; + + jFYI(1, ("lmLogInit: lsn:0x%x page:%d eor:%d:%d\n", + le32_to_cpu(logsuper->end), log->page, log->eor, + le16_to_cpu(lp->h.eor))); + +// ASSERT(log->eor == lp->h.eor); + + log->bp = bp; + bp->l_pn = log->page; + bp->l_eor = log->eor; + + /* initialize the group commit serialization lock */ + LOGGC_LOCK_INIT(log); + + /* if current page is full, move on to next page */ + if (log->eor >= LOGPSIZE - LOGPTLRSIZE) + lmNextPage(log); + + /* allocate/initialize the log write serialization lock */ + LOG_LOCK_INIT(log); + + /* + * initialize log syncpoint + */ + /* + * write the first SYNCPT record with syncpoint = 0 + * (i.e., log redo up to HERE !); + * remove current page from lbm write queue at end of pageout + * (to write log superblock update), but do not release to freelist; + */ + lrd.logtid = 0; + lrd.backchain = 0; + lrd.type = cpu_to_le16(LOG_SYNCPT); + lrd.length = 0; + lrd.log.syncpt.sync = 0; + lsn = lmWriteRecord(log, NULL, &lrd, NULL); + bp = log->bp; + bp->l_ceor = bp->l_eor; + lp = (logpage_t *) bp->l_ldata; + lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); + lbmWrite(log, bp, lbmWRITE | lbmSYNC, 0); + if ((rc = lbmIOWait(bp, 0))) + goto errout30; + + /* initialize logsync parameters */ + log->logsize = (log->size - 2) << L2LOGPSIZE; + log->lsn = lsn; + log->syncpt = lsn; + log->sync = log->syncpt; + log->nextsync = LOGSYNC_DELTA(log->logsize); + + jFYI(1, ("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x\n", + log->lsn, log->syncpt, log->sync)); + + LOGSYNC_LOCK_INIT(log); + + INIT_LIST_HEAD(&log->synclist); + + log->cqueue.head = log->cqueue.tail = 0; + + log->count = 0; + + /* + * initialize for lazy/group commit + */ + log->clsn = lsn; + + /* + * update/write superblock + */ + logsuper->state = cpu_to_le32(LOGMOUNT); + log->serial = le32_to_cpu(logsuper->serial) + 1; + logsuper->serial = cpu_to_le32(log->serial); + lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); + if ((rc = lbmIOWait(bpsuper, lbmFREE))) + goto errout30; + + jFYI(1, ("lmLogInit: exit(%d)\n", rc)); + return 0; + + /* + * unwind on error + */ + errout30: /* release log page */ + lbmFree(bp); + + errout20: /* release log superblock */ + lbmFree(bpsuper); + + errout10: /* unwind lbmLogInit() */ + lbmLogShutdown(log); + + jFYI(1, ("lmLogInit: exit(%d)\n", rc)); + return rc; +} + + +/* + * NAME: lmLogClose() + * + * FUNCTION: remove file system from active list of log + * and close it on last close. + * + * PARAMETER: sb - superblock + * log - log inode + * + * RETURN: errors from subroutines + * + * serialization: + */ +int lmLogClose(struct super_block *sb, log_t * log) +{ + int rc; + + jFYI(1, ("lmLogClose: log:0x%p\n", log)); + + if (!test_bit(log_INLINELOG, &log->flag)) + goto externalLog; + + /* + * in-line log in host file system + */ + rc = lmLogShutdown(log); + goto out; + + /* + * external log as separate logical volume + */ + externalLog: + lmLogFileSystem(log, JFS_SBI(sb)->uuid, 0); + rc = lmLogShutdown(log); + blkdev_put(log->bdev, BDEV_FS); + + out: + jFYI(0, ("lmLogClose: exit(%d)\n", rc)); + return rc; +} + + +/* + * NAME: lmLogShutdown() + * + * FUNCTION: log shutdown at last LogClose(). + * + * write log syncpt record. + * update super block to set redone flag to 0. + * + * PARAMETER: log - log inode + * + * RETURN: 0 - success + * + * serialization: single last close thread + */ +int lmLogShutdown(log_t * log) +{ + int rc; + lrd_t lrd; + int lsn; + logsuper_t *logsuper; + lbuf_t *bpsuper; + lbuf_t *bp; + logpage_t *lp; + + jFYI(1, ("lmLogShutdown: log:0x%p\n", log)); + + if (log->cqueue.head || !list_empty(&log->synclist)) { + /* + * If there was very recent activity, we may need to wait + * for the lazycommit thread to catch up + */ + int i; + + for (i = 0; i < 800; i++) { /* Too much? */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ / 4); + if ((log->cqueue.head == NULL) && + list_empty(&log->synclist)) + break; + } + } + assert(log->cqueue.head == NULL); + assert(list_empty(&log->synclist)); + + /* + * We need to make sure all of the "written" metapages + * actually make it to disk + */ + fsync_no_super(log->sb->s_dev); + + /* + * write the last SYNCPT record with syncpoint = 0 + * (i.e., log redo up to HERE !) + */ + lrd.logtid = 0; + lrd.backchain = 0; + lrd.type = cpu_to_le16(LOG_SYNCPT); + lrd.length = 0; + lrd.log.syncpt.sync = 0; + lsn = lmWriteRecord(log, NULL, &lrd, NULL); + bp = log->bp; + lp = (logpage_t *) bp->l_ldata; + lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor); + lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0); + lbmIOWait(log->bp, lbmFREE); + + /* + * synchronous update log superblock + * mark log state as shutdown cleanly + * (i.e., Log does not need to be replayed). + */ + if ((rc = lbmRead(log, 1, &bpsuper))) + goto out; + + logsuper = (logsuper_t *) bpsuper->l_ldata; + logsuper->state = cpu_to_le32(LOGREDONE); + logsuper->end = cpu_to_le32(lsn); + lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); + rc = lbmIOWait(bpsuper, lbmFREE); + + jFYI(1, ("lmLogShutdown: lsn:0x%x page:%d eor:%d\n", + lsn, log->page, log->eor)); + + out: + /* + * shutdown per log i/o + */ + lbmLogShutdown(log); + + if (rc) { + jFYI(1, ("lmLogShutdown: exit(%d)\n", rc)); + } + return rc; +} + + +/* + * NAME: lmLogFileSystem() + * + * FUNCTION: insert ( = true)/remove ( = false) + * file system into/from log active file system list. + * + * PARAMETE: log - pointer to logs inode. + * fsdev - kdev_t of filesystem. + * serial - pointer to returned log serial number + * activate - insert/remove device from active list. + * + * RETURN: 0 - success + * errors returned by vms_iowait(). + */ +static int lmLogFileSystem(log_t * log, char *uuid, int activate) +{ + int rc = 0; + int i; + logsuper_t *logsuper; + lbuf_t *bpsuper; + + /* + * insert/remove file system device to log active file system list. + */ + if ((rc = lbmRead(log, 1, &bpsuper))) + return rc; + + logsuper = (logsuper_t *) bpsuper->l_ldata; + if (activate) { + for (i = 0; i < MAX_ACTIVE; i++) + if (!memcmp(logsuper->active[i].uuid, NULL_UUID, 16)) { + memcpy(logsuper->active[i].uuid, uuid, 16); + break; + } + if (i == MAX_ACTIVE) { + jERROR(1,("Too many file systems sharing journal!\n")); + lbmFree(bpsuper); + return EMFILE; /* Is there a better rc? */ + } + } else { + for (i = 0; i < MAX_ACTIVE; i++) + if (!memcmp(logsuper->active[i].uuid, uuid, 16)) { + memcpy(logsuper->active[i].uuid, NULL_UUID, 16); + break; + } + assert(i < MAX_ACTIVE); + } + + /* + * synchronous write log superblock: + * + * write sidestream bypassing write queue: + * at file system mount, log super block is updated for + * activation of the file system before any log record + * (MOUNT record) of the file system, and at file system + * unmount, all meta data for the file system has been + * flushed before log super block is updated for deactivation + * of the file system. + */ + lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC); + rc = lbmIOWait(bpsuper, lbmFREE); + + return rc; +} + +/* + * log buffer manager (lbm) + * ------------------------ + * + * special purpose buffer manager supporting log i/o requirements. + * + * per log write queue: + * log pageout occurs in serial order by fifo write queue and + * restricting to a single i/o in pregress at any one time. + * a circular singly-linked list + * (log->wrqueue points to the tail, and buffers are linked via + * bp->wrqueue field), and + * maintains log page in pageout ot waiting for pageout in serial pageout. + */ + +/* + * lbmLogInit() + * + * initialize per log I/O setup at lmLogInit() + */ +static int lbmLogInit(log_t * log) +{ /* log inode */ + int i; + lbuf_t *lbuf; + + jFYI(1, ("lbmLogInit: log:0x%p\n", log)); + + /* initialize current buffer cursor */ + log->bp = NULL; + + /* initialize log device write queue */ + log->wqueue = NULL; + + /* + * Each log has its own buffer pages allocated to it. These are + * not managed by the page cache. This ensures that a transaction + * writing to the log does not block trying to allocate a page from + * the page cache (for the log). This would be bad, since page + * allocation waits on the kswapd thread that may be committing inodes + * which would cause log activity. Was that clear? I'm trying to + * avoid deadlock here. + */ + init_waitqueue_head(&log->free_wait); + + log->lbuf_free = NULL; + + for (i = 0; i < LOGPAGES; i++) { + lbuf = kmalloc(sizeof(lbuf_t), GFP_KERNEL); + if (lbuf == 0) + goto error; + lbuf->l_bh.b_data = lbuf->l_ldata = + (char *) __get_free_page(GFP_KERNEL); + if (lbuf->l_ldata == 0) { + kfree(lbuf); + goto error; + } + lbuf->l_log = log; + init_waitqueue_head(&lbuf->l_ioevent); + + lbuf->l_bh.b_size = LOGPSIZE; + lbuf->l_bh.b_dev = to_kdev_t(log->bdev->bd_dev); + lbuf->l_bh.b_end_io = lbmIODone; + lbuf->l_bh.b_private = lbuf; + lbuf->l_bh.b_page = virt_to_page(lbuf->l_ldata); + lbuf->l_bh.b_state = 0; + init_waitqueue_head(&lbuf->l_bh.b_wait); + + lbuf->l_freelist = log->lbuf_free; + log->lbuf_free = lbuf; + } + + return (0); + + error: + lbmLogShutdown(log); + return (ENOMEM); +} + + +/* + * lbmLogShutdown() + * + * finalize per log I/O setup at lmLogShutdown() + */ +static void lbmLogShutdown(log_t * log) +{ + lbuf_t *lbuf; + + jFYI(1, ("lbmLogShutdown: log:0x%p\n", log)); + + lbuf = log->lbuf_free; + while (lbuf) { + lbuf_t *next = lbuf->l_freelist; + free_page((unsigned long) lbuf->l_ldata); + kfree(lbuf); + lbuf = next; + } + + log->bp = NULL; +} + + +/* + * lbmAllocate() + * + * allocate an empty log buffer + */ +static lbuf_t *lbmAllocate(log_t * log, int pn) +{ + lbuf_t *bp; + unsigned long flags; + + /* + * recycle from log buffer freelist if any + */ + LCACHE_LOCK(flags); + LCACHE_SLEEP_COND(log->free_wait, (bp = log->lbuf_free), flags); + log->lbuf_free = bp->l_freelist; + LCACHE_UNLOCK(flags); + + bp->l_flag = 0; + + bp->l_wqnext = NULL; + bp->l_freelist = NULL; + + bp->l_pn = pn; + bp->l_blkno = log->base + (pn << (L2LOGPSIZE - log->l2bsize)); + bp->l_bh.b_blocknr = bp->l_blkno; + bp->l_ceor = 0; + + return bp; +} + + +/* + * lbmFree() + * + * release a log buffer to freelist + */ +static void lbmFree(lbuf_t * bp) +{ + unsigned long flags; + + LCACHE_LOCK(flags); + + lbmfree(bp); + + LCACHE_UNLOCK(flags); +} + +static void lbmfree(lbuf_t * bp) +{ + log_t *log = bp->l_log; + + assert(bp->l_wqnext == NULL); + + /* + * return the buffer to head of freelist + */ + bp->l_freelist = log->lbuf_free; + log->lbuf_free = bp; + + wake_up(&log->free_wait); + return; +} + + +/* + * NAME: lbmRedrive + * + * FUNCTION: add a log buffer to the the log redrive list + * + * PARAMETER: + * bp - log buffer + * + * NOTES: + * Takes log_redrive_lock. + */ +static inline void lbmRedrive(lbuf_t *bp) +{ + unsigned long flags; + + spin_lock_irqsave(&log_redrive_lock, flags); + bp->l_redrive_next = log_redrive_list; + log_redrive_list = bp; + spin_unlock_irqrestore(&log_redrive_lock, flags); + + wake_up(&jfs_IO_thread_wait); +} + + +/* + * lbmRead() + */ +static int lbmRead(log_t * log, int pn, lbuf_t ** bpp) +{ + lbuf_t *bp; + + /* + * allocate a log buffer + */ + *bpp = bp = lbmAllocate(log, pn); + jFYI(1, ("lbmRead: bp:0x%p pn:0x%x\n", bp, pn)); + + bp->l_flag |= lbmREAD; + bp->l_bh.b_reqnext = NULL; + clear_bit(BH_Uptodate, &bp->l_bh.b_state); + lock_buffer(&bp->l_bh); + set_bit(BH_Mapped, &bp->l_bh.b_state); + set_bit(BH_Req, &bp->l_bh.b_state); + bp->l_bh.b_rdev = bp->l_bh.b_dev; + bp->l_bh.b_rsector = bp->l_blkno << (log->l2bsize - 9); + generic_make_request(READ, &bp->l_bh); + run_task_queue(&tq_disk); + + wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD)); + + return 0; +} + + +/* + * lbmWrite() + * + * buffer at head of pageout queue stays after completion of + * partial-page pageout and redriven by explicit initiation of + * pageout by caller until full-page pageout is completed and + * released. + * + * device driver i/o done redrives pageout of new buffer at + * head of pageout queue when current buffer at head of pageout + * queue is released at the completion of its full-page pageout. + * + * LOGGC_LOCK() serializes lbmWrite() by lmNextPage() and lmGroupCommit(). + * LCACHE_LOCK() serializes xflag between lbmWrite() and lbmIODone() + */ +static void lbmWrite(log_t * log, lbuf_t * bp, int flag, int cant_block) +{ + lbuf_t *tail; + unsigned long flags; + + jFYI(1, ("lbmWrite: bp:0x%p flag:0x%x pn:0x%x\n", + bp, flag, bp->l_pn)); + + /* map the logical block address to physical block address */ + bp->l_blkno = + log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize)); + + LCACHE_LOCK(flags); /* disable+lock */ + + /* + * initialize buffer for device driver + */ + bp->l_flag = flag; + + /* + * insert bp at tail of write queue associated with log + * + * (request is either for bp already/currently at head of queue + * or new bp to be inserted at tail) + */ + tail = log->wqueue; + + /* is buffer not already on write queue ? */ + if (bp->l_wqnext == NULL) { + /* insert at tail of wqueue */ + if (tail == NULL) { + log->wqueue = bp; + bp->l_wqnext = bp; + } else { + log->wqueue = bp; + bp->l_wqnext = tail->l_wqnext; + tail->l_wqnext = bp; + } + + tail = bp; + } + + /* is buffer at head of wqueue and for write ? */ + if ((bp != tail->l_wqnext) || !(flag & lbmWRITE)) { + LCACHE_UNLOCK(flags); /* unlock+enable */ + return; + } + + LCACHE_UNLOCK(flags); /* unlock+enable */ + + if (cant_block) + lbmRedrive(bp); + else if (flag & lbmSYNC) + lbmStartIO(bp); + else { + LOGGC_UNLOCK(log); + lbmStartIO(bp); + LOGGC_LOCK(log); + } +} + + +/* + * lbmDirectWrite() + * + * initiate pageout bypassing write queue for sidestream + * (e.g., log superblock) write; + */ +static void lbmDirectWrite(log_t * log, lbuf_t * bp, int flag) +{ + jEVENT(0, ("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x\n", + bp, flag, bp->l_pn)); + + /* + * initialize buffer for device driver + */ + bp->l_flag = flag | lbmDIRECT; + + /* map the logical block address to physical block address */ + bp->l_blkno = + log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize)); + + /* + * initiate pageout of the page + */ + lbmStartIO(bp); +} + + +/* + * NAME: lbmStartIO() + * + * FUNCTION: Interface to DD strategy routine + * + * RETURN: none + * + * serialization: LCACHE_LOCK() is NOT held during log i/o; + */ +void lbmStartIO(lbuf_t * bp) +{ + jFYI(1, ("lbmStartIO\n")); + + bp->l_bh.b_reqnext = NULL; + set_bit(BH_Dirty, &bp->l_bh.b_state); +// lock_buffer(&bp->l_bh); + assert(!test_bit(BH_Lock, &bp->l_bh.b_state)); + set_bit(BH_Lock, &bp->l_bh.b_state); + + set_bit(BH_Mapped, &bp->l_bh.b_state); + set_bit(BH_Req, &bp->l_bh.b_state); + bp->l_bh.b_rdev = bp->l_bh.b_dev; + bp->l_bh.b_rsector = bp->l_blkno << (bp->l_log->l2bsize - 9); + generic_make_request(WRITE, &bp->l_bh); + + INCREMENT(lmStat.submitted); + run_task_queue(&tq_disk); + + jFYI(1, ("lbmStartIO done\n")); +} + + +/* + * lbmIOWait() + */ +static int lbmIOWait(lbuf_t * bp, int flag) +{ + unsigned long flags; + int rc = 0; + + jFYI(1, + ("lbmIOWait1: bp:0x%p flag:0x%x:0x%x\n", bp, bp->l_flag, + flag)); + + LCACHE_LOCK(flags); /* disable+lock */ + + LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags); + + rc = (bp->l_flag & lbmERROR) ? EIO : 0; + + if (flag & lbmFREE) + lbmfree(bp); + + LCACHE_UNLOCK(flags); /* unlock+enable */ + + jFYI(1, + ("lbmIOWait2: bp:0x%p flag:0x%x:0x%x\n", bp, bp->l_flag, + flag)); + return rc; +} + +/* + * lbmIODone() + * + * executed at INTIODONE level + */ +static void lbmIODone(struct buffer_head *bh, int uptodate) +{ + lbuf_t *bp = bh->b_private; + lbuf_t *nextbp, *tail; + log_t *log; + unsigned long flags; + + /* + * get back jfs buffer bound to the i/o buffer + */ + jEVENT(0, ("lbmIODone: bp:0x%p flag:0x%x\n", bp, bp->l_flag)); + + LCACHE_LOCK(flags); /* disable+lock */ + + unlock_buffer(&bp->l_bh); + bp->l_flag |= lbmDONE; + + if (!uptodate) { + bp->l_flag |= lbmERROR; + + jERROR(1, ("lbmIODone: I/O error in JFS log\n")); + } + + /* + * pagein completion + */ + if (bp->l_flag & lbmREAD) { + bp->l_flag &= ~lbmREAD; + + LCACHE_UNLOCK(flags); /* unlock+enable */ + + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + + return; + } + + /* + * pageout completion + * + * the bp at the head of write queue has completed pageout. + * + * if single-commit/full-page pageout, remove the current buffer + * from head of pageout queue, and redrive pageout with + * the new buffer at head of pageout queue; + * otherwise, the partial-page pageout buffer stays at + * the head of pageout queue to be redriven for pageout + * by lmGroupCommit() until full-page pageout is completed. + */ + bp->l_flag &= ~lbmWRITE; + INCREMENT(lmStat.pagedone); + + /* update committed lsn */ + log = bp->l_log; + log->clsn = (bp->l_pn << L2LOGPSIZE) + bp->l_ceor; + + if (bp->l_flag & lbmDIRECT) { + LCACHE_WAKEUP(&bp->l_ioevent); + LCACHE_UNLOCK(flags); + return; + } + + tail = log->wqueue; + + /* single element queue */ + if (bp == tail) { + /* remove head buffer of full-page pageout + * from log device write queue + */ + if (bp->l_flag & lbmRELEASE) { + log->wqueue = NULL; + bp->l_wqnext = NULL; + } + } + /* multi element queue */ + else { + /* remove head buffer of full-page pageout + * from log device write queue + */ + if (bp->l_flag & lbmRELEASE) { + nextbp = tail->l_wqnext = bp->l_wqnext; + bp->l_wqnext = NULL; + + /* + * redrive pageout of next page at head of write queue: + * redrive next page without any bound tblk + * (i.e., page w/o any COMMIT records), or + * first page of new group commit which has been + * queued after current page (subsequent pageout + * is performed synchronously, except page without + * any COMMITs) by lmGroupCommit() as indicated + * by lbmWRITE flag; + */ + if (nextbp->l_flag & lbmWRITE) { + /* + * We can't do the I/O at interrupt time. + * The jfsIO thread can do it + */ + lbmRedrive(nextbp); + } + } + } + + /* + * synchronous pageout: + * + * buffer has not necessarily been removed from write queue + * (e.g., synchronous write of partial-page with COMMIT): + * leave buffer for i/o initiator to dispose + */ + if (bp->l_flag & lbmSYNC) { + LCACHE_UNLOCK(flags); /* unlock+enable */ + + /* wakeup I/O initiator */ + LCACHE_WAKEUP(&bp->l_ioevent); + } + + /* + * Group Commit pageout: + */ + else if (bp->l_flag & lbmGC) { + LCACHE_UNLOCK(flags); + lmPostGC(bp); + } + + /* + * asynchronous pageout: + * + * buffer must have been removed from write queue: + * insert buffer at head of freelist where it can be recycled + */ + else { + assert(bp->l_flag & lbmRELEASE); + assert(bp->l_flag & lbmFREE); + lbmfree(bp); + + LCACHE_UNLOCK(flags); /* unlock+enable */ + } +} + +int jfsIOWait(void *arg) +{ + lbuf_t *bp; + + jFYI(1, ("jfsIOWait is here!\n")); + + lock_kernel(); + + daemonize(); + current->tty = NULL; + strcpy(current->comm, "jfsIO"); + + unlock_kernel(); + + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + complete(&jfsIOwait); + + do { + DECLARE_WAITQUEUE(wq, current); + + spin_lock_irq(&log_redrive_lock); + while ((bp = log_redrive_list)) { + log_redrive_list = bp->l_redrive_next; + bp->l_redrive_next = NULL; + spin_unlock_irq(&log_redrive_lock); + lbmStartIO(bp); + spin_lock_irq(&log_redrive_lock); + } + add_wait_queue(&jfs_IO_thread_wait, &wq); + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&log_redrive_lock); + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&jfs_IO_thread_wait, &wq); + } while (!jfs_stop_threads); + + jFYI(1,("jfsIOWait being killed!\n")); + complete(&jfsIOwait); + return 0; +} + + + +/* + * NAME: lmLogFormat()/jfs_logform() + * + * FUNCTION: format file system log + * + * PARAMETERS: + * log - volume log + * logAddress - start address of log space in FS block + * logSize - length of log space in FS block; + * + * RETURN: 0 - success + * -EIO - i/o error + * + * XXX: We're synchronously writing one page at a time. This needs to + * be improved by writing multiple pages at once. + */ +int lmLogFormat(log_t *log, s64 logAddress, int logSize) +{ + int rc = -EIO; + struct jfs_sb_info *sbi = JFS_SBI(log->sb); + logsuper_t *logsuper; + logpage_t *lp; + int lspn; /* log sequence page number */ + struct lrd *lrd_ptr; + int npages = 0; + lbuf_t *bp; + + jFYI(0, ("lmLogFormat: logAddress:%Ld logSize:%d\n", + (long long)logAddress, logSize)); + + /* allocate a log buffer */ + bp = lbmAllocate(log, 1); + + npages = logSize >> sbi->l2nbperpage; + + /* + * log space: + * + * page 0 - reserved; + * page 1 - log superblock; + * page 2 - log data page: A SYNC log record is written + * into this page at logform time; + * pages 3-N - log data page: set to empty log data pages; + */ + /* + * init log superblock: log page 1 + */ + logsuper = (logsuper_t *) bp->l_ldata; + + logsuper->magic = cpu_to_le32(LOGMAGIC); + logsuper->version = cpu_to_le32(LOGVERSION); + logsuper->state = cpu_to_le32(LOGREDONE); + logsuper->flag = cpu_to_le32(sbi->mntflag); /* ? */ + logsuper->size = cpu_to_le32(npages); + logsuper->bsize = cpu_to_le32(sbi->bsize); + logsuper->l2bsize = cpu_to_le32(sbi->l2bsize); + logsuper->end = cpu_to_le32(2 * LOGPSIZE + LOGPHDRSIZE + LOGRDSIZE); + + bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; + bp->l_blkno = logAddress + sbi->nbperpage; + lbmStartIO(bp); + if ((rc = lbmIOWait(bp, 0))) + goto exit; + + /* + * init pages 2 to npages-1 as log data pages: + * + * log page sequence number (lpsn) initialization: + * + * pn: 0 1 2 3 n-1 + * +-----+-----+=====+=====+===.....===+=====+ + * lspn: N-1 0 1 N-2 + * <--- N page circular file ----> + * + * the N (= npages-2) data pages of the log is maintained as + * a circular file for the log records; + * lpsn grows by 1 monotonically as each log page is written + * to the circular file of the log; + * and setLogpage() will not reset the page number even if + * the eor is equal to LOGPHDRSIZE. In order for binary search + * still work in find log end process, we have to simulate the + * log wrap situation at the log format time. + * The 1st log page written will have the highest lpsn. Then + * the succeeding log pages will have ascending order of + * the lspn starting from 0, ... (N-2) + */ + lp = (logpage_t *) bp->l_ldata; + /* + * initialize 1st log page to be written: lpsn = N - 1, + * write a SYNCPT log record is written to this page + */ + lp->h.page = lp->t.page = cpu_to_le32(npages - 3); + lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE + LOGRDSIZE); + + lrd_ptr = (struct lrd *) &lp->data; + lrd_ptr->logtid = 0; + lrd_ptr->backchain = 0; + lrd_ptr->type = cpu_to_le16(LOG_SYNCPT); + lrd_ptr->length = 0; + lrd_ptr->log.syncpt.sync = 0; + + bp->l_blkno += sbi->nbperpage; + bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; + lbmStartIO(bp); + if ((rc = lbmIOWait(bp, 0))) + goto exit; + + /* + * initialize succeeding log pages: lpsn = 0, 1, ..., (N-2) + */ + for (lspn = 0; lspn < npages - 3; lspn++) { + lp->h.page = lp->t.page = cpu_to_le32(lspn); + lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE); + + bp->l_blkno += sbi->nbperpage; + bp->l_flag = lbmWRITE | lbmSYNC | lbmDIRECT; + lbmStartIO(bp); + if ((rc = lbmIOWait(bp, 0))) + goto exit; + } + + rc = 0; +exit: + /* + * finalize log + */ + /* release the buffer */ + lbmFree(bp); + + return rc; +} + + +#ifdef CONFIG_JFS_STATISTICS +int jfs_lmstats_read(char *buffer, char **start, off_t offset, int length, + int *eof, void *data) +{ + int len = 0; + off_t begin; + + len += sprintf(buffer, + "JFS Logmgr stats\n" + "================\n" + "commits = %d\n" + "writes submitted = %d\n" + "writes completed = %d\n", + lmStat.commit, + lmStat.submitted, + lmStat.pagedone); + + begin = offset; + *start = buffer + begin; + len -= begin; + + if (len > length) + len = length; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +#endif /* CONFIG_JFS_STATISTICS */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_logmgr.h linux.20pre2-ac1/fs/jfs/jfs_logmgr.h --- linux.20pre2/fs/jfs/jfs_logmgr.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_logmgr.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,511 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 _H_JFS_LOGMGR +#define _H_JFS_LOGMGR + +#include "jfs_filsys.h" +#include "jfs_lock.h" + +/* + * log manager configuration parameters + */ + +/* log page size */ +#define LOGPSIZE 4096 +#define L2LOGPSIZE 12 + +#define LOGPAGES 16 /* Log pages per mounted file system */ + +/* + * log logical volume + * + * a log is used to make the commit operation on journalled + * files within the same logical volume group atomic. + * a log is implemented with a logical volume. + * there is one log per logical volume group. + * + * block 0 of the log logical volume is not used (ipl etc). + * block 1 contains a log "superblock" and is used by logFormat(), + * lmLogInit(), lmLogShutdown(), and logRedo() to record status + * of the log but is not otherwise used during normal processing. + * blocks 2 - (N-1) are used to contain log records. + * + * when a volume group is varied-on-line, logRedo() must have + * been executed before the file systems (logical volumes) in + * the volume group can be mounted. + */ +/* + * log superblock (block 1 of logical volume) + */ +#define LOGSUPER_B 1 +#define LOGSTART_B 2 + +#define LOGMAGIC 0x87654321 +#define LOGVERSION 1 + +#define MAX_ACTIVE 128 /* Max active file systems sharing log */ + +typedef struct { + u32 magic; /* 4: log lv identifier */ + s32 version; /* 4: version number */ + s32 serial; /* 4: log open/mount counter */ + s32 size; /* 4: size in number of LOGPSIZE blocks */ + s32 bsize; /* 4: logical block size in byte */ + s32 l2bsize; /* 4: log2 of bsize */ + + u32 flag; /* 4: option */ + u32 state; /* 4: state - see below */ + + s32 end; /* 4: addr of last log record set by logredo */ + char uuid[16]; /* 16: 128-bit journal uuid */ + char label[16]; /* 16: journal label */ + struct { + char uuid[16]; + } active[MAX_ACTIVE]; /* 2048: active file systems list */ +} logsuper_t; + +#define NULL_UUID "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + +/* log flag: commit option (see jfs_filsys.h) */ + +/* log state */ +#define LOGMOUNT 0 /* log mounted by lmLogInit() */ +#define LOGREDONE 1 /* log shutdown by lmLogShutdown(). + * log redo completed by logredo(). + */ +#define LOGWRAP 2 /* log wrapped */ +#define LOGREADERR 3 /* log read error detected in logredo() */ + + +/* + * log logical page + * + * (this comment should be rewritten !) + * the header and trailer structures (h,t) will normally have + * the same page and eor value. + * An exception to this occurs when a complete page write is not + * accomplished on a power failure. Since the hardware may "split write" + * sectors in the page, any out of order sequence may occur during powerfail + * and needs to be recognized during log replay. The xor value is + * an "exclusive or" of all log words in the page up to eor. This + * 32 bit eor is stored with the top 16 bits in the header and the + * bottom 16 bits in the trailer. logredo can easily recognize pages + * that were not completed by reconstructing this eor and checking + * the log page. + * + * Previous versions of the operating system did not allow split + * writes and detected partially written records in logredo by + * ordering the updates to the header, trailer, and the move of data + * into the logdata area. The order: (1) data is moved (2) header + * is updated (3) trailer is updated. In logredo, when the header + * differed from the trailer, the header and trailer were reconciled + * as follows: if h.page != t.page they were set to the smaller of + * the two and h.eor and t.eor set to 8 (i.e. empty page). if (only) + * h.eor != t.eor they were set to the smaller of their two values. + */ +typedef struct { + struct { /* header */ + s32 page; /* 4: log sequence page number */ + s16 rsrvd; /* 2: */ + s16 eor; /* 2: end-of-log offset of lasrt record write */ + } h; + + s32 data[LOGPSIZE / 4 - 4]; /* log record area */ + + struct { /* trailer */ + s32 page; /* 4: normally the same as h.page */ + s16 rsrvd; /* 2: */ + s16 eor; /* 2: normally the same as h.eor */ + } t; +} logpage_t; + +#define LOGPHDRSIZE 8 /* log page header size */ +#define LOGPTLRSIZE 8 /* log page trailer size */ + + +/* + * log record + * + * (this comment should be rewritten !) + * jfs uses only "after" log records (only a single writer is allowed + * in a page, pages are written to temporary paging space if + * if they must be written to disk before commit, and i/o is + * scheduled for modified pages to their home location after + * the log records containing the after values and the commit + * record is written to the log on disk, undo discards the copy + * in main-memory.) + * + * a log record consists of a data area of variable length followed by + * a descriptor of fixed size LOGRDSIZE bytes. + * the data area is rounded up to an integral number of 4-bytes and + * must be no longer than LOGPSIZE. + * the descriptor is of size of multiple of 4-bytes and aligned on a + * 4-byte boundary. + * records are packed one after the other in the data area of log pages. + * (sometimes a DUMMY record is inserted so that at least one record ends + * on every page or the longest record is placed on at most two pages). + * the field eor in page header/trailer points to the byte following + * the last record on a page. + */ + +/* log record types */ +#define LOG_COMMIT 0x8000 +#define LOG_SYNCPT 0x4000 +#define LOG_MOUNT 0x2000 +#define LOG_REDOPAGE 0x0800 +#define LOG_NOREDOPAGE 0x0080 +#define LOG_NOREDOINOEXT 0x0040 +#define LOG_UPDATEMAP 0x0008 +#define LOG_NOREDOFILE 0x0001 + +/* REDOPAGE/NOREDOPAGE log record data type */ +#define LOG_INODE 0x0001 +#define LOG_XTREE 0x0002 +#define LOG_DTREE 0x0004 +#define LOG_BTROOT 0x0010 +#define LOG_EA 0x0020 +#define LOG_ACL 0x0040 +#define LOG_DATA 0x0080 +#define LOG_NEW 0x0100 +#define LOG_EXTEND 0x0200 +#define LOG_RELOCATE 0x0400 +#define LOG_DIR_XTREE 0x0800 /* Xtree is in directory inode */ + +/* UPDATEMAP log record descriptor type */ +#define LOG_ALLOCXADLIST 0x0080 +#define LOG_ALLOCPXDLIST 0x0040 +#define LOG_ALLOCXAD 0x0020 +#define LOG_ALLOCPXD 0x0010 +#define LOG_FREEXADLIST 0x0008 +#define LOG_FREEPXDLIST 0x0004 +#define LOG_FREEXAD 0x0002 +#define LOG_FREEPXD 0x0001 + + +typedef struct lrd { + /* + * type independent area + */ + s32 logtid; /* 4: log transaction identifier */ + s32 backchain; /* 4: ptr to prev record of same transaction */ + u16 type; /* 2: record type */ + s16 length; /* 2: length of data in record (in byte) */ + u32 aggregate; /* 4: file system lv/aggregate */ + /* (16) */ + + /* + * type dependent area (20) + */ + union { + + /* + * COMMIT: commit + * + * transaction commit: no type-dependent information; + */ + + /* + * REDOPAGE: after-image + * + * apply after-image; + * + * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format; + */ + struct { + u32 fileset; /* 4: fileset number */ + u32 inode; /* 4: inode number */ + u16 type; /* 2: REDOPAGE record type */ + s16 l2linesize; /* 2: log2 of line size */ + pxd_t pxd; /* 8: on-disk page pxd */ + } redopage; /* (20) */ + + /* + * NOREDOPAGE: the page is freed + * + * do not apply after-image records which precede this record + * in the log with the same page block number to this page. + * + * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format; + */ + struct { + s32 fileset; /* 4: fileset number */ + u32 inode; /* 4: inode number */ + u16 type; /* 2: NOREDOPAGE record type */ + s16 rsrvd; /* 2: reserved */ + pxd_t pxd; /* 8: on-disk page pxd */ + } noredopage; /* (20) */ + + /* + * UPDATEMAP: update block allocation map + * + * either in-line PXD, + * or out-of-line XADLIST; + * + * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format; + */ + struct { + u32 fileset; /* 4: fileset number */ + u32 inode; /* 4: inode number */ + u16 type; /* 2: UPDATEMAP record type */ + s16 nxd; /* 2: number of extents */ + pxd_t pxd; /* 8: pxd */ + } updatemap; /* (20) */ + + /* + * NOREDOINOEXT: the inode extent is freed + * + * do not apply after-image records which precede this + * record in the log with the any of the 4 page block + * numbers in this inode extent. + * + * NOTE: The fileset and pxd fields MUST remain in + * the same fields in the REDOPAGE record format. + * + */ + struct { + s32 fileset; /* 4: fileset number */ + s32 iagnum; /* 4: IAG number */ + s32 inoext_idx; /* 4: inode extent index */ + pxd_t pxd; /* 8: on-disk page pxd */ + } noredoinoext; /* (20) */ + + /* + * SYNCPT: log sync point + * + * replay log upto syncpt address specified; + */ + struct { + s32 sync; /* 4: syncpt address (0 = here) */ + } syncpt; + + /* + * MOUNT: file system mount + * + * file system mount: no type-dependent information; + */ + + /* + * ? FREEXTENT: free specified extent(s) + * + * free specified extent(s) from block allocation map + * N.B.: nextents should be length of data/sizeof(xad_t) + */ + struct { + s32 type; /* 4: FREEXTENT record type */ + s32 nextent; /* 4: number of extents */ + + /* data: PXD or XAD list */ + } freextent; + + /* + * ? NOREDOFILE: this file is freed + * + * do not apply records which precede this record in the log + * with the same inode number. + * + * NOREDILE must be the first to be written at commit + * (last to be read in logredo()) - it prevents + * replay of preceding updates of all preceding generations + * of the inumber esp. the on-disk inode itself, + * but does NOT prevent + * replay of the + */ + struct { + s32 fileset; /* 4: fileset number */ + u32 inode; /* 4: inode number */ + } noredofile; + + /* + * ? NEWPAGE: + * + * metadata type dependent + */ + struct { + s32 fileset; /* 4: fileset number */ + u32 inode; /* 4: inode number */ + s32 type; /* 4: NEWPAGE record type */ + pxd_t pxd; /* 8: on-disk page pxd */ + } newpage; + + /* + * ? DUMMY: filler + * + * no type-dependent information + */ + } log; +} lrd_t; /* (36) */ + +#define LOGRDSIZE (sizeof(struct lrd)) + +/* + * line vector descriptor + */ +typedef struct { + s16 offset; + s16 length; +} lvd_t; + + +/* + * log logical volume + */ +typedef struct jfs_log { + + struct super_block *sb; /* 4: This is used to sync metadata + * before writing syncpt. Will + * need to be a list if we share + * the log between fs's + */ + struct block_device *bdev; /* 4: log lv pointer */ + s32 serial; /* 4: log mount serial number */ + + s64 base; /* @8: log extent address (inline log ) */ + int size; /* 4: log size in log page (in page) */ + int l2bsize; /* 4: log2 of bsize */ + + long flag; /* 4: flag */ + + struct lbuf *lbuf_free; /* 4: free lbufs */ + wait_queue_head_t free_wait; /* 4: */ + + /* log write */ + int logtid; /* 4: log tid */ + int page; /* 4: page number of eol page */ + int eor; /* 4: eor of last record in eol page */ + struct lbuf *bp; /* 4: current log page buffer */ + + struct semaphore loglock; /* 4: log write serialization lock */ + + /* syncpt */ + int nextsync; /* 4: bytes to write before next syncpt */ + int active; /* 4: */ + wait_queue_head_t syncwait; /* 4: */ + + /* commit */ + uint cflag; /* 4: */ + struct { /* 8: FIFO commit queue header */ + struct tblock *head; + struct tblock *tail; + } cqueue; + int gcrtc; /* 4: GC_READY transaction count */ + struct tblock *gclrt; /* 4: latest GC_READY transaction */ + spinlock_t gclock; /* 4: group commit lock */ + int logsize; /* 4: log data area size in byte */ + int lsn; /* 4: end-of-log */ + int clsn; /* 4: clsn */ + int syncpt; /* 4: addr of last syncpt record */ + int sync; /* 4: addr from last logsync() */ + struct list_head synclist; /* 8: logsynclist anchor */ + spinlock_t synclock; /* 4: synclist lock */ + struct lbuf *wqueue; /* 4: log pageout queue */ + int count; /* 4: count */ + char uuid[16]; /* 16: 128-bit uuid of log device */ +} log_t; + +/* + * Log flag + */ +#define log_INLINELOG 1 +#define log_SYNCBARRIER 2 +#define log_QUIESCE 3 + +/* + * group commit flag + */ +/* log_t */ +#define logGC_PAGEOUT 0x00000001 + +/* tblock_t/lbuf_t */ +#define tblkGC_QUEUE 0x0001 +#define tblkGC_READY 0x0002 +#define tblkGC_COMMIT 0x0004 +#define tblkGC_COMMITTED 0x0008 +#define tblkGC_EOP 0x0010 +#define tblkGC_FREE 0x0020 +#define tblkGC_LEADER 0x0040 +#define tblkGC_ERROR 0x0080 +#define tblkGC_LAZY 0x0100 // D230860 +#define tblkGC_UNLOCKED 0x0200 // D230860 + +/* + * log cache buffer header + */ +typedef struct lbuf { + struct buffer_head l_bh; /* for doing I/O */ + log_t *l_log; /* 4: log associated with buffer */ + + /* + * data buffer base area + */ + uint l_flag; /* 4: pageout control flags */ + + struct lbuf *l_wqnext; /* 4: write queue link */ + struct lbuf *l_freelist; /* 4: freelistlink */ + + int l_pn; /* 4: log page number */ + int l_eor; /* 4: log record eor */ + int l_ceor; /* 4: committed log record eor */ + + s64 l_blkno; /* 8: log page block number */ + caddr_t l_ldata; /* 4: data page */ + + wait_queue_head_t l_ioevent; /* 4: i/o done event */ + struct page *l_page; /* The page itself */ +} lbuf_t; + +/* Reuse l_freelist for redrive list */ +#define l_redrive_next l_freelist + +/* + * logsynclist block + * + * common logsyncblk prefix for jbuf_t and tblock_t + */ +typedef struct logsyncblk { + u16 xflag; /* flags */ + u16 flag; /* only meaninful in tblock_t */ + lid_t lid; /* lock id */ + s32 lsn; /* log sequence number */ + struct list_head synclist; /* log sync list link */ +} logsyncblk_t; + +/* + * logsynclist serialization (per log) + */ + +#define LOGSYNC_LOCK_INIT(log) spin_lock_init(&(log)->synclock) +#define LOGSYNC_LOCK(log) spin_lock(&(log)->synclock) +#define LOGSYNC_UNLOCK(log) spin_unlock(&(log)->synclock) + +/* compute the difference in bytes of lsn from sync point */ +#define logdiff(diff, lsn, log)\ +{\ + diff = (lsn) - (log)->syncpt;\ + if (diff < 0)\ + diff += (log)->logsize;\ +} + +extern int lmLogOpen(struct super_block *sb, log_t ** log); +extern int lmLogClose(struct super_block *sb, log_t * log); +extern int lmLogSync(log_t * log, int nosyncwait); +extern int lmLogShutdown(log_t * log); +extern int lmLogInit(log_t * log); +extern int lmLogFormat(log_t *log, s64 logAddress, int logSize); + +#endif /* _H_JFS_LOGMGR */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_metapage.c linux.20pre2-ac1/fs/jfs/jfs_metapage.c --- linux.20pre2/fs/jfs/jfs_metapage.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_metapage.c 2002-08-06 18:00:08.000000000 +0100 @@ -0,0 +1,677 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_metapage.h" +#include "jfs_txnmgr.h" +#include "jfs_debug.h" + +extern struct task_struct *jfsCommitTask; +static spinlock_t meta_lock = SPIN_LOCK_UNLOCKED; +static wait_queue_head_t meta_wait; + +#ifdef CONFIG_JFS_STATISTICS +struct { + uint pagealloc; /* # of page allocations */ + uint pagefree; /* # of page frees */ + uint lockwait; /* # of sleeping lock_metapage() calls */ + uint allocwait; /* # of sleeping alloc_metapage() calls */ +} mpStat; +#endif + + +#define HASH_BITS 10 /* This makes hash_table 1 4K page */ +#define HASH_SIZE (1 << HASH_BITS) +static metapage_t **hash_table = NULL; +static unsigned long hash_order; + + +static inline int metapage_locked(struct metapage *mp) +{ + return test_bit(META_locked, &mp->flag); +} + +static inline int trylock_metapage(struct metapage *mp) +{ + return test_and_set_bit(META_locked, &mp->flag); +} + +static inline void unlock_metapage(struct metapage *mp) +{ + clear_bit(META_locked, &mp->flag); + wake_up(&mp->wait); +} + +static void __lock_metapage(struct metapage *mp) +{ + DECLARE_WAITQUEUE(wait, current); + + INCREMENT(mpStat.lockwait); + + add_wait_queue_exclusive(&mp->wait, &wait); + do { + set_current_state(TASK_UNINTERRUPTIBLE); + if (metapage_locked(mp)) { + spin_unlock(&meta_lock); + schedule(); + spin_lock(&meta_lock); + } + } while (trylock_metapage(mp)); + __set_current_state(TASK_RUNNING); + remove_wait_queue(&mp->wait, &wait); +} + +/* needs meta_lock */ +static inline void lock_metapage(struct metapage *mp) +{ + if (trylock_metapage(mp)) + __lock_metapage(mp); +} + +/* + * metapage pool is based on Linux 2.5's mempool + * + * Tap into reserved structures in critical paths where waiting on a + * memory allocation could cause deadlock + */ +#define METAPOOL_MIN_PAGES 32 +static metapage_t *reserved_metapages[METAPOOL_MIN_PAGES]; +static int num_reserved = 0; +kmem_cache_t *metapage_cache; + +static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) +{ + metapage_t *mp = (metapage_t *)foo; + + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + mp->lid = 0; + mp->lsn = 0; + mp->flag = 0; + mp->data = NULL; + mp->clsn = 0; + mp->log = NULL; + set_bit(META_free, &mp->flag); + init_waitqueue_head(&mp->wait); + } +} + +static void empty_reserved(void) +{ + while (num_reserved--) + kmem_cache_free(metapage_cache, + reserved_metapages[num_reserved]); +} + +static metapage_t *alloc_metapage(int *dropped_lock, int no_wait) +{ + metapage_t *new; + + *dropped_lock = 0; + + /* + * Always try an atomic alloc first, to avoid dropping the + * spinlock + */ + new = kmem_cache_alloc(metapage_cache, GFP_ATOMIC); + if (new) + return new; + + if (no_wait && num_reserved) + return reserved_metapages[--num_reserved]; + + *dropped_lock = 1; + spin_unlock(&meta_lock); + new = kmem_cache_alloc(metapage_cache, GFP_NOFS); + spin_lock(&meta_lock); + return new; +} + +static void __free_metapage(metapage_t *mp) +{ + mp->flag = 0; + set_bit(META_free, &mp->flag); + + if (num_reserved < METAPOOL_MIN_PAGES) + reserved_metapages[num_reserved++] = mp; + else + kmem_cache_free(metapage_cache, mp); +} + +static inline void free_metapage(metapage_t * mp) +{ + spin_lock(&meta_lock); + __free_metapage(mp); + spin_unlock(&meta_lock); +} + +int __init metapage_init(void) +{ + metapage_t *mp; + + /* + * Initialize wait queue + */ + init_waitqueue_head(&meta_wait); + + /* + * Allocate the metapage structures + */ + metapage_cache = kmem_cache_create("jfs_mp", sizeof(metapage_t), 0, 0, + init_once, NULL); + if (metapage_cache == NULL) + return -ENOMEM; + + while (num_reserved < METAPOOL_MIN_PAGES) { + mp = kmem_cache_alloc(metapage_cache, GFP_NOFS); + if (mp) + reserved_metapages[num_reserved++] = mp; + else { + empty_reserved(); + kmem_cache_destroy(metapage_cache); + return -ENOMEM; + } + } + /* + * Now the hash list + */ + for (hash_order = 0; + ((PAGE_SIZE << hash_order) / sizeof(void *)) < HASH_SIZE; + hash_order++); + hash_table = + (metapage_t **) __get_free_pages(GFP_KERNEL, hash_order); + assert(hash_table); + memset(hash_table, 0, PAGE_SIZE << hash_order); + + return 0; +} + +void metapage_exit(void) +{ + empty_reserved(); + kmem_cache_destroy(metapage_cache); +} + +/* + * Basically same hash as in pagemap.h, but using our hash table + */ +static metapage_t **meta_hash(struct address_space *mapping, + unsigned long index) +{ +#define i (((unsigned long)mapping)/ \ + (sizeof(struct inode) & ~(sizeof(struct inode) -1 ))) +#define s(x) ((x) + ((x) >> HASH_BITS)) + return hash_table + (s(i + index) & (HASH_SIZE - 1)); +#undef i +#undef s +} + +static metapage_t *search_hash(metapage_t ** hash_ptr, + struct address_space *mapping, + unsigned long index) +{ + metapage_t *ptr; + + for (ptr = *hash_ptr; ptr; ptr = ptr->hash_next) { + if ((ptr->mapping == mapping) && (ptr->index == index)) + return ptr; + } + + return NULL; +} + +static void add_to_hash(metapage_t * mp, metapage_t ** hash_ptr) +{ + if (*hash_ptr) + (*hash_ptr)->hash_prev = mp; + + mp->hash_prev = NULL; + mp->hash_next = *hash_ptr; + *hash_ptr = mp; +} + +static void remove_from_hash(metapage_t * mp, metapage_t ** hash_ptr) +{ + if (mp->hash_prev) + mp->hash_prev->hash_next = mp->hash_next; + else { + assert(*hash_ptr == mp); + *hash_ptr = mp->hash_next; + } + + if (mp->hash_next) + mp->hash_next->hash_prev = mp->hash_prev; +} + +/* + * Direct address space operations + */ + +static int direct_get_block(struct inode *ip, long lblock, + struct buffer_head *bh_result, int create) +{ + bh_result->b_dev = ip->i_dev; + bh_result->b_blocknr = lblock; + if (create) + bh_result->b_state |= (1UL << BH_Mapped) | (1UL << BH_New); + else + bh_result->b_state |= (1UL << BH_Mapped); + + return 0; +} + +static int direct_writepage(struct page *page) +{ + return block_write_full_page(page, direct_get_block); +} + +static int direct_readpage(struct file *fp, struct page *page) +{ + return block_read_full_page(page, direct_get_block); +} + +static int direct_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + return block_prepare_write(page, from, to, direct_get_block); +} + +static int direct_bmap(struct address_space *mapping, long block) +{ + return generic_block_bmap(mapping, block, direct_get_block); +} + +struct address_space_operations direct_aops = { + readpage: direct_readpage, + writepage: direct_writepage, + sync_page: block_sync_page, + prepare_write: direct_prepare_write, + commit_write: generic_commit_write, + bmap: direct_bmap, +}; + +metapage_t *__get_metapage(struct inode *inode, + unsigned long lblock, unsigned int size, + int absolute, unsigned long new) +{ + int dropped_lock; + metapage_t **hash_ptr; + int l2BlocksPerPage; + int l2bsize; + int no_wait; + struct address_space *mapping; + metapage_t *mp; + unsigned long page_index; + unsigned long page_offset; + + jFYI(1, ("__get_metapage: inode = 0x%p, lblock = 0x%lx\n", + inode, lblock)); + + if (absolute) + mapping = JFS_SBI(inode->i_sb)->direct_mapping; + else + mapping = inode->i_mapping; + + spin_lock(&meta_lock); + + hash_ptr = meta_hash(mapping, lblock); + + mp = search_hash(hash_ptr, mapping, lblock); + if (mp) { + page_found: + if (test_bit(META_discard, &mp->flag)) { + assert(new); /* It's okay to reuse a discarded + * if we expect it to be empty + */ + clear_bit(META_discard, &mp->flag); + } + mp->count++; + jFYI(1, ("__get_metapage: found 0x%p, in hash\n", mp)); + assert(mp->logical_size == size); + lock_metapage(mp); + spin_unlock(&meta_lock); + } else { + l2bsize = inode->i_sb->s_blocksize_bits; + l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize; + page_index = lblock >> l2BlocksPerPage; + page_offset = (lblock - (page_index << l2BlocksPerPage)) << + l2bsize; + if ((page_offset + size) > PAGE_CACHE_SIZE) { + spin_unlock(&meta_lock); + jERROR(1, ("MetaData crosses page boundary!!\n")); + return NULL; + } + + /* + * Locks held on aggregate inode pages are usually + * not held long, and they are taken in critical code + * paths (committing dirty inodes, txCommit thread) + * + * Attempt to get metapage without blocking, tapping into + * reserves if necessary. + */ + if (JFS_IP(inode)->fileset == AGGREGATE_I) + no_wait = 1; + else + no_wait = 0; + + mp = alloc_metapage(&dropped_lock, no_wait); + if (dropped_lock) { + /* alloc_metapage blocked, we need to search the hash + * again. + */ + metapage_t *mp2; + mp2 = search_hash(hash_ptr, mapping, lblock); + if (mp2) { + __free_metapage(mp); + mp = mp2; + goto page_found; + } + } + mp->flag = 0; + lock_metapage(mp); + if (absolute) + set_bit(META_absolute, &mp->flag); + mp->xflag = COMMIT_PAGE; + mp->count = 1; + atomic_set(&mp->nohomeok,0); + mp->mapping = mapping; + mp->index = lblock; + mp->page = 0; + mp->logical_size = size; + add_to_hash(mp, hash_ptr); + if (!absolute) + list_add(&mp->inode_list, &JFS_IP(inode)->mp_list); + spin_unlock(&meta_lock); + + if (new) { + jFYI(1, + ("__get_metapage: Calling grab_cache_page\n")); + mp->page = grab_cache_page(mapping, page_index); + if (!mp->page) { + jERROR(1, ("grab_cache_page failed!\n")); + goto freeit; + } else + INCREMENT(mpStat.pagealloc); + } else { + jFYI(1, + ("__get_metapage: Calling read_cache_page\n")); + mp->page = read_cache_page(mapping, lblock, + (filler_t *)mapping->a_ops->readpage, NULL); + if (IS_ERR(mp->page)) { + jERROR(1, ("read_cache_page failed!\n")); + goto freeit; + } else + INCREMENT(mpStat.pagealloc); + lock_page(mp->page); + } + mp->data = kmap(mp->page) + page_offset; + } + jFYI(1, ("__get_metapage: returning = 0x%p\n", mp)); + return mp; + +freeit: + spin_lock(&meta_lock); + remove_from_hash(mp, hash_ptr); + if (!absolute) + list_del(&mp->inode_list); + __free_metapage(mp); + spin_unlock(&meta_lock); + return NULL; +} + +void hold_metapage(metapage_t * mp, int force) +{ + spin_lock(&meta_lock); + + mp->count++; + + if (force) { + ASSERT (!(test_bit(META_forced, &mp->flag))); + if (trylock_metapage(mp)) + set_bit(META_forced, &mp->flag); + } else + lock_metapage(mp); + + spin_unlock(&meta_lock); +} + +static void __write_metapage(metapage_t * mp) +{ + struct inode *ip = (struct inode *) mp->mapping->host; + unsigned long page_index; + unsigned long page_offset; + int rc; + int l2bsize = ip->i_sb->s_blocksize_bits; + int l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize; + + jFYI(1, ("__write_metapage: mp = 0x%p\n", mp)); + + if (test_bit(META_discard, &mp->flag)) { + /* + * This metadata is no longer valid + */ + clear_bit(META_dirty, &mp->flag); + return; + } + + page_index = mp->page->index; + page_offset = + (mp->index - (page_index << l2BlocksPerPage)) << l2bsize; + + rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset, + page_offset + + mp->logical_size); + if (rc) { + jERROR(1, ("prepare_write return %d!\n", rc)); + ClearPageUptodate(mp->page); + kunmap(mp->page); + clear_bit(META_dirty, &mp->flag); + return; + } + rc = mp->mapping->a_ops->commit_write(NULL, mp->page, page_offset, + page_offset + + mp->logical_size); + if (rc) { + jERROR(1, ("commit_write returned %d\n", rc)); + } + + clear_bit(META_dirty, &mp->flag); + + jFYI(1, ("__write_metapage done\n")); +} + +static inline void sync_metapage(metapage_t *mp) +{ + struct page *page = mp->page; + + page_cache_get(page); + lock_page(page); + + /* we're done with this page - no need to check for errors */ + if (page->buffers) { + writeout_one_page(page); + waitfor_one_page(page); + } + + UnlockPage(page); + page_cache_release(page); +} + +void release_metapage(metapage_t * mp) +{ + log_t *log; + + jFYI(1, + ("release_metapage: mp = 0x%p, flag = 0x%lx\n", mp, + mp->flag)); + + spin_lock(&meta_lock); + if (test_bit(META_forced, &mp->flag)) { + clear_bit(META_forced, &mp->flag); + mp->count--; + spin_unlock(&meta_lock); + return; + } + + assert(mp->count); + if (--mp->count || atomic_read(&mp->nohomeok)) { + unlock_metapage(mp); + spin_unlock(&meta_lock); + } else { + remove_from_hash(mp, meta_hash(mp->mapping, mp->index)); + if (!test_bit(META_absolute, &mp->flag)) + list_del(&mp->inode_list); + spin_unlock(&meta_lock); + + if (mp->page) { + kunmap(mp->page); + mp->data = 0; + if (test_bit(META_dirty, &mp->flag)) + __write_metapage(mp); + UnlockPage(mp->page); + if (test_bit(META_sync, &mp->flag)) { + sync_metapage(mp); + clear_bit(META_sync, &mp->flag); + } + + if (test_bit(META_discard, &mp->flag)) { + lock_page(mp->page); + block_flushpage(mp->page, 0); + unlock_page(mp->page); + } + + page_cache_release(mp->page); + INCREMENT(mpStat.pagefree); + } + + if (mp->lsn) { + /* + * Remove metapage from logsynclist. + */ + log = mp->log; + LOGSYNC_LOCK(log); + mp->log = 0; + mp->lsn = 0; + mp->clsn = 0; + log->count--; + list_del(&mp->synclist); + LOGSYNC_UNLOCK(log); + } + + free_metapage(mp); + } + jFYI(1, ("release_metapage: done\n")); +} + +void invalidate_metapages(struct inode *ip, unsigned long addr, + unsigned long len) +{ + metapage_t **hash_ptr; + unsigned long lblock; + int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_sb->s_blocksize_bits; + struct address_space *mapping = ip->i_mapping; + metapage_t *mp; + struct page *page; + + /* + * First, mark metapages to discard. They will eventually be + * released, but should not be written. + */ + for (lblock = addr; lblock < addr + len; + lblock += 1 << l2BlocksPerPage) { + hash_ptr = meta_hash(mapping, lblock); + spin_lock(&meta_lock); + mp = search_hash(hash_ptr, mapping, lblock); + if (mp) { + set_bit(META_discard, &mp->flag); + spin_unlock(&meta_lock); + /* + * If in the metapage cache, we've got the page locked + */ + block_flushpage(mp->page, 0); + } else { + spin_unlock(&meta_lock); + page = find_lock_page(mapping, lblock>>l2BlocksPerPage); + if (page) { + block_flushpage(page, 0); + UnlockPage(page); + } + } + } +} + +void invalidate_inode_metapages(struct inode *inode) +{ + struct list_head *ptr; + metapage_t *mp; + + spin_lock(&meta_lock); + list_for_each(ptr, &JFS_IP(inode)->mp_list) { + mp = list_entry(ptr, metapage_t, inode_list); + clear_bit(META_dirty, &mp->flag); + set_bit(META_discard, &mp->flag); + kunmap(mp->page); + UnlockPage(mp->page); + page_cache_release(mp->page); + INCREMENT(mpStat.pagefree); + mp->data = 0; + mp->page = 0; + } + spin_unlock(&meta_lock); + truncate_inode_pages(inode->i_mapping, 0); +} + +#ifdef CONFIG_JFS_STATISTICS +int jfs_mpstat_read(char *buffer, char **start, off_t offset, int length, + int *eof, void *data) +{ + int len = 0; + off_t begin; + + len += sprintf(buffer, + "JFS Metapage statistics\n" + "=======================\n" + "page allocations = %d\n" + "page frees = %d\n" + "lock waits = %d\n" + "allocation waits = %d\n", + mpStat.pagealloc, + mpStat.pagefree, + mpStat.lockwait, + mpStat.allocwait); + + begin = offset; + *start = buffer + begin; + len -= begin; + + if (len > length) + len = length; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_metapage.h linux.20pre2-ac1/fs/jfs/jfs_metapage.h --- linux.20pre2/fs/jfs/jfs_metapage.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_metapage.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,118 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 _H_JFS_METAPAGE +#define _H_JFS_METAPAGE + +#include + +typedef struct metapage { + /* Common logsyncblk prefix (see jfs_logmgr.h) */ + u16 xflag; + u16 unused; + lid_t lid; + int lsn; + struct list_head synclist; + /* End of logsyncblk prefix */ + + unsigned long flag; /* See Below */ + unsigned long count; /* Reference count */ + void *data; /* Data pointer */ + + /* list management stuff */ + struct metapage *hash_prev; + struct metapage *hash_next; /* Also used for free list */ + + struct list_head inode_list; /* per-inode metapage list */ + /* + * mapping & index become redundant, but we need these here to + * add the metapage to the hash before we have the real page + */ + struct address_space *mapping; + unsigned long index; + wait_queue_head_t wait; + + /* implementation */ + struct page *page; + unsigned long logical_size; + + /* Journal management */ + int clsn; + atomic_t nohomeok; + struct jfs_log *log; +} metapage_t; + +/* + * Direct-access address space operations + */ +extern struct address_space_operations direct_aops; + +/* metapage flag */ +#define META_locked 0 +#define META_absolute 1 +#define META_free 2 +#define META_dirty 3 +#define META_sync 4 +#define META_discard 5 +#define META_forced 6 + +#define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag) + +/* function prototypes */ +extern metapage_t *__get_metapage(struct inode *inode, + unsigned long lblock, unsigned int size, + int absolute, unsigned long new); + +#define read_metapage(inode, lblock, size, absolute)\ + __get_metapage(inode, lblock, size, absolute, FALSE) + +#define get_metapage(inode, lblock, size, absolute)\ + __get_metapage(inode, lblock, size, absolute, TRUE) + +extern void release_metapage(metapage_t *); +extern void hold_metapage(metapage_t *, int); + +static inline void write_metapage(metapage_t *mp) +{ + set_bit(META_dirty, &mp->flag); + release_metapage(mp); +} + +static inline void flush_metapage(metapage_t *mp) +{ + set_bit(META_sync, &mp->flag); + write_metapage(mp); +} + +static inline void discard_metapage(metapage_t *mp) +{ + clear_bit(META_dirty, &mp->flag); + set_bit(META_discard, &mp->flag); + release_metapage(mp); +} + +/* + * This routine uses hash to explicitly find small number of pages + */ +extern void invalidate_metapages(struct inode *, unsigned long, unsigned long); + +/* + * This one uses mp_list to invalidate all pages for an inode + */ +extern void invalidate_inode_metapages(struct inode *inode); +#endif /* _H_JFS_METAPAGE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_mount.c linux.20pre2-ac1/fs/jfs/jfs_mount.c --- linux.20pre2/fs/jfs/jfs_mount.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_mount.c 2002-08-06 18:01:05.000000000 +0100 @@ -0,0 +1,515 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 + */ + +/* + * Module: jfs_mount.c + * + * note: file system in transition to aggregate/fileset: + * + * file system mount is interpreted as the mount of aggregate, + * if not already mounted, and mount of the single/only fileset in + * the aggregate; + * + * a file system/aggregate is represented by an internal inode + * (aka mount inode) initialized with aggregate superblock; + * each vfs represents a fileset, and points to its "fileset inode + * allocation map inode" (aka fileset inode): + * (an aggregate itself is structured recursively as a filset: + * an internal vfs is constructed and points to its "fileset inode + * allocation map inode" (aka aggregate inode) where each inode + * represents a fileset inode) so that inode number is mapped to + * on-disk inode in uniform way at both aggregate and fileset level; + * + * each vnode/inode of a fileset is linked to its vfs (to facilitate + * per fileset inode operations, e.g., unmount of a fileset, etc.); + * each inode points to the mount inode (to facilitate access to + * per aggregate information, e.g., block size, etc.) as well as + * its file set inode. + * + * aggregate + * ipmnt + * mntvfs -> fileset ipimap+ -> aggregate ipbmap -> aggregate ipaimap; + * fileset vfs -> vp(1) <-> ... <-> vp(n) <->vproot; + */ + +#include +#include "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_superblock.h" +#include "jfs_dmap.h" +#include "jfs_imap.h" +#include "jfs_metapage.h" +#include "jfs_debug.h" + + +/* + * forward references + */ +static int chkSuper(struct super_block *); +static int logMOUNT(struct super_block *sb); + +/* + * NAME: jfs_mount(sb) + * + * FUNCTION: vfs_mount() + * + * PARAMETER: sb - super block + * + * RETURN: EBUSY - device already mounted or open for write + * EBUSY - cvrdvp already mounted; + * EBUSY - mount table full + * ENOTDIR - cvrdvp not directory on a device mount + * ENXIO - device open failure + */ +int jfs_mount(struct super_block *sb) +{ + int rc = 0; /* Return code */ + struct jfs_sb_info *sbi = JFS_SBI(sb); + struct inode *ipaimap = NULL; + struct inode *ipaimap2 = NULL; + struct inode *ipimap = NULL; + struct inode *ipbmap = NULL; + + jFYI(1, ("\nMount JFS\n")); + + /* + * read/validate superblock + * (initialize mount inode from the superblock) + */ + if ((rc = chkSuper(sb))) { + goto errout20; + } + + ipaimap = diReadSpecial(sb, AGGREGATE_I, 0); + if (ipaimap == NULL) { + jERROR(1, ("jfs_mount: Faild to read AGGREGATE_I\n")); + rc = EIO; + goto errout20; + } + sbi->ipaimap = ipaimap; + + jFYI(1, ("jfs_mount: ipaimap:0x%p\n", ipaimap)); + + /* + * initialize aggregate inode allocation map + */ + if ((rc = diMount(ipaimap))) { + jERROR(1, + ("jfs_mount: diMount(ipaimap) failed w/rc = %d\n", + rc)); + goto errout21; + } + + /* + * open aggregate block allocation map + */ + ipbmap = diReadSpecial(sb, BMAP_I, 0); + if (ipbmap == NULL) { + rc = EIO; + goto errout22; + } + + jFYI(1, ("jfs_mount: ipbmap:0x%p\n", ipbmap)); + + sbi->ipbmap = ipbmap; + + /* + * initialize aggregate block allocation map + */ + if ((rc = dbMount(ipbmap))) { + jERROR(1, ("jfs_mount: dbMount failed w/rc = %d\n", rc)); + goto errout22; + } + + /* + * open the secondary aggregate inode allocation map + * + * This is a duplicate of the aggregate inode allocation map. + * + * hand craft a vfs in the same fashion as we did to read ipaimap. + * By adding INOSPEREXT (32) to the inode number, we are telling + * diReadSpecial that we are reading from the secondary aggregate + * inode table. This also creates a unique entry in the inode hash + * table. + */ + if ((sbi->mntflag & JFS_BAD_SAIT) == 0) { + ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1); + if (ipaimap2 == 0) { + jERROR(1, + ("jfs_mount: Faild to read AGGREGATE_I\n")); + rc = EIO; + goto errout35; + } + sbi->ipaimap2 = ipaimap2; + + jFYI(1, ("jfs_mount: ipaimap2:0x%p\n", ipaimap2)); + + /* + * initialize secondary aggregate inode allocation map + */ + if ((rc = diMount(ipaimap2))) { + jERROR(1, + ("jfs_mount: diMount(ipaimap2) failed, rc = %d\n", + rc)); + goto errout35; + } + } else + /* Secondary aggregate inode table is not valid */ + sbi->ipaimap2 = 0; + + /* + * mount (the only/single) fileset + */ + /* + * open fileset inode allocation map (aka fileset inode) + */ + ipimap = diReadSpecial(sb, FILESYSTEM_I, 0); + if (ipimap == NULL) { + jERROR(1, ("jfs_mount: Failed to read FILESYSTEM_I\n")); + /* open fileset secondary inode allocation map */ + rc = EIO; + goto errout40; + } + jFYI(1, ("jfs_mount: ipimap:0x%p\n", ipimap)); + + /* map further access of per fileset inodes by the fileset inode */ + sbi->ipimap = ipimap; + + /* initialize fileset inode allocation map */ + if ((rc = diMount(ipimap))) { + jERROR(1, ("jfs_mount: diMount failed w/rc = %d\n", rc)); + goto errout41; + } + + jFYI(1, ("Mount JFS Complete.\n")); + goto out; + + /* + * unwind on error + */ +//errout42: /* close fileset inode allocation map */ + diUnmount(ipimap, 1); + + errout41: /* close fileset inode allocation map inode */ + diFreeSpecial(ipimap); + + errout40: /* fileset closed */ + + /* close secondary aggregate inode allocation map */ + if (ipaimap2) { + diUnmount(ipaimap2, 1); + diFreeSpecial(ipaimap2); + } + + errout35: + + /* close aggregate block allocation map */ + dbUnmount(ipbmap, 1); + diFreeSpecial(ipbmap); + + errout22: /* close aggregate inode allocation map */ + + diUnmount(ipaimap, 1); + + errout21: /* close aggregate inodes */ + diFreeSpecial(ipaimap); + errout20: /* aggregate closed */ + + out: + + if (rc) { + jERROR(1, ("Mount JFS Failure: %d\n", rc)); + } + return rc; +} + +/* + * NAME: jfs_mount_rw(sb, remount) + * + * FUNCTION: Completes read-write mount, or remounts read-only volume + * as read-write + */ +int jfs_mount_rw(struct super_block *sb, int remount) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + log_t *log; + int rc; + + /* + * If we are re-mounting a previously read-only volume, we want to + * re-read the inode and block maps, since fsck.jfs may have updated + * them. + */ + if (remount) { + if (chkSuper(sb) || (sbi->state != FM_CLEAN)) + return -EINVAL; + + truncate_inode_pages(sbi->ipimap->i_mapping, 0); + truncate_inode_pages(sbi->ipbmap->i_mapping, 0); + diUnmount(sbi->ipimap, 1); + if ((rc = diMount(sbi->ipimap))) { + jERROR(1,("jfs_mount_rw: diMount failed!\n")); + return rc; + } + + dbUnmount(sbi->ipbmap, 1); + if ((rc = dbMount(sbi->ipbmap))) { + jERROR(1,("jfs_mount_rw: dbMount failed!\n")); + return rc; + } + } + + /* + * open/initialize log + */ + if ((rc = lmLogOpen(sb, &log))) + return rc; + + JFS_SBI(sb)->log = log; + + /* + * update file system superblock; + */ + if ((rc = updateSuper(sb, FM_MOUNT))) { + jERROR(1, + ("jfs_mount: updateSuper failed w/rc = %d\n", rc)); + lmLogClose(sb, log); + JFS_SBI(sb)->log = 0; + return rc; + } + + /* + * write MOUNT log record of the file system + */ + logMOUNT(sb); + + return rc; +} + +/* + * chkSuper() + * + * validate the superblock of the file system to be mounted and + * get the file system parameters. + * + * returns + * 0 with fragsize set if check successful + * error code if not successful + */ +static int chkSuper(struct super_block *sb) +{ + int rc = 0; + metapage_t *mp; + struct jfs_sb_info *sbi = JFS_SBI(sb); + struct jfs_superblock *j_sb; + int AIM_bytesize, AIT_bytesize; + int expected_AIM_bytesize, expected_AIT_bytesize; + s64 AIM_byte_addr, AIT_byte_addr, fsckwsp_addr; + s64 byte_addr_diff0, byte_addr_diff1; + s32 bsize; + + if ((rc = readSuper(sb, &mp))) + return rc; + j_sb = (struct jfs_superblock *) (mp->data); + + /* + * validate superblock + */ + /* validate fs signature */ + if (strncmp(j_sb->s_magic, JFS_MAGIC, 4) || + j_sb->s_version > cpu_to_le32(JFS_VERSION)) { + //rc = EFORMAT; + rc = EINVAL; + goto out; + } + + bsize = le32_to_cpu(j_sb->s_bsize); +#ifdef _JFS_4K + if (bsize != PSIZE) { + jERROR(1, ("Currently only 4K block size supported!\n")); + rc = EINVAL; + goto out; + } +#endif /* _JFS_4K */ + + jFYI(1, ("superblock: flag:0x%08x state:0x%08x size:0x%Lx\n", + le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state), + (unsigned long long) le64_to_cpu(j_sb->s_size))); + + /* validate the descriptors for Secondary AIM and AIT */ + if ((j_sb->s_flag & cpu_to_le32(JFS_BAD_SAIT)) != + cpu_to_le32(JFS_BAD_SAIT)) { + expected_AIM_bytesize = 2 * PSIZE; + AIM_bytesize = lengthPXD(&(j_sb->s_aim2)) * bsize; + expected_AIT_bytesize = 4 * PSIZE; + AIT_bytesize = lengthPXD(&(j_sb->s_ait2)) * bsize; + AIM_byte_addr = addressPXD(&(j_sb->s_aim2)) * bsize; + AIT_byte_addr = addressPXD(&(j_sb->s_ait2)) * bsize; + byte_addr_diff0 = AIT_byte_addr - AIM_byte_addr; + fsckwsp_addr = addressPXD(&(j_sb->s_fsckpxd)) * bsize; + byte_addr_diff1 = fsckwsp_addr - AIT_byte_addr; + if ((AIM_bytesize != expected_AIM_bytesize) || + (AIT_bytesize != expected_AIT_bytesize) || + (byte_addr_diff0 != AIM_bytesize) || + (byte_addr_diff1 <= AIT_bytesize)) + j_sb->s_flag |= cpu_to_le32(JFS_BAD_SAIT); + } + + if ((j_sb->s_flag & cpu_to_le32(JFS_GROUPCOMMIT)) != + cpu_to_le32(JFS_GROUPCOMMIT)) + j_sb->s_flag |= cpu_to_le32(JFS_GROUPCOMMIT); + jFYI(0, ("superblock: flag:0x%08x state:0x%08x size:0x%Lx\n", + le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state), + (unsigned long long) le64_to_cpu(j_sb->s_size))); + + /* validate fs state */ + if (j_sb->s_state != cpu_to_le32(FM_CLEAN) && + !(sb->s_flags & MS_RDONLY)) { + jERROR(1, + ("jfs_mount: Mount Failure: File System Dirty.\n")); + rc = EINVAL; + goto out; + } + + sbi->state = le32_to_cpu(j_sb->s_state); + sbi->mntflag = le32_to_cpu(j_sb->s_flag); + + /* + * JFS always does I/O by 4K pages. Don't tell the buffer cache + * that we use anything else (leave s_blocksize alone). + */ + sbi->bsize = bsize; + sbi->l2bsize = le16_to_cpu(j_sb->s_l2bsize); + + /* + * For now, ignore s_pbsize, l2bfactor. All I/O going through buffer + * cache. + */ + sbi->nbperpage = PSIZE >> sbi->l2bsize; + sbi->l2nbperpage = L2PSIZE - sbi->l2bsize; + sbi->l2niperblk = sbi->l2bsize - L2DISIZE; + if (sbi->mntflag & JFS_INLINELOG) + sbi->logpxd = j_sb->s_logpxd; + else { + sbi->logdev = to_kdev_t(le32_to_cpu(j_sb->s_logdev)); + memcpy(sbi->uuid, j_sb->s_uuid, sizeof(sbi->uuid)); + memcpy(sbi->loguuid, j_sb->s_loguuid, sizeof(sbi->uuid)); + } + sbi->fsckpxd = j_sb->s_fsckpxd; + sbi->ait2 = j_sb->s_ait2; + + out: + release_metapage(mp); + + return rc; +} + + +/* + * updateSuper() + * + * update synchronously superblock if it is mounted read-write. + */ +int updateSuper(struct super_block *sb, uint state) +{ + struct jfs_superblock *j_sb; + struct jfs_sb_info *sbi = JFS_SBI(sb); + metapage_t *mp; + int rc; + + /* + * Only fsck can fix dirty state + */ + if (JFS_SBI(sb)->state == FM_DIRTY) + return 0; + + if ((rc = readSuper(sb, &mp))) + return rc; + + j_sb = (struct jfs_superblock *) (mp->data); + + j_sb->s_state = cpu_to_le32(state); + sbi->state = state; + + if (state == FM_MOUNT) { + /* record log's dev_t and mount serial number */ + j_sb->s_logdev = cpu_to_le32(sbi->log->bdev->bd_dev); + j_sb->s_logserial = cpu_to_le32(sbi->log->serial); + } else if (state == FM_CLEAN) { + /* + * If this volume is shared with OS/2, OS/2 will need to + * recalculate DASD usage, since we don't deal with it. + */ + if (j_sb->s_flag & cpu_to_le32(JFS_DASD_ENABLED)) + j_sb->s_flag |= cpu_to_le32(JFS_DASD_PRIME); + } + + flush_metapage(mp); + + return 0; +} + + +/* + * readSuper() + * + * read superblock by raw sector address + */ +int readSuper(struct super_block *sb, metapage_t ** mpp) +{ + /* read in primary superblock */ + *mpp = read_metapage(JFS_SBI(sb)->direct_inode, + SUPER1_OFF >> sb->s_blocksize_bits, PSIZE, 1); + if (*mpp == NULL) { + /* read in secondary/replicated superblock */ + *mpp = read_metapage(JFS_SBI(sb)->direct_inode, + SUPER2_OFF >> sb->s_blocksize_bits, + PSIZE, 1); + } + return *mpp ? 0 : 1; +} + + +/* + * logMOUNT() + * + * function: write a MOUNT log record for file system. + * + * MOUNT record keeps logredo() from processing log records + * for this file system past this point in log. + * it is harmless if mount fails. + * + * note: MOUNT record is at aggregate level, not at fileset level, + * since log records of previous mounts of a fileset + * (e.g., AFTER record of extent allocation) have to be processed + * to update block allocation map at aggregate level. + */ +static int logMOUNT(struct super_block *sb) +{ + log_t *log = JFS_SBI(sb)->log; + lrd_t lrd; + + lrd.logtid = 0; + lrd.backchain = 0; + lrd.type = cpu_to_le16(LOG_MOUNT); + lrd.length = 0; + lrd.aggregate = cpu_to_le32(kdev_t_to_nr(sb->s_dev)); + lmLog(log, NULL, &lrd, NULL); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_superblock.h linux.20pre2-ac1/fs/jfs/jfs_superblock.h --- linux.20pre2/fs/jfs/jfs_superblock.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_superblock.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,112 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 _H_JFS_SUPERBLOCK +#define _H_JFS_SUPERBLOCK + +/* + * make the magic number something a human could read + */ +#define JFS_MAGIC "JFS1" /* Magic word */ + +#define JFS_VERSION 2 /* Version number: Version 2 */ + +#define LV_NAME_SIZE 11 /* MUST BE 11 for OS/2 boot sector */ + +/* + * aggregate superblock + * + * The name superblock is too close to super_block, so the name has been + * changed to jfs_superblock. The utilities are still using the old name. + */ +struct jfs_superblock { + char s_magic[4]; /* 4: magic number */ + u32 s_version; /* 4: version number */ + + s64 s_size; /* 8: aggregate size in hardware/LVM blocks; + * VFS: number of blocks + */ + s32 s_bsize; /* 4: aggregate block size in bytes; + * VFS: fragment size + */ + s16 s_l2bsize; /* 2: log2 of s_bsize */ + s16 s_l2bfactor; /* 2: log2(s_bsize/hardware block size) */ + s32 s_pbsize; /* 4: hardware/LVM block size in bytes */ + s16 s_l2pbsize; /* 2: log2 of s_pbsize */ + s16 pad; /* 2: padding necessary for alignment */ + + u32 s_agsize; /* 4: allocation group size in aggr. blocks */ + + u32 s_flag; /* 4: aggregate attributes: + * see jfs_filsys.h + */ + u32 s_state; /* 4: mount/unmount/recovery state: + * see jfs_filsys.h + */ + s32 s_compress; /* 4: > 0 if data compression */ + + pxd_t s_ait2; /* 8: first extent of secondary + * aggregate inode table + */ + + pxd_t s_aim2; /* 8: first extent of secondary + * aggregate inode map + */ + u32 s_logdev; /* 4: device address of log */ + s32 s_logserial; /* 4: log serial number at aggregate mount */ + pxd_t s_logpxd; /* 8: inline log extent */ + + pxd_t s_fsckpxd; /* 8: inline fsck work space extent */ + + struct timestruc_t s_time; /* 8: time last updated */ + + s32 s_fsckloglen; /* 4: Number of filesystem blocks reserved for + * the fsck service log. + * N.B. These blocks are divided among the + * versions kept. This is not a per + * version size. + * N.B. These blocks are included in the + * length field of s_fsckpxd. + */ + s8 s_fscklog; /* 1: which fsck service log is most recent + * 0 => no service log data yet + * 1 => the first one + * 2 => the 2nd one + */ + char s_fpack[11]; /* 11: file system volume name + * N.B. This must be 11 bytes to + * conform with the OS/2 BootSector + * requirements + * Only used when s_version is 1 + */ + + /* extendfs() parameter under s_state & FM_EXTENDFS */ + s64 s_xsize; /* 8: extendfs s_size */ + pxd_t s_xfsckpxd; /* 8: extendfs fsckpxd */ + pxd_t s_xlogpxd; /* 8: extendfs logpxd */ + /* - 128 byte boundary - */ + + char s_uuid[16]; /* 16: 128-bit uuid for volume */ + char s_label[16]; /* 16: volume label */ + char s_loguuid[16]; /* 16: 128-bit uuid for log device */ + +}; + +extern int readSuper(struct super_block *, struct metapage **); +extern int updateSuper(struct super_block *, uint); + +#endif /*_H_JFS_SUPERBLOCK */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_txnmgr.c linux.20pre2-ac1/fs/jfs/jfs_txnmgr.c --- linux.20pre2/fs/jfs/jfs_txnmgr.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_txnmgr.c 2002-08-06 18:01:05.000000000 +0100 @@ -0,0 +1,3086 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 + */ + +/* + * jfs_txnmgr.c: transaction manager + * + * notes: + * transaction starts with txBegin() and ends with txCommit() + * or txAbort(). + * + * tlock is acquired at the time of update; + * (obviate scan at commit time for xtree and dtree) + * tlock and mp points to each other; + * (no hashlist for mp -> tlock). + * + * special cases: + * tlock on in-memory inode: + * in-place tlock in the in-memory inode itself; + * converted to page lock by iWrite() at commit time. + * + * tlock during write()/mmap() under anonymous transaction (tid = 0): + * transferred (?) to transaction at commit time. + * + * use the page itself to update allocation maps + * (obviate intermediate replication of allocation/deallocation data) + * hold on to mp+lock thru update of maps + */ + + +#include +#include +#include +#include +#include +#include "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_metapage.h" +#include "jfs_dinode.h" +#include "jfs_imap.h" +#include "jfs_dmap.h" +#include "jfs_superblock.h" +#include "jfs_debug.h" + +/* + * transaction management structures + */ +static struct { + /* tblock */ + int freetid; /* 4: index of a free tid structure */ + wait_queue_head_t freewait; /* 4: eventlist of free tblock */ + + /* tlock */ + int freelock; /* 4: index first free lock word */ + wait_queue_head_t freelockwait; /* 4: eventlist of free tlock */ + wait_queue_head_t lowlockwait; /* 4: eventlist of ample tlocks */ + int tlocksInUse; /* 4: Number of tlocks in use */ + spinlock_t LazyLock; /* 4: synchronize sync_queue & unlock_queue */ +/* tblock_t *sync_queue; * 4: Transactions waiting for data sync */ + tblock_t *unlock_queue; /* 4: Transactions waiting to be released */ + tblock_t *unlock_tail; /* 4: Tail of unlock_queue */ + struct list_head anon_list; /* inodes having anonymous txns */ + struct list_head anon_list2; /* inodes having anonymous txns + that couldn't be sync'ed */ +} TxAnchor; + +static int nTxBlock = 512; /* number of transaction blocks */ +struct tblock *TxBlock; /* transaction block table */ + +static int nTxLock = 4096; /* number of transaction locks */ +static int TxLockLWM = 4096*.4; /* Low water mark for number of txLocks used */ +static int TxLockHWM = 4096*.8; /* High water mark for number of txLocks used */ +struct tlock *TxLock; /* transaction lock table */ +static int TlocksLow = 0; /* Indicates low number of available tlocks */ + + +/* + * transaction management lock + */ +static spinlock_t jfsTxnLock = SPIN_LOCK_UNLOCKED; + +#define TXN_LOCK() spin_lock(&jfsTxnLock) +#define TXN_UNLOCK() spin_unlock(&jfsTxnLock) + +#define LAZY_LOCK_INIT() spin_lock_init(&TxAnchor.LazyLock); +#define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags) +#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags) + +DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait); +DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait); + +/* + * Retry logic exist outside these macros to protect from spurrious wakeups. + */ +static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(event, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + TXN_UNLOCK(); + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(event, &wait); +} + +#define TXN_SLEEP(event)\ +{\ + TXN_SLEEP_DROP_LOCK(event);\ + TXN_LOCK();\ +} + +#define TXN_WAKEUP(event) wake_up_all(event) + + +/* + * statistics + */ +struct { + tid_t maxtid; /* 4: biggest tid ever used */ + lid_t maxlid; /* 4: biggest lid ever used */ + int ntid; /* 4: # of transactions performed */ + int nlid; /* 4: # of tlocks acquired */ + int waitlock; /* 4: # of tlock wait */ +} stattx; + + +/* + * external references + */ +extern int lmGroupCommit(log_t * log, tblock_t * tblk); +extern void lmSync(log_t *); +extern int readSuper(struct super_block *sb, metapage_t ** bpp); +extern int jfs_commit_inode(struct inode *, int); +extern int jfs_stop_threads; + +struct task_struct *jfsCommitTask; +extern struct completion jfsIOwait; + +/* + * forward references + */ +int diLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck, + commit_t * cd); +int dataLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck); +void dtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck); +void inlineLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck); +void mapLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck); +void txAbortCommit(commit_t * cd, int exval); +static void txAllocPMap(struct inode *ip, maplock_t * maplock, + tblock_t * tblk); +void txForce(tblock_t * tblk); +static int txLog(log_t * log, tblock_t * tblk, commit_t * cd); +int txMoreLock(void); +static void txUpdateMap(tblock_t * tblk); +static void txRelease(tblock_t * tblk); +void xtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck); +static void LogSyncRelease(metapage_t * mp); + +/* + * transaction block/lock management + * --------------------------------- + */ + +/* + * Get a transaction lock from the free list. If the number in use is + * greater than the high water mark, wake up the sync daemon. This should + * free some anonymous transaction locks. (TXN_LOCK must be held.) + */ +static lid_t txLockAlloc(void) +{ + lid_t lid; + + while (!(lid = TxAnchor.freelock)) + TXN_SLEEP(&TxAnchor.freelockwait); + TxAnchor.freelock = TxLock[lid].next; + HIGHWATERMARK(stattx.maxlid, lid); + if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TlocksLow == 0)) { + jEVENT(0,("txLockAlloc TlocksLow\n")); + TlocksLow = 1; + wake_up(&jfs_sync_thread_wait); + } + + return lid; +} + +static void txLockFree(lid_t lid) +{ + TxLock[lid].next = TxAnchor.freelock; + TxAnchor.freelock = lid; + TxAnchor.tlocksInUse--; + if (TlocksLow && (TxAnchor.tlocksInUse < TxLockLWM)) { + jEVENT(0,("txLockFree TlocksLow no more\n")); + TlocksLow = 0; + TXN_WAKEUP(&TxAnchor.lowlockwait); + } + TXN_WAKEUP(&TxAnchor.freelockwait); +} + +/* + * NAME: txInit() + * + * FUNCTION: initialize transaction management structures + * + * RETURN: + * + * serialization: single thread at jfs_init() + */ +int txInit(void) +{ + int k, size; + + /* + * initialize transaction block (tblock) table + * + * transaction id (tid) = tblock index + * tid = 0 is reserved. + */ + size = sizeof(tblock_t) * nTxBlock; + TxBlock = (tblock_t *) vmalloc(size); + if (TxBlock == NULL) + return ENOMEM; + + for (k = 1; k < nTxBlock - 1; k++) { + TxBlock[k].next = k + 1; + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); + } + TxBlock[k].next = 0; + init_waitqueue_head(&TxBlock[k].gcwait); + init_waitqueue_head(&TxBlock[k].waitor); + + TxAnchor.freetid = 1; + init_waitqueue_head(&TxAnchor.freewait); + + stattx.maxtid = 1; /* statistics */ + + /* + * initialize transaction lock (tlock) table + * + * transaction lock id = tlock index + * tlock id = 0 is reserved. + */ + size = sizeof(tlock_t) * nTxLock; + TxLock = (tlock_t *) vmalloc(size); + if (TxLock == NULL) { + vfree(TxBlock); + return ENOMEM; + } + + /* initialize tlock table */ + for (k = 1; k < nTxLock - 1; k++) + TxLock[k].next = k + 1; + TxLock[k].next = 0; + init_waitqueue_head(&TxAnchor.freelockwait); + init_waitqueue_head(&TxAnchor.lowlockwait); + + TxAnchor.freelock = 1; + TxAnchor.tlocksInUse = 0; + INIT_LIST_HEAD(&TxAnchor.anon_list); + INIT_LIST_HEAD(&TxAnchor.anon_list2); + + stattx.maxlid = 1; /* statistics */ + + return 0; +} + +/* + * NAME: txExit() + * + * FUNCTION: clean up when module is unloaded + */ +void txExit(void) +{ + vfree(TxLock); + TxLock = 0; + vfree(TxBlock); + TxBlock = 0; +} + + +/* + * NAME: txBegin() + * + * FUNCTION: start a transaction. + * + * PARAMETER: sb - superblock + * flag - force for nested tx; + * + * RETURN: tid - transaction id + * + * note: flag force allows to start tx for nested tx + * to prevent deadlock on logsync barrier; + */ +tid_t txBegin(struct super_block *sb, int flag) +{ + tid_t t; + tblock_t *tblk; + log_t *log; + + jFYI(1, ("txBegin: flag = 0x%x\n", flag)); + log = (log_t *) JFS_SBI(sb)->log; + + TXN_LOCK(); + + retry: + if (!(flag & COMMIT_FORCE)) { + /* + * synchronize with logsync barrier + */ + if (test_bit(log_SYNCBARRIER, &log->flag) || + test_bit(log_QUIESCE, &log->flag)) { + TXN_SLEEP(&log->syncwait); + goto retry; + } + } + if (flag == 0) { + /* + * Don't begin transaction if we're getting starved for tlocks + * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately + * free tlocks) + */ + if (TlocksLow) { + TXN_SLEEP(&TxAnchor.lowlockwait); + goto retry; + } + } + + /* + * allocate transaction id/block + */ + if ((t = TxAnchor.freetid) == 0) { + jFYI(1, ("txBegin: waiting for free tid\n")); + TXN_SLEEP(&TxAnchor.freewait); + goto retry; + } + + tblk = tid_to_tblock(t); + + if ((tblk->next == 0) && (current != jfsCommitTask)) { + /* Save one tblk for jfsCommit thread */ + jFYI(1, ("txBegin: waiting for free tid\n")); + TXN_SLEEP(&TxAnchor.freewait); + goto retry; + } + + TxAnchor.freetid = tblk->next; + + /* + * initialize transaction + */ + + /* + * We can't zero the whole thing or we screw up another thread being + * awakened after sleeping on tblk->waitor + * + * memset(tblk, 0, sizeof(tblock_t)); + */ + tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0; + + tblk->sb = sb; + ++log->logtid; + tblk->logtid = log->logtid; + + ++log->active; + + HIGHWATERMARK(stattx.maxtid, t); /* statistics */ + INCREMENT(stattx.ntid); /* statistics */ + + TXN_UNLOCK(); + + jFYI(1, ("txBegin: returning tid = %d\n", t)); + + return t; +} + + +/* + * NAME: txBeginAnon() + * + * FUNCTION: start an anonymous transaction. + * Blocks if logsync or available tlocks are low to prevent + * anonymous tlocks from depleting supply. + * + * PARAMETER: sb - superblock + * + * RETURN: none + */ +void txBeginAnon(struct super_block *sb) +{ + log_t *log; + + log = (log_t *) JFS_SBI(sb)->log; + + TXN_LOCK(); + + retry: + /* + * synchronize with logsync barrier + */ + if (test_bit(log_SYNCBARRIER, &log->flag) || + test_bit(log_QUIESCE, &log->flag)) { + TXN_SLEEP(&log->syncwait); + goto retry; + } + + /* + * Don't begin transaction if we're getting starved for tlocks + */ + if (TlocksLow) { + TXN_SLEEP(&TxAnchor.lowlockwait); + goto retry; + } + TXN_UNLOCK(); +} + + +/* + * txEnd() + * + * function: free specified transaction block. + * + * logsync barrier processing: + * + * serialization: + */ +void txEnd(tid_t tid) +{ + tblock_t *tblk = tid_to_tblock(tid); + log_t *log; + + jFYI(1, ("txEnd: tid = %d\n", tid)); + TXN_LOCK(); + + /* + * wakeup transactions waiting on the page locked + * by the current transaction + */ + TXN_WAKEUP(&tblk->waitor); + + log = (log_t *) JFS_SBI(tblk->sb)->log; + + /* + * Lazy commit thread can't free this guy until we mark it UNLOCKED, + * otherwise, we would be left with a transaction that may have been + * reused. + * + * Lazy commit thread will turn off tblkGC_LAZY before calling this + * routine. + */ + if (tblk->flag & tblkGC_LAZY) { + jFYI(1, + ("txEnd called w/lazy tid: %d, tblk = 0x%p\n", + tid, tblk)); + TXN_UNLOCK(); + + spin_lock_irq(&log->gclock); // LOGGC_LOCK + tblk->flag |= tblkGC_UNLOCKED; + spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK + return; + } + + jFYI(1, ("txEnd: tid: %d, tblk = 0x%p\n", tid, tblk)); + + assert(tblk->next == 0); + + /* + * insert tblock back on freelist + */ + tblk->next = TxAnchor.freetid; + TxAnchor.freetid = tid; + + /* + * mark the tblock not active + */ + --log->active; + + /* + * synchronize with logsync barrier + */ + if (test_bit(log_SYNCBARRIER, &log->flag) && log->active == 0) { + /* forward log syncpt */ + /* lmSync(log); */ + + jFYI(1, (" log barrier off: 0x%x\n", log->lsn)); + + /* enable new transactions start */ + clear_bit(log_SYNCBARRIER, &log->flag); + + /* wakeup all waitors for logsync barrier */ + TXN_WAKEUP(&log->syncwait); + } + + /* + * wakeup all waitors for a free tblock + */ + TXN_WAKEUP(&TxAnchor.freewait); + + TXN_UNLOCK(); + jFYI(1, ("txEnd: exitting\n")); +} + + +/* + * txLock() + * + * function: acquire a transaction lock on the specified + * + * parameter: + * + * return: transaction lock id + * + * serialization: + */ +tlock_t *txLock(tid_t tid, struct inode *ip, metapage_t * mp, int type) +{ + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + int dir_xtree = 0; + lid_t lid; + tid_t xtid; + tlock_t *tlck; + xtlock_t *xtlck; + linelock_t *linelock; + xtpage_t *p; + tblock_t *tblk; + + assert(!test_cflag(COMMIT_Nolink, ip)); + + TXN_LOCK(); + + if (S_ISDIR(ip->i_mode) && (type & tlckXTREE) && + !(mp->xflag & COMMIT_PAGE)) { + /* + * Directory inode is special. It can have both an xtree tlock + * and a dtree tlock associated with it. + */ + dir_xtree = 1; + lid = jfs_ip->xtlid; + } else + lid = mp->lid; + + /* is page not locked by a transaction ? */ + if (lid == 0) + goto allocateLock; + + jFYI(1, ("txLock: tid:%d ip:0x%p mp:0x%p lid:%d\n", + tid, ip, mp, lid)); + + /* is page locked by the requester transaction ? */ + tlck = lid_to_tlock(lid); + if ((xtid = tlck->tid) == tid) + goto grantLock; + + /* + * is page locked by anonymous transaction/lock ? + * + * (page update without transaction (i.e., file write) is + * locked under anonymous transaction tid = 0: + * anonymous tlocks maintained on anonymous tlock list of + * the inode of the page and available to all anonymous + * transactions until txCommit() time at which point + * they are transferred to the transaction tlock list of + * the commiting transaction of the inode) + */ + if (xtid == 0) { + tlck->tid = tid; + tblk = tid_to_tblock(tid); + /* + * The order of the tlocks in the transaction is important + * (during truncate, child xtree pages must be freed before + * parent's tlocks change the working map). + * Take tlock off anonymous list and add to tail of + * transaction list + * + * Note: We really need to get rid of the tid & lid and + * use list_head's. This code is getting UGLY! + */ + if (jfs_ip->atlhead == lid) { + if (jfs_ip->atltail == lid) { + /* only anonymous txn. + * Remove from anon_list + */ + list_del_init(&jfs_ip->anon_inode_list); + } + jfs_ip->atlhead = tlck->next; + } else { + lid_t last; + for (last = jfs_ip->atlhead; + lid_to_tlock(last)->next != lid; + last = lid_to_tlock(last)->next) { + assert(last); + } + lid_to_tlock(last)->next = tlck->next; + if (jfs_ip->atltail == lid) + jfs_ip->atltail = last; + } + + /* insert the tlock at tail of transaction tlock list */ + + if (tblk->next) + lid_to_tlock(tblk->last)->next = lid; + else + tblk->next = lid; + tlck->next = 0; + tblk->last = lid; + + goto grantLock; + } + + goto waitLock; + + /* + * allocate a tlock + */ + allocateLock: + lid = txLockAlloc(); + tlck = lid_to_tlock(lid); + + /* + * initialize tlock + */ + tlck->tid = tid; + + /* mark tlock for meta-data page */ + if (mp->xflag & COMMIT_PAGE) { + + tlck->flag = tlckPAGELOCK; + + /* mark the page dirty and nohomeok */ + mark_metapage_dirty(mp); + atomic_inc(&mp->nohomeok); + + jFYI(1, + ("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p\n", + mp, atomic_read(&mp->nohomeok), tid, tlck)); + + /* if anonymous transaction, and buffer is on the group + * commit synclist, mark inode to show this. This will + * prevent the buffer from being marked nohomeok for too + * long a time. + */ + if ((tid == 0) && mp->lsn) + set_cflag(COMMIT_Synclist, ip); + } + /* mark tlock for in-memory inode */ + else + tlck->flag = tlckINODELOCK; + + tlck->type = 0; + + /* bind the tlock and the page */ + tlck->ip = ip; + tlck->mp = mp; + if (dir_xtree) + jfs_ip->xtlid = lid; + else + mp->lid = lid; + + /* + * enqueue transaction lock to transaction/inode + */ + /* insert the tlock at tail of transaction tlock list */ + if (tid) { + tblk = tid_to_tblock(tid); + if (tblk->next) + lid_to_tlock(tblk->last)->next = lid; + else + tblk->next = lid; + tlck->next = 0; + tblk->last = lid; + } + /* anonymous transaction: + * insert the tlock at head of inode anonymous tlock list + */ + else { + tlck->next = jfs_ip->atlhead; + jfs_ip->atlhead = lid; + if (tlck->next == 0) { + /* This inode's first anonymous transaction */ + jfs_ip->atltail = lid; + list_add_tail(&jfs_ip->anon_inode_list, + &TxAnchor.anon_list); + } + } + + /* initialize type dependent area for linelock */ + linelock = (linelock_t *) & tlck->lock; + linelock->next = 0; + linelock->flag = tlckLINELOCK; + linelock->maxcnt = TLOCKSHORT; + linelock->index = 0; + + switch (type & tlckTYPE) { + case tlckDTREE: + linelock->l2linesize = L2DTSLOTSIZE; + break; + + case tlckXTREE: + linelock->l2linesize = L2XTSLOTSIZE; + + xtlck = (xtlock_t *) linelock; + xtlck->header.offset = 0; + xtlck->header.length = 2; + + if (type & tlckNEW) { + xtlck->lwm.offset = XTENTRYSTART; + } else { + if (mp->xflag & COMMIT_PAGE) + p = (xtpage_t *) mp->data; + else + p = &jfs_ip->i_xtroot; + xtlck->lwm.offset = + le16_to_cpu(p->header.nextindex); + } + xtlck->lwm.length = 0; /* ! */ + xtlck->twm.offset = 0; + xtlck->hwm.offset = 0; + + xtlck->index = 2; + break; + + case tlckINODE: + linelock->l2linesize = L2INODESLOTSIZE; + break; + + case tlckDATA: + linelock->l2linesize = L2DATASLOTSIZE; + break; + + default: + jERROR(1, ("UFO tlock:0x%p\n", tlck)); + } + + /* + * update tlock vector + */ + grantLock: + tlck->type |= type; + + TXN_UNLOCK(); + + return tlck; + + /* + * page is being locked by another transaction: + */ + waitLock: + /* Only locks on ipimap or ipaimap should reach here */ + /* assert(jfs_ip->fileset == AGGREGATE_I); */ + if (jfs_ip->fileset != AGGREGATE_I) { + jERROR(1, ("txLock: trying to lock locked page!\n")); + dump_mem("ip", ip, sizeof(struct inode)); + dump_mem("mp", mp, sizeof(metapage_t)); + dump_mem("Locker's tblk", tid_to_tblock(tid), + sizeof(tblock_t)); + dump_mem("Tlock", tlck, sizeof(tlock_t)); + BUG(); + } + INCREMENT(stattx.waitlock); /* statistics */ + release_metapage(mp); + + jEVENT(0, ("txLock: in waitLock, tid = %d, xtid = %d, lid = %d\n", + tid, xtid, lid)); + TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor); + jEVENT(0, ("txLock: awakened tid = %d, lid = %d\n", tid, lid)); + + return NULL; +} + + +/* + * NAME: txRelease() + * + * FUNCTION: Release buffers associated with transaction locks, but don't + * mark homeok yet. The allows other transactions to modify + * buffers, but won't let them go to disk until commit record + * actually gets written. + * + * PARAMETER: + * tblk - + * + * RETURN: Errors from subroutines. + */ +static void txRelease(tblock_t * tblk) +{ + metapage_t *mp; + lid_t lid; + tlock_t *tlck; + + TXN_LOCK(); + + for (lid = tblk->next; lid; lid = tlck->next) { + tlck = lid_to_tlock(lid); + if ((mp = tlck->mp) != NULL && + (tlck->type & tlckBTROOT) == 0) { + assert(mp->xflag & COMMIT_PAGE); + mp->lid = 0; + } + } + + /* + * wakeup transactions waiting on a page locked + * by the current transaction + */ + TXN_WAKEUP(&tblk->waitor); + + TXN_UNLOCK(); +} + + +/* + * NAME: txUnlock() + * + * FUNCTION: Initiates pageout of pages modified by tid in journalled + * objects and frees their lockwords. + */ +static void txUnlock(tblock_t * tblk) +{ + tlock_t *tlck; + linelock_t *linelock; + lid_t lid, next, llid, k; + metapage_t *mp; + log_t *log; + int difft, diffp; + + jFYI(1, ("txUnlock: tblk = 0x%p\n", tblk)); + log = (log_t *) JFS_SBI(tblk->sb)->log; + + /* + * mark page under tlock homeok (its log has been written): + */ + for (lid = tblk->next; lid; lid = next) { + tlck = lid_to_tlock(lid); + next = tlck->next; + + jFYI(1, ("unlocking lid = %d, tlck = 0x%p\n", lid, tlck)); + + /* unbind page from tlock */ + if ((mp = tlck->mp) != NULL && + (tlck->type & tlckBTROOT) == 0) { + assert(mp->xflag & COMMIT_PAGE); + + /* hold buffer + * + * It's possible that someone else has the metapage. + * The only things were changing are nohomeok, which + * is handled atomically, and clsn which is protected + * by the LOGSYNC_LOCK. + */ + hold_metapage(mp, 1); + + assert(atomic_read(&mp->nohomeok) > 0); + atomic_dec(&mp->nohomeok); + + /* inherit younger/larger clsn */ + LOGSYNC_LOCK(log); + if (mp->clsn) { + logdiff(difft, tblk->clsn, log); + logdiff(diffp, mp->clsn, log); + if (difft > diffp) + mp->clsn = tblk->clsn; + } else + mp->clsn = tblk->clsn; + LOGSYNC_UNLOCK(log); + + assert(!(tlck->flag & tlckFREEPAGE)); + + if (tlck->flag & tlckWRITEPAGE) { + write_metapage(mp); + } else { + /* release page which has been forced */ + release_metapage(mp); + } + } + + /* insert tlock, and linelock(s) of the tlock if any, + * at head of freelist + */ + TXN_LOCK(); + + llid = ((linelock_t *) & tlck->lock)->next; + while (llid) { + linelock = (linelock_t *) lid_to_tlock(llid); + k = linelock->next; + txLockFree(llid); + llid = k; + } + txLockFree(lid); + + TXN_UNLOCK(); + } + tblk->next = tblk->last = 0; + + /* + * remove tblock from logsynclist + * (allocation map pages inherited lsn of tblk and + * has been inserted in logsync list at txUpdateMap()) + */ + if (tblk->lsn) { + LOGSYNC_LOCK(log); + log->count--; + list_del(&tblk->synclist); + LOGSYNC_UNLOCK(log); + } +} + + +/* + * txMaplock() + * + * function: allocate a transaction lock for freed page/entry; + * for freed page, maplock is used as xtlock/dtlock type; + */ +tlock_t *txMaplock(tid_t tid, struct inode *ip, int type) +{ + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + lid_t lid; + tblock_t *tblk; + tlock_t *tlck; + maplock_t *maplock; + + TXN_LOCK(); + + /* + * allocate a tlock + */ + lid = txLockAlloc(); + tlck = lid_to_tlock(lid); + + /* + * initialize tlock + */ + tlck->tid = tid; + + /* bind the tlock and the object */ + tlck->flag = tlckINODELOCK; + tlck->ip = ip; + tlck->mp = NULL; + + tlck->type = type; + + /* + * enqueue transaction lock to transaction/inode + */ + /* insert the tlock at tail of transaction tlock list */ + if (tid) { + tblk = tid_to_tblock(tid); + if (tblk->next) + lid_to_tlock(tblk->last)->next = lid; + else + tblk->next = lid; + tlck->next = 0; + tblk->last = lid; + } + /* anonymous transaction: + * insert the tlock at head of inode anonymous tlock list + */ + else { + tlck->next = jfs_ip->atlhead; + jfs_ip->atlhead = lid; + if (tlck->next == 0) { + /* This inode's first anonymous transaction */ + jfs_ip->atltail = lid; + list_add_tail(&jfs_ip->anon_inode_list, + &TxAnchor.anon_list); + } + } + + TXN_UNLOCK(); + + /* initialize type dependent area for maplock */ + maplock = (maplock_t *) & tlck->lock; + maplock->next = 0; + maplock->maxcnt = 0; + maplock->index = 0; + + return tlck; +} + + +/* + * txLinelock() + * + * function: allocate a transaction lock for log vector list + */ +linelock_t *txLinelock(linelock_t * tlock) +{ + lid_t lid; + tlock_t *tlck; + linelock_t *linelock; + + TXN_LOCK(); + + /* allocate a TxLock structure */ + lid = txLockAlloc(); + tlck = lid_to_tlock(lid); + + TXN_UNLOCK(); + + /* initialize linelock */ + linelock = (linelock_t *) tlck; + linelock->next = 0; + linelock->flag = tlckLINELOCK; + linelock->maxcnt = TLOCKLONG; + linelock->index = 0; + + /* append linelock after tlock */ + linelock->next = tlock->next; + tlock->next = lid; + + return linelock; +} + + + +/* + * transaction commit management + * ----------------------------- + */ + +/* + * NAME: txCommit() + * + * FUNCTION: commit the changes to the objects specified in + * clist. For journalled segments only the + * changes of the caller are committed, ie by tid. + * for non-journalled segments the data are flushed to + * disk and then the change to the disk inode and indirect + * blocks committed (so blocks newly allocated to the + * segment will be made a part of the segment atomically). + * + * all of the segments specified in clist must be in + * one file system. no more than 6 segments are needed + * to handle all unix svcs. + * + * if the i_nlink field (i.e. disk inode link count) + * is zero, and the type of inode is a regular file or + * directory, or symbolic link , the inode is truncated + * to zero length. the truncation is committed but the + * VM resources are unaffected until it is closed (see + * iput and iclose). + * + * PARAMETER: + * + * RETURN: + * + * serialization: + * on entry the inode lock on each segment is assumed + * to be held. + * + * i/o error: + */ +int txCommit(tid_t tid, /* transaction identifier */ + int nip, /* number of inodes to commit */ + struct inode **iplist, /* list of inode to commit */ + int flag) +{ + int rc = 0, rc1 = 0; + commit_t cd; + log_t *log; + tblock_t *tblk; + lrd_t *lrd; + int lsn; + struct inode *ip; + struct jfs_inode_info *jfs_ip; + int k, n; + ino_t top; + struct super_block *sb; + + jFYI(1, ("txCommit, tid = %d, flag = %d\n", tid, flag)); + /* is read-only file system ? */ + if (isReadOnly(iplist[0])) { + rc = EROFS; + goto TheEnd; + } + + sb = cd.sb = iplist[0]->i_sb; + cd.tid = tid; + + if (tid == 0) + tid = txBegin(sb, 0); + tblk = tid_to_tblock(tid); + + /* + * initialize commit structure + */ + log = (log_t *) JFS_SBI(sb)->log; + cd.log = log; + + /* initialize log record descriptor in commit */ + lrd = &cd.lrd; + lrd->logtid = cpu_to_le32(tblk->logtid); + lrd->backchain = 0; + + tblk->xflag |= flag; + + if ((flag & (COMMIT_FORCE | COMMIT_SYNC)) == 0) + tblk->xflag |= COMMIT_LAZY; + /* + * prepare non-journaled objects for commit + * + * flush data pages of non-journaled file + * to prevent the file getting non-initialized disk blocks + * in case of crash. + * (new blocks - ) + */ + cd.iplist = iplist; + cd.nip = nip; + + /* + * acquire transaction lock on (on-disk) inodes + * + * update on-disk inode from in-memory inode + * acquiring transaction locks for AFTER records + * on the on-disk inode of file object + * + * sort the inodes array by inode number in descending order + * to prevent deadlock when acquiring transaction lock + * of on-disk inodes on multiple on-disk inode pages by + * multiple concurrent transactions + */ + for (k = 0; k < cd.nip; k++) { + top = (cd.iplist[k])->i_ino; + for (n = k + 1; n < cd.nip; n++) { + ip = cd.iplist[n]; + if (ip->i_ino > top) { + top = ip->i_ino; + cd.iplist[n] = cd.iplist[k]; + cd.iplist[k] = ip; + } + } + + ip = cd.iplist[k]; + jfs_ip = JFS_IP(ip); + + /* + * BUGBUG - Should we call filemap_fdatasync here instead + * of fsync_inode_data? + * If we do, we have a deadlock condition since we may end + * up recursively calling jfs_get_block with the IWRITELOCK + * held. We may be able to do away with IWRITELOCK while + * committing transactions and use i_sem instead. + */ + if ((!S_ISDIR(ip->i_mode)) + && (tblk->flag & COMMIT_DELETE) == 0) + fsync_inode_data_buffers(ip); + + /* + * Mark inode as not dirty. It will still be on the dirty + * inode list, but we'll know not to commit it again unless + * it gets marked dirty again + */ + clear_cflag(COMMIT_Dirty, ip); + + /* inherit anonymous tlock(s) of inode */ + if (jfs_ip->atlhead) { + lid_to_tlock(jfs_ip->atltail)->next = tblk->next; + tblk->next = jfs_ip->atlhead; + if (!tblk->last) + tblk->last = jfs_ip->atltail; + jfs_ip->atlhead = jfs_ip->atltail = 0; + TXN_LOCK(); + list_del_init(&jfs_ip->anon_inode_list); + TXN_UNLOCK(); + } + + /* + * acquire transaction lock on on-disk inode page + * (become first tlock of the tblk's tlock list) + */ + if (((rc = diWrite(tid, ip)))) + goto out; + } + + /* + * write log records from transaction locks + * + * txUpdateMap() resets XAD_NEW in XAD. + */ + if ((rc = txLog(log, tblk, &cd))) + goto TheEnd; + + /* + * Ensure that inode isn't reused before + * lazy commit thread finishes processing + */ + if (tblk->xflag & (COMMIT_CREATE | COMMIT_DELETE)) + atomic_inc(&tblk->ip->i_count); + + ASSERT((!(tblk->xflag & COMMIT_DELETE)) || + ((tblk->ip->i_nlink == 0) && + !test_cflag(COMMIT_Nolink, tblk->ip))); + + /* + * write COMMIT log record + */ + lrd->type = cpu_to_le16(LOG_COMMIT); + lrd->length = 0; + lsn = lmLog(log, tblk, lrd, NULL); + + lmGroupCommit(log, tblk); + + /* + * - transaction is now committed - + */ + + /* + * force pages in careful update + * (imap addressing structure update) + */ + if (flag & COMMIT_FORCE) + txForce(tblk); + + /* + * update allocation map. + * + * update inode allocation map and inode: + * free pager lock on memory object of inode if any. + * update block allocation map. + * + * txUpdateMap() resets XAD_NEW in XAD. + */ + if (tblk->xflag & COMMIT_FORCE) + txUpdateMap(tblk); + + /* + * free transaction locks and pageout/free pages + */ + txRelease(tblk); + + if ((tblk->flag & tblkGC_LAZY) == 0) + txUnlock(tblk); + + + /* + * reset in-memory object state + */ + for (k = 0; k < cd.nip; k++) { + ip = cd.iplist[k]; + jfs_ip = JFS_IP(ip); + + /* + * reset in-memory inode state + */ + jfs_ip->bxflag = 0; + jfs_ip->blid = 0; + } + + out: + if (rc != 0) + txAbortCommit(&cd, rc); + else + rc = rc1; + + TheEnd: + jFYI(1, ("txCommit: tid = %d, returning %d\n", tid, rc)); + return rc; +} + + +/* + * NAME: txLog() + * + * FUNCTION: Writes AFTER log records for all lines modified + * by tid for segments specified by inodes in comdata. + * Code assumes only WRITELOCKS are recorded in lockwords. + * + * PARAMETERS: + * + * RETURN : + */ +static int txLog(log_t * log, tblock_t * tblk, commit_t * cd) +{ + int rc = 0; + struct inode *ip; + lid_t lid; + tlock_t *tlck; + lrd_t *lrd = &cd->lrd; + + /* + * write log record(s) for each tlock of transaction, + */ + for (lid = tblk->next; lid; lid = tlck->next) { + tlck = lid_to_tlock(lid); + + tlck->flag |= tlckLOG; + + /* initialize lrd common */ + ip = tlck->ip; + lrd->aggregate = cpu_to_le32(kdev_t_to_nr(ip->i_dev)); + lrd->log.redopage.fileset = cpu_to_le32(JFS_IP(ip)->fileset); + lrd->log.redopage.inode = cpu_to_le32(ip->i_ino); + + if (tlck->mp) + hold_metapage(tlck->mp, 0); + + /* write log record of page from the tlock */ + switch (tlck->type & tlckTYPE) { + case tlckXTREE: + xtLog(log, tblk, lrd, tlck); + break; + + case tlckDTREE: + dtLog(log, tblk, lrd, tlck); + break; + + case tlckINODE: + diLog(log, tblk, lrd, tlck, cd); + break; + + case tlckMAP: + mapLog(log, tblk, lrd, tlck); + break; + + case tlckDATA: + dataLog(log, tblk, lrd, tlck); + break; + + default: + jERROR(1, ("UFO tlock:0x%p\n", tlck)); + } + if (tlck->mp) + release_metapage(tlck->mp); + } + + return rc; +} + + +/* + * diLog() + * + * function: log inode tlock and format maplock to update bmap; + */ +int diLog(log_t * log, + tblock_t * tblk, lrd_t * lrd, tlock_t * tlck, commit_t * cd) +{ + int rc = 0; + metapage_t *mp; + pxd_t *pxd; + pxdlock_t *pxdlock; + + mp = tlck->mp; + + /* initialize as REDOPAGE record format */ + lrd->log.redopage.type = cpu_to_le16(LOG_INODE); + lrd->log.redopage.l2linesize = cpu_to_le16(L2INODESLOTSIZE); + + pxd = &lrd->log.redopage.pxd; + + /* + * inode after image + */ + if (tlck->type & tlckENTRY) { + /* log after-image for logredo(): */ + lrd->type = cpu_to_le16(LOG_REDOPAGE); +// *pxd = mp->cm_pxd; + PXDaddress(pxd, mp->index); + PXDlength(pxd, + mp->logical_size >> tblk->sb->s_blocksize_bits); + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + + /* mark page as homeward bound */ + tlck->flag |= tlckWRITEPAGE; + } else if (tlck->type & tlckFREE) { + /* + * free inode extent + * + * (pages of the freed inode extent have been invalidated and + * a maplock for free of the extent has been formatted at + * txLock() time); + * + * the tlock had been acquired on the inode allocation map page + * (iag) that specifies the freed extent, even though the map + * page is not itself logged, to prevent pageout of the map + * page before the log; + */ + assert(tlck->type & tlckFREE); + + /* log LOG_NOREDOINOEXT of the freed inode extent for + * logredo() to start NoRedoPage filters, and to update + * imap and bmap for free of the extent; + */ + lrd->type = cpu_to_le16(LOG_NOREDOINOEXT); + /* + * For the LOG_NOREDOINOEXT record, we need + * to pass the IAG number and inode extent + * index (within that IAG) from which the + * the extent being released. These have been + * passed to us in the iplist[1] and iplist[2]. + */ + lrd->log.noredoinoext.iagnum = + cpu_to_le32((u32) (size_t) cd->iplist[1]); + lrd->log.noredoinoext.inoext_idx = + cpu_to_le32((u32) (size_t) cd->iplist[2]); + + pxdlock = (pxdlock_t *) & tlck->lock; + *pxd = pxdlock->pxd; + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL)); + + /* update bmap */ + tlck->flag |= tlckUPDATEMAP; + + /* mark page as homeward bound */ + tlck->flag |= tlckWRITEPAGE; + } else { + jERROR(2, ("diLog: UFO type tlck:0x%p\n", tlck)); + } +#ifdef _JFS_WIP + /* + * alloc/free external EA extent + * + * a maplock for txUpdateMap() to update bPWMAP for alloc/free + * of the extent has been formatted at txLock() time; + */ + else { + assert(tlck->type & tlckEA); + + /* log LOG_UPDATEMAP for logredo() to update bmap for + * alloc of new (and free of old) external EA extent; + */ + lrd->type = cpu_to_le16(LOG_UPDATEMAP); + pxdlock = (pxdlock_t *) & tlck->lock; + nlock = pxdlock->index; + for (i = 0; i < nlock; i++, pxdlock++) { + if (pxdlock->flag & mlckALLOCPXD) + lrd->log.updatemap.type = + cpu_to_le16(LOG_ALLOCPXD); + else + lrd->log.updatemap.type = + cpu_to_le16(LOG_FREEPXD); + lrd->log.updatemap.nxd = cpu_to_le16(1); + lrd->log.updatemap.pxd = pxdlock->pxd; + lrd->backchain = + cpu_to_le32(lmLog(log, tblk, lrd, NULL)); + } + + /* update bmap */ + tlck->flag |= tlckUPDATEMAP; + } +#endif /* _JFS_WIP */ + + return rc; +} + + +/* + * dataLog() + * + * function: log data tlock + */ +int dataLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck) +{ + metapage_t *mp; + pxd_t *pxd; + int rc; + s64 xaddr; + int xflag; + s32 xlen; + + mp = tlck->mp; + + /* initialize as REDOPAGE record format */ + lrd->log.redopage.type = cpu_to_le16(LOG_DATA); + lrd->log.redopage.l2linesize = cpu_to_le16(L2DATASLOTSIZE); + + pxd = &lrd->log.redopage.pxd; + + /* log after-image for logredo(): */ + lrd->type = cpu_to_le16(LOG_REDOPAGE); + + if (JFS_IP(tlck->ip)->next_index < MAX_INLINE_DIRTABLE_ENTRY) { + /* + * The table has been truncated, we've must have deleted + * the last entry, so don't bother logging this + */ + mp->lid = 0; + atomic_dec(&mp->nohomeok); + discard_metapage(mp); + tlck->mp = 0; + return 0; + } + + rc = xtLookup(tlck->ip, mp->index, 1, &xflag, &xaddr, &xlen, 1); + if (rc || (xlen == 0)) { + jERROR(1, ("dataLog: can't find physical address\n")); + return 0; + } + + PXDaddress(pxd, xaddr); + PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits); + + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + + /* mark page as homeward bound */ + tlck->flag |= tlckWRITEPAGE; + + return 0; +} + + +/* + * dtLog() + * + * function: log dtree tlock and format maplock to update bmap; + */ +void dtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck) +{ + struct inode *ip; + metapage_t *mp; + pxdlock_t *pxdlock; + pxd_t *pxd; + + ip = tlck->ip; + mp = tlck->mp; + + /* initialize as REDOPAGE/NOREDOPAGE record format */ + lrd->log.redopage.type = cpu_to_le16(LOG_DTREE); + lrd->log.redopage.l2linesize = cpu_to_le16(L2DTSLOTSIZE); + + pxd = &lrd->log.redopage.pxd; + + if (tlck->type & tlckBTROOT) + lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT); + + /* + * page extension via relocation: entry insertion; + * page extension in-place: entry insertion; + * new right page from page split, reinitialized in-line + * root from root page split: entry insertion; + */ + if (tlck->type & (tlckNEW | tlckEXTEND)) { + /* log after-image of the new page for logredo(): + * mark log (LOG_NEW) for logredo() to initialize + * freelist and update bmap for alloc of the new page; + */ + lrd->type = cpu_to_le16(LOG_REDOPAGE); + if (tlck->type & tlckEXTEND) + lrd->log.redopage.type |= cpu_to_le16(LOG_EXTEND); + else + lrd->log.redopage.type |= cpu_to_le16(LOG_NEW); +// *pxd = mp->cm_pxd; + PXDaddress(pxd, mp->index); + PXDlength(pxd, + mp->logical_size >> tblk->sb->s_blocksize_bits); + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + + /* format a maplock for txUpdateMap() to update bPMAP for + * alloc of the new page; + */ + if (tlck->type & tlckBTROOT) + return; + tlck->flag |= tlckUPDATEMAP; + pxdlock = (pxdlock_t *) & tlck->lock; + pxdlock->flag = mlckALLOCPXD; + pxdlock->pxd = *pxd; + + pxdlock->index = 1; + + /* mark page as homeward bound */ + tlck->flag |= tlckWRITEPAGE; + return; + } + + /* + * entry insertion/deletion, + * sibling page link update (old right page before split); + */ + if (tlck->type & (tlckENTRY | tlckRELINK)) { + /* log after-image for logredo(): */ + lrd->type = cpu_to_le16(LOG_REDOPAGE); + PXDaddress(pxd, mp->index); + PXDlength(pxd, + mp->logical_size >> tblk->sb->s_blocksize_bits); + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + + /* mark page as homeward bound */ + tlck->flag |= tlckWRITEPAGE; + return; + } + + /* + * page deletion: page has been invalidated + * page relocation: source extent + * + * a maplock for free of the page has been formatted + * at txLock() time); + */ + if (tlck->type & (tlckFREE | tlckRELOCATE)) { + /* log LOG_NOREDOPAGE of the deleted page for logredo() + * to start NoRedoPage filter and to update bmap for free + * of the deletd page + */ + lrd->type = cpu_to_le16(LOG_NOREDOPAGE); + pxdlock = (pxdlock_t *) & tlck->lock; + *pxd = pxdlock->pxd; + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL)); + + /* a maplock for txUpdateMap() for free of the page + * has been formatted at txLock() time; + */ + tlck->flag |= tlckUPDATEMAP; + } + return; +} + + +/* + * xtLog() + * + * function: log xtree tlock and format maplock to update bmap; + */ +void xtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck) +{ + struct inode *ip; + metapage_t *mp; + xtpage_t *p; + xtlock_t *xtlck; + maplock_t *maplock; + xdlistlock_t *xadlock; + pxdlock_t *pxdlock; + pxd_t *pxd; + int next, lwm, hwm; + + ip = tlck->ip; + mp = tlck->mp; + + /* initialize as REDOPAGE/NOREDOPAGE record format */ + lrd->log.redopage.type = cpu_to_le16(LOG_XTREE); + lrd->log.redopage.l2linesize = cpu_to_le16(L2XTSLOTSIZE); + + pxd = &lrd->log.redopage.pxd; + + if (tlck->type & tlckBTROOT) { + lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT); + p = &JFS_IP(ip)->i_xtroot; + if (S_ISDIR(ip->i_mode)) + lrd->log.redopage.type |= + cpu_to_le16(LOG_DIR_XTREE); + } else + p = (xtpage_t *) mp->data; + next = le16_to_cpu(p->header.nextindex); + + xtlck = (xtlock_t *) & tlck->lock; + + maplock = (maplock_t *) & tlck->lock; + xadlock = (xdlistlock_t *) maplock; + + /* + * entry insertion/extension; + * sibling page link update (old right page before split); + */ + if (tlck->type & (tlckNEW | tlckGROW | tlckRELINK)) { + /* log after-image for logredo(): + * logredo() will update bmap for alloc of new/extended + * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from + * after-image of XADlist; + * logredo() resets (XAD_NEW|XAD_EXTEND) flag when + * applying the after-image to the meta-data page. + */ + lrd->type = cpu_to_le16(LOG_REDOPAGE); +// *pxd = mp->cm_pxd; + PXDaddress(pxd, mp->index); + PXDlength(pxd, + mp->logical_size >> tblk->sb->s_blocksize_bits); + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + + /* format a maplock for txUpdateMap() to update bPMAP + * for alloc of new/extended extents of XAD[lwm:next) + * from the page itself; + * txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag. + */ + lwm = xtlck->lwm.offset; + if (lwm == 0) + lwm = XTPAGEMAXSLOT; + + if (lwm == next) + goto out; + assert(lwm < next); + tlck->flag |= tlckUPDATEMAP; + xadlock->flag = mlckALLOCXADLIST; + xadlock->count = next - lwm; + if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) { + int i; + /* + * Lazy commit may allow xtree to be modified before + * txUpdateMap runs. Copy xad into linelock to + * preserve correct data. + */ + xadlock->xdlist = &xtlck->pxdlock; + memcpy(xadlock->xdlist, &p->xad[lwm], + sizeof(xad_t) * xadlock->count); + + for (i = 0; i < xadlock->count; i++) + p->xad[lwm + i].flag &= + ~(XAD_NEW | XAD_EXTENDED); + } else { + /* + * xdlist will point to into inode's xtree, ensure + * that transaction is not committed lazily. + */ + xadlock->xdlist = &p->xad[lwm]; + tblk->xflag &= ~COMMIT_LAZY; + } + jFYI(1, + ("xtLog: alloc ip:0x%p mp:0x%p tlck:0x%p lwm:%d count:%d\n", + tlck->ip, mp, tlck, lwm, xadlock->count)); + + maplock->index = 1; + + out: + /* mark page as homeward bound */ + tlck->flag |= tlckWRITEPAGE; + + return; + } + + /* + * page deletion: file deletion/truncation (ref. xtTruncate()) + * + * (page will be invalidated after log is written and bmap + * is updated from the page); + */ + if (tlck->type & tlckFREE) { + /* LOG_NOREDOPAGE log for NoRedoPage filter: + * if page free from file delete, NoRedoFile filter from + * inode image of zero link count will subsume NoRedoPage + * filters for each page; + * if page free from file truncattion, write NoRedoPage + * filter; + * + * upadte of block allocation map for the page itself: + * if page free from deletion and truncation, LOG_UPDATEMAP + * log for the page itself is generated from processing + * its parent page xad entries; + */ + /* if page free from file truncation, log LOG_NOREDOPAGE + * of the deleted page for logredo() to start NoRedoPage + * filter for the page; + */ + if (tblk->xflag & COMMIT_TRUNCATE) { + /* write NOREDOPAGE for the page */ + lrd->type = cpu_to_le16(LOG_NOREDOPAGE); + PXDaddress(pxd, mp->index); + PXDlength(pxd, + mp->logical_size >> tblk->sb-> + s_blocksize_bits); + lrd->backchain = + cpu_to_le32(lmLog(log, tblk, lrd, NULL)); + + if (tlck->type & tlckBTROOT) { + /* Empty xtree must be logged */ + lrd->type = cpu_to_le16(LOG_REDOPAGE); + lrd->backchain = + cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + } + } + + /* init LOG_UPDATEMAP of the freed extents + * XAD[XTENTRYSTART:hwm) from the deleted page itself + * for logredo() to update bmap; + */ + lrd->type = cpu_to_le16(LOG_UPDATEMAP); + lrd->log.updatemap.type = cpu_to_le16(LOG_FREEXADLIST); + xtlck = (xtlock_t *) & tlck->lock; + hwm = xtlck->hwm.offset; + lrd->log.updatemap.nxd = + cpu_to_le16(hwm - XTENTRYSTART + 1); + /* reformat linelock for lmLog() */ + xtlck->header.offset = XTENTRYSTART; + xtlck->header.length = hwm - XTENTRYSTART + 1; + xtlck->index = 1; + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + + /* format a maplock for txUpdateMap() to update bmap + * to free extents of XAD[XTENTRYSTART:hwm) from the + * deleted page itself; + */ + tlck->flag |= tlckUPDATEMAP; + xadlock->flag = mlckFREEXADLIST; + xadlock->count = hwm - XTENTRYSTART + 1; + if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) { + /* + * Lazy commit may allow xtree to be modified before + * txUpdateMap runs. Copy xad into linelock to + * preserve correct data. + */ + xadlock->xdlist = &xtlck->pxdlock; + memcpy(xadlock->xdlist, &p->xad[XTENTRYSTART], + sizeof(xad_t) * xadlock->count); + } else { + /* + * xdlist will point to into inode's xtree, ensure + * that transaction is not committed lazily unless + * we're deleting the inode (unlink). In that case + * we have special logic for the inode to be + * unlocked by the lazy commit thread. + */ + xadlock->xdlist = &p->xad[XTENTRYSTART]; + if ((tblk->xflag & COMMIT_LAZY) && + (tblk->xflag & COMMIT_DELETE) && + (tblk->ip == ip)) + set_cflag(COMMIT_Holdlock, ip); + else + tblk->xflag &= ~COMMIT_LAZY; + } + jFYI(1, + ("xtLog: free ip:0x%p mp:0x%p count:%d lwm:2\n", + tlck->ip, mp, xadlock->count)); + + maplock->index = 1; + + /* mark page as invalid */ + if (((tblk->xflag & COMMIT_PWMAP) || S_ISDIR(ip->i_mode)) + && !(tlck->type & tlckBTROOT)) + tlck->flag |= tlckFREEPAGE; + /* + else (tblk->xflag & COMMIT_PMAP) + ? release the page; + */ + return; + } + + /* + * page/entry truncation: file truncation (ref. xtTruncate()) + * + * |----------+------+------+---------------| + * | | | + * | | hwm - hwm before truncation + * | next - truncation point + * lwm - lwm before truncation + * header ? + */ + if (tlck->type & tlckTRUNCATE) { + pxd_t tpxd; /* truncated extent of xad */ + int twm; + + /* + * For truncation the entire linelock may be used, so it would + * be difficult to store xad list in linelock itself. + * Therefore, we'll just force transaction to be committed + * synchronously, so that xtree pages won't be changed before + * txUpdateMap runs. + */ + tblk->xflag &= ~COMMIT_LAZY; + lwm = xtlck->lwm.offset; + if (lwm == 0) + lwm = XTPAGEMAXSLOT; + hwm = xtlck->hwm.offset; + twm = xtlck->twm.offset; + + /* + * write log records + */ + /* + * allocate entries XAD[lwm:next]: + */ + if (lwm < next) { + /* log after-image for logredo(): + * logredo() will update bmap for alloc of new/extended + * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from + * after-image of XADlist; + * logredo() resets (XAD_NEW|XAD_EXTEND) flag when + * applying the after-image to the meta-data page. + */ + lrd->type = cpu_to_le16(LOG_REDOPAGE); + PXDaddress(pxd, mp->index); + PXDlength(pxd, + mp->logical_size >> tblk->sb-> + s_blocksize_bits); + lrd->backchain = + cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + } + + /* + * truncate entry XAD[twm == next - 1]: + */ + if (twm == next - 1) { + /* init LOG_UPDATEMAP for logredo() to update bmap for + * free of truncated delta extent of the truncated + * entry XAD[next - 1]: + * (xtlck->pxdlock = truncated delta extent); + */ + pxdlock = (pxdlock_t *) & xtlck->pxdlock; + /* assert(pxdlock->type & tlckTRUNCATE); */ + lrd->type = cpu_to_le16(LOG_UPDATEMAP); + lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD); + lrd->log.updatemap.nxd = cpu_to_le16(1); + lrd->log.updatemap.pxd = pxdlock->pxd; + tpxd = pxdlock->pxd; /* save to format maplock */ + lrd->backchain = + cpu_to_le32(lmLog(log, tblk, lrd, NULL)); + } + + /* + * free entries XAD[next:hwm]: + */ + if (hwm >= next) { + /* init LOG_UPDATEMAP of the freed extents + * XAD[next:hwm] from the deleted page itself + * for logredo() to update bmap; + */ + lrd->type = cpu_to_le16(LOG_UPDATEMAP); + lrd->log.updatemap.type = + cpu_to_le16(LOG_FREEXADLIST); + xtlck = (xtlock_t *) & tlck->lock; + hwm = xtlck->hwm.offset; + lrd->log.updatemap.nxd = + cpu_to_le16(hwm - next + 1); + /* reformat linelock for lmLog() */ + xtlck->header.offset = next; + xtlck->header.length = hwm - next + 1; + xtlck->index = 1; + lrd->backchain = + cpu_to_le32(lmLog(log, tblk, lrd, tlck)); + } + + /* + * format maplock(s) for txUpdateMap() to update bmap + */ + maplock->index = 0; + + /* + * allocate entries XAD[lwm:next): + */ + if (lwm < next) { + /* format a maplock for txUpdateMap() to update bPMAP + * for alloc of new/extended extents of XAD[lwm:next) + * from the page itself; + * txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag. + */ + tlck->flag |= tlckUPDATEMAP; + xadlock->flag = mlckALLOCXADLIST; + xadlock->count = next - lwm; + xadlock->xdlist = &p->xad[lwm]; + + jFYI(1, + ("xtLog: alloc ip:0x%p mp:0x%p count:%d lwm:%d next:%d\n", + tlck->ip, mp, xadlock->count, lwm, next)); + maplock->index++; + xadlock++; + } + + /* + * truncate entry XAD[twm == next - 1]: + */ + if (twm == next - 1) { + pxdlock_t *pxdlock; + + /* format a maplock for txUpdateMap() to update bmap + * to free truncated delta extent of the truncated + * entry XAD[next - 1]; + * (xtlck->pxdlock = truncated delta extent); + */ + tlck->flag |= tlckUPDATEMAP; + pxdlock = (pxdlock_t *) xadlock; + pxdlock->flag = mlckFREEPXD; + pxdlock->count = 1; + pxdlock->pxd = tpxd; + + jFYI(1, + ("xtLog: truncate ip:0x%p mp:0x%p count:%d hwm:%d\n", + ip, mp, pxdlock->count, hwm)); + maplock->index++; + xadlock++; + } + + /* + * free entries XAD[next:hwm]: + */ + if (hwm >= next) { + /* format a maplock for txUpdateMap() to update bmap + * to free extents of XAD[next:hwm] from thedeleted + * page itself; + */ + tlck->flag |= tlckUPDATEMAP; + xadlock->flag = mlckFREEXADLIST; + xadlock->count = hwm - next + 1; + xadlock->xdlist = &p->xad[next]; + + jFYI(1, + ("xtLog: free ip:0x%p mp:0x%p count:%d next:%d hwm:%d\n", + tlck->ip, mp, xadlock->count, next, hwm)); + maplock->index++; + } + + /* mark page as homeward bound */ + tlck->flag |= tlckWRITEPAGE; + } + return; +} + + +/* + * mapLog() + * + * function: log from maplock of freed data extents; + */ +void mapLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck) +{ + pxdlock_t *pxdlock; + int i, nlock; + pxd_t *pxd; + + /* + * page relocation: free the source page extent + * + * a maplock for txUpdateMap() for free of the page + * has been formatted at txLock() time saving the src + * relocated page address; + */ + if (tlck->type & tlckRELOCATE) { + /* log LOG_NOREDOPAGE of the old relocated page + * for logredo() to start NoRedoPage filter; + */ + lrd->type = cpu_to_le16(LOG_NOREDOPAGE); + pxdlock = (pxdlock_t *) & tlck->lock; + pxd = &lrd->log.redopage.pxd; + *pxd = pxdlock->pxd; + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL)); + + /* (N.B. currently, logredo() does NOT update bmap + * for free of the page itself for (LOG_XTREE|LOG_NOREDOPAGE); + * if page free from relocation, LOG_UPDATEMAP log is + * specifically generated now for logredo() + * to update bmap for free of src relocated page; + * (new flag LOG_RELOCATE may be introduced which will + * inform logredo() to start NORedoPage filter and also + * update block allocation map at the same time, thus + * avoiding an extra log write); + */ + lrd->type = cpu_to_le16(LOG_UPDATEMAP); + lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD); + lrd->log.updatemap.nxd = cpu_to_le16(1); + lrd->log.updatemap.pxd = pxdlock->pxd; + lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL)); + + /* a maplock for txUpdateMap() for free of the page + * has been formatted at txLock() time; + */ + tlck->flag |= tlckUPDATEMAP; + return; + } + /* + + * Otherwise it's not a relocate request + * + */ + else { + /* log LOG_UPDATEMAP for logredo() to update bmap for + * free of truncated/relocated delta extent of the data; + * e.g.: external EA extent, relocated/truncated extent + * from xtTailgate(); + */ + lrd->type = cpu_to_le16(LOG_UPDATEMAP); + pxdlock = (pxdlock_t *) & tlck->lock; + nlock = pxdlock->index; + for (i = 0; i < nlock; i++, pxdlock++) { + if (pxdlock->flag & mlckALLOCPXD) + lrd->log.updatemap.type = + cpu_to_le16(LOG_ALLOCPXD); + else + lrd->log.updatemap.type = + cpu_to_le16(LOG_FREEPXD); + lrd->log.updatemap.nxd = cpu_to_le16(1); + lrd->log.updatemap.pxd = pxdlock->pxd; + lrd->backchain = + cpu_to_le32(lmLog(log, tblk, lrd, NULL)); + jFYI(1, ("mapLog: xaddr:0x%lx xlen:0x%x\n", + (ulong) addressPXD(&pxdlock->pxd), + lengthPXD(&pxdlock->pxd))); + } + + /* update bmap */ + tlck->flag |= tlckUPDATEMAP; + } +} + + +/* + * txEA() + * + * function: acquire maplock for EA/ACL extents or + * set COMMIT_INLINE flag; + */ +void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea) +{ + tlock_t *tlck = NULL; + pxdlock_t *maplock = NULL, *pxdlock = NULL; + + /* + * format maplock for alloc of new EA extent + */ + if (newea) { + /* Since the newea could be a completely zeroed entry we need to + * check for the two flags which indicate we should actually + * commit new EA data + */ + if (newea->flag & DXD_EXTENT) { + tlck = txMaplock(tid, ip, tlckMAP); + maplock = (pxdlock_t *) & tlck->lock; + pxdlock = (pxdlock_t *) maplock; + pxdlock->flag = mlckALLOCPXD; + PXDaddress(&pxdlock->pxd, addressDXD(newea)); + PXDlength(&pxdlock->pxd, lengthDXD(newea)); + pxdlock++; + maplock->index = 1; + } else if (newea->flag & DXD_INLINE) { + tlck = NULL; + + set_cflag(COMMIT_Inlineea, ip); + } + } + + /* + * format maplock for free of old EA extent + */ + if (!test_cflag(COMMIT_Nolink, ip) && oldea->flag & DXD_EXTENT) { + if (tlck == NULL) { + tlck = txMaplock(tid, ip, tlckMAP); + maplock = (pxdlock_t *) & tlck->lock; + pxdlock = (pxdlock_t *) maplock; + maplock->index = 0; + } + pxdlock->flag = mlckFREEPXD; + PXDaddress(&pxdlock->pxd, addressDXD(oldea)); + PXDlength(&pxdlock->pxd, lengthDXD(oldea)); + maplock->index++; + } +} + + +/* + * txForce() + * + * function: synchronously write pages locked by transaction + * after txLog() but before txUpdateMap(); + */ +void txForce(tblock_t * tblk) +{ + tlock_t *tlck; + lid_t lid, next; + metapage_t *mp; + + /* + * reverse the order of transaction tlocks in + * careful update order of address index pages + * (right to left, bottom up) + */ + tlck = lid_to_tlock(tblk->next); + lid = tlck->next; + tlck->next = 0; + while (lid) { + tlck = lid_to_tlock(lid); + next = tlck->next; + tlck->next = tblk->next; + tblk->next = lid; + lid = next; + } + + /* + * synchronously write the page, and + * hold the page for txUpdateMap(); + */ + for (lid = tblk->next; lid; lid = next) { + tlck = lid_to_tlock(lid); + next = tlck->next; + + if ((mp = tlck->mp) != NULL && + (tlck->type & tlckBTROOT) == 0) { + assert(mp->xflag & COMMIT_PAGE); + + if (tlck->flag & tlckWRITEPAGE) { + tlck->flag &= ~tlckWRITEPAGE; + + /* do not release page to freelist */ + assert(atomic_read(&mp->nohomeok)); + hold_metapage(mp, 0); + write_metapage(mp); + } + } + } +} + + +/* + * txUpdateMap() + * + * function: update persistent allocation map (and working map + * if appropriate); + * + * parameter: + */ +static void txUpdateMap(tblock_t * tblk) +{ + struct inode *ip; + struct inode *ipimap; + lid_t lid; + tlock_t *tlck; + maplock_t *maplock; + pxdlock_t pxdlock; + int maptype; + int k, nlock; + metapage_t *mp = 0; + + ipimap = JFS_SBI(tblk->sb)->ipimap; + + maptype = (tblk->xflag & COMMIT_PMAP) ? COMMIT_PMAP : COMMIT_PWMAP; + + + /* + * update block allocation map + * + * update allocation state in pmap (and wmap) and + * update lsn of the pmap page; + */ + /* + * scan each tlock/page of transaction for block allocation/free: + * + * for each tlock/page of transaction, update map. + * ? are there tlock for pmap and pwmap at the same time ? + */ + for (lid = tblk->next; lid; lid = tlck->next) { + tlck = lid_to_tlock(lid); + + if ((tlck->flag & tlckUPDATEMAP) == 0) + continue; + + if (tlck->flag & tlckFREEPAGE) { + /* + * Another thread may attempt to reuse freed space + * immediately, so we want to get rid of the metapage + * before anyone else has a chance to get it. + * Lock metapage, update maps, then invalidate + * the metapage. + */ + mp = tlck->mp; + ASSERT(mp->xflag & COMMIT_PAGE); + hold_metapage(mp, 0); + } + + /* + * extent list: + * . in-line PXD list: + * . out-of-line XAD list: + */ + maplock = (maplock_t *) & tlck->lock; + nlock = maplock->index; + + for (k = 0; k < nlock; k++, maplock++) { + /* + * allocate blocks in persistent map: + * + * blocks have been allocated from wmap at alloc time; + */ + if (maplock->flag & mlckALLOC) { + txAllocPMap(ipimap, maplock, tblk); + } + /* + * free blocks in persistent and working map: + * blocks will be freed in pmap and then in wmap; + * + * ? tblock specifies the PMAP/PWMAP based upon + * transaction + * + * free blocks in persistent map: + * blocks will be freed from wmap at last reference + * release of the object for regular files; + * + * Alway free blocks from both persistent & working + * maps for directories + */ + else { /* (maplock->flag & mlckFREE) */ + + if (S_ISDIR(tlck->ip->i_mode)) + txFreeMap(ipimap, maplock, + tblk, COMMIT_PWMAP); + else + txFreeMap(ipimap, maplock, + tblk, maptype); + } + } + if (tlck->flag & tlckFREEPAGE) { + if (!(tblk->flag & tblkGC_LAZY)) { + /* This is equivalent to txRelease */ + ASSERT(mp->lid == lid); + tlck->mp->lid = 0; + } + assert(atomic_read(&mp->nohomeok) == 1); + atomic_dec(&mp->nohomeok); + discard_metapage(mp); + tlck->mp = 0; + } + } + /* + * update inode allocation map + * + * update allocation state in pmap and + * update lsn of the pmap page; + * update in-memory inode flag/state + * + * unlock mapper/write lock + */ + if (tblk->xflag & COMMIT_CREATE) { + ip = tblk->ip; + + ASSERT(test_cflag(COMMIT_New, ip)); + clear_cflag(COMMIT_New, ip); + + diUpdatePMap(ipimap, ip->i_ino, FALSE, tblk); + ipimap->i_state |= I_DIRTY; + /* update persistent block allocation map + * for the allocation of inode extent; + */ + pxdlock.flag = mlckALLOCPXD; + pxdlock.pxd = JFS_IP(ip)->ixpxd; + pxdlock.index = 1; + txAllocPMap(ip, (maplock_t *) & pxdlock, tblk); + iput(ip); + } else if (tblk->xflag & COMMIT_DELETE) { + ip = tblk->ip; + diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk); + ipimap->i_state |= I_DIRTY; + if (test_and_clear_cflag(COMMIT_Holdlock, ip)) { + if (tblk->flag & tblkGC_LAZY) + IWRITE_UNLOCK(ip); + } + iput(ip); + } +} + + +/* + * txAllocPMap() + * + * function: allocate from persistent map; + * + * parameter: + * ipbmap - + * malock - + * xad list: + * pxd: + * + * maptype - + * allocate from persistent map; + * free from persistent map; + * (e.g., tmp file - free from working map at releae + * of last reference); + * free from persistent and working map; + * + * lsn - log sequence number; + */ +static void txAllocPMap(struct inode *ip, maplock_t * maplock, + tblock_t * tblk) +{ + struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; + xdlistlock_t *xadlistlock; + xad_t *xad; + s64 xaddr; + int xlen; + pxdlock_t *pxdlock; + xdlistlock_t *pxdlistlock; + pxd_t *pxd; + int n; + + /* + * allocate from persistent map; + */ + if (maplock->flag & mlckALLOCXADLIST) { + xadlistlock = (xdlistlock_t *) maplock; + xad = xadlistlock->xdlist; + for (n = 0; n < xadlistlock->count; n++, xad++) { + if (xad->flag & (XAD_NEW | XAD_EXTENDED)) { + xaddr = addressXAD(xad); + xlen = lengthXAD(xad); + dbUpdatePMap(ipbmap, FALSE, xaddr, + (s64) xlen, tblk); + xad->flag &= ~(XAD_NEW | XAD_EXTENDED); + jFYI(1, + ("allocPMap: xaddr:0x%lx xlen:%d\n", + (ulong) xaddr, xlen)); + } + } + } else if (maplock->flag & mlckALLOCPXD) { + pxdlock = (pxdlock_t *) maplock; + xaddr = addressPXD(&pxdlock->pxd); + xlen = lengthPXD(&pxdlock->pxd); + dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen, tblk); + jFYI(1, + ("allocPMap: xaddr:0x%lx xlen:%d\n", (ulong) xaddr, + xlen)); + } else { /* (maplock->flag & mlckALLOCPXDLIST) */ + + pxdlistlock = (xdlistlock_t *) maplock; + pxd = pxdlistlock->xdlist; + for (n = 0; n < pxdlistlock->count; n++, pxd++) { + xaddr = addressPXD(pxd); + xlen = lengthPXD(pxd); + dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen, + tblk); + jFYI(1, + ("allocPMap: xaddr:0x%lx xlen:%d\n", + (ulong) xaddr, xlen)); + } + } +} + + +/* + * txFreeMap() + * + * function: free from persistent and/or working map; + * + * todo: optimization + */ +void txFreeMap(struct inode *ip, + maplock_t * maplock, tblock_t * tblk, int maptype) +{ + struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; + xdlistlock_t *xadlistlock; + xad_t *xad; + s64 xaddr; + int xlen; + pxdlock_t *pxdlock; + xdlistlock_t *pxdlistlock; + pxd_t *pxd; + int n; + + jFYI(1, + ("txFreeMap: tblk:0x%p maplock:0x%p maptype:0x%x\n", + tblk, maplock, maptype)); + + /* + * free from persistent map; + */ + if (maptype == COMMIT_PMAP || maptype == COMMIT_PWMAP) { + if (maplock->flag & mlckFREEXADLIST) { + xadlistlock = (xdlistlock_t *) maplock; + xad = xadlistlock->xdlist; + for (n = 0; n < xadlistlock->count; n++, xad++) { + if (!(xad->flag & XAD_NEW)) { + xaddr = addressXAD(xad); + xlen = lengthXAD(xad); + dbUpdatePMap(ipbmap, TRUE, xaddr, + (s64) xlen, tblk); + jFYI(1, + ("freePMap: xaddr:0x%lx xlen:%d\n", + (ulong) xaddr, xlen)); + } + } + } else if (maplock->flag & mlckFREEPXD) { + pxdlock = (pxdlock_t *) maplock; + xaddr = addressPXD(&pxdlock->pxd); + xlen = lengthPXD(&pxdlock->pxd); + dbUpdatePMap(ipbmap, TRUE, xaddr, (s64) xlen, + tblk); + jFYI(1, + ("freePMap: xaddr:0x%lx xlen:%d\n", + (ulong) xaddr, xlen)); + } else { /* (maplock->flag & mlckALLOCPXDLIST) */ + + pxdlistlock = (xdlistlock_t *) maplock; + pxd = pxdlistlock->xdlist; + for (n = 0; n < pxdlistlock->count; n++, pxd++) { + xaddr = addressPXD(pxd); + xlen = lengthPXD(pxd); + dbUpdatePMap(ipbmap, TRUE, xaddr, + (s64) xlen, tblk); + jFYI(1, + ("freePMap: xaddr:0x%lx xlen:%d\n", + (ulong) xaddr, xlen)); + } + } + } + + /* + * free from working map; + */ + if (maptype == COMMIT_PWMAP || maptype == COMMIT_WMAP) { + if (maplock->flag & mlckFREEXADLIST) { + xadlistlock = (xdlistlock_t *) maplock; + xad = xadlistlock->xdlist; + for (n = 0; n < xadlistlock->count; n++, xad++) { + xaddr = addressXAD(xad); + xlen = lengthXAD(xad); + dbFree(ip, xaddr, (s64) xlen); + xad->flag = 0; + jFYI(1, + ("freeWMap: xaddr:0x%lx xlen:%d\n", + (ulong) xaddr, xlen)); + } + } else if (maplock->flag & mlckFREEPXD) { + pxdlock = (pxdlock_t *) maplock; + xaddr = addressPXD(&pxdlock->pxd); + xlen = lengthPXD(&pxdlock->pxd); + dbFree(ip, xaddr, (s64) xlen); + jFYI(1, + ("freeWMap: xaddr:0x%lx xlen:%d\n", + (ulong) xaddr, xlen)); + } else { /* (maplock->flag & mlckFREEPXDLIST) */ + + pxdlistlock = (xdlistlock_t *) maplock; + pxd = pxdlistlock->xdlist; + for (n = 0; n < pxdlistlock->count; n++, pxd++) { + xaddr = addressPXD(pxd); + xlen = lengthPXD(pxd); + dbFree(ip, xaddr, (s64) xlen); + jFYI(1, + ("freeWMap: xaddr:0x%lx xlen:%d\n", + (ulong) xaddr, xlen)); + } + } + } +} + + +/* + * txFreelock() + * + * function: remove tlock from inode anonymous locklist + */ +void txFreelock(struct inode *ip) +{ + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + tlock_t *xtlck, *tlck; + lid_t xlid = 0, lid; + + if (!jfs_ip->atlhead) + return; + + xtlck = (tlock_t *) &jfs_ip->atlhead; + + while ((lid = xtlck->next)) { + tlck = lid_to_tlock(lid); + if (tlck->flag & tlckFREELOCK) { + xtlck->next = tlck->next; + txLockFree(lid); + } else { + xtlck = tlck; + xlid = lid; + } + } + + if (jfs_ip->atlhead) + jfs_ip->atltail = xlid; + else { + jfs_ip->atltail = 0; + /* + * If inode was on anon_list, remove it + */ + TXN_LOCK(); + list_del_init(&jfs_ip->anon_inode_list); + TXN_UNLOCK(); + } +} + + +/* + * txAbort() + * + * function: abort tx before commit; + * + * frees line-locks and segment locks for all + * segments in comdata structure. + * Optionally sets state of file-system to FM_DIRTY in super-block. + * log age of page-frames in memory for which caller has + * are reset to 0 (to avoid logwarap). + */ +void txAbort(tid_t tid, int dirty) +{ + lid_t lid, next; + metapage_t *mp; + tblock_t *tblk = tid_to_tblock(tid); + + jEVENT(1, ("txAbort: tid:%d dirty:0x%x\n", tid, dirty)); + + /* + * free tlocks of the transaction + */ + for (lid = tblk->next; lid; lid = next) { + next = lid_to_tlock(lid)->next; + + mp = lid_to_tlock(lid)->mp; + + if (mp) { + mp->lid = 0; + + /* + * reset lsn of page to avoid logwarap: + * + * (page may have been previously committed by another + * transaction(s) but has not been paged, i.e., + * it may be on logsync list even though it has not + * been logged for the current tx.) + */ + if (mp->xflag & COMMIT_PAGE && mp->lsn) + LogSyncRelease(mp); + } + /* insert tlock at head of freelist */ + TXN_LOCK(); + txLockFree(lid); + TXN_UNLOCK(); + } + + /* caller will free the transaction block */ + + tblk->next = tblk->last = 0; + + /* + * mark filesystem dirty + */ + if (dirty) + updateSuper(tblk->sb, FM_DIRTY); + + return; +} + + +/* + * txAbortCommit() + * + * function: abort commit. + * + * frees tlocks of transaction; line-locks and segment locks for all + * segments in comdata structure. frees malloc storage + * sets state of file-system to FM_MDIRTY in super-block. + * log age of page-frames in memory for which caller has + * are reset to 0 (to avoid logwarap). + */ +void txAbortCommit(commit_t * cd, int exval) +{ + tblock_t *tblk; + tid_t tid; + lid_t lid, next; + metapage_t *mp; + + assert(exval == EIO || exval == ENOMEM); + jEVENT(1, ("txAbortCommit: cd:0x%p\n", cd)); + + /* + * free tlocks of the transaction + */ + tid = cd->tid; + tblk = tid_to_tblock(tid); + for (lid = tblk->next; lid; lid = next) { + next = lid_to_tlock(lid)->next; + + mp = lid_to_tlock(lid)->mp; + if (mp) { + mp->lid = 0; + + /* + * reset lsn of page to avoid logwarap; + */ + if (mp->xflag & COMMIT_PAGE) + LogSyncRelease(mp); + } + + /* insert tlock at head of freelist */ + TXN_LOCK(); + txLockFree(lid); + TXN_UNLOCK(); + } + + tblk->next = tblk->last = 0; + + /* free the transaction block */ + txEnd(tid); + + /* + * mark filesystem dirty + */ + updateSuper(cd->sb, FM_DIRTY); +} + + +/* + * txLazyCommit(void) + * + * All transactions except those changing ipimap (COMMIT_FORCE) are + * processed by this routine. This insures that the inode and block + * allocation maps are updated in order. For synchronous transactions, + * let the user thread finish processing after txUpdateMap() is called. + */ +void txLazyCommit(tblock_t * tblk) +{ + log_t *log; + + while (((tblk->flag & tblkGC_READY) == 0) && + ((tblk->flag & tblkGC_UNLOCKED) == 0)) { + /* We must have gotten ahead of the user thread + */ + jFYI(1, + ("jfs_lazycommit: tblk 0x%p not unlocked\n", tblk)); + schedule(); + } + + jFYI(1, ("txLazyCommit: processing tblk 0x%p\n", tblk)); + + txUpdateMap(tblk); + + log = (log_t *) JFS_SBI(tblk->sb)->log; + + spin_lock_irq(&log->gclock); // LOGGC_LOCK + + tblk->flag |= tblkGC_COMMITTED; + + if ((tblk->flag & tblkGC_READY) || (tblk->flag & tblkGC_LAZY)) + log->gcrtc--; + + if (tblk->flag & tblkGC_READY) + wake_up(&tblk->gcwait); // LOGGC_WAKEUP + + spin_unlock_irq(&log->gclock); // LOGGC_UNLOCK + + if (tblk->flag & tblkGC_LAZY) { + txUnlock(tblk); + tblk->flag &= ~tblkGC_LAZY; + txEnd(tblk - TxBlock); /* Convert back to tid */ + } + + jFYI(1, ("txLazyCommit: done: tblk = 0x%p\n", tblk)); +} + +/* + * jfs_lazycommit(void) + * + * To be run as a kernel daemon. If lbmIODone is called in an interrupt + * context, or where blocking is not wanted, this routine will process + * committed transactions from the unlock queue. + */ +int jfs_lazycommit(void) +{ + int WorkDone; + tblock_t *tblk; + unsigned long flags; + + lock_kernel(); + + daemonize(); + current->tty = NULL; + strcpy(current->comm, "jfsCommit"); + + unlock_kernel(); + + jfsCommitTask = current; + + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + LAZY_LOCK_INIT(); + TxAnchor.unlock_queue = TxAnchor.unlock_tail = 0; + + complete(&jfsIOwait); + + do { + DECLARE_WAITQUEUE(wq, current); + + LAZY_LOCK(flags); +restart: + WorkDone = 0; + while ((tblk = TxAnchor.unlock_queue)) { + /* + * We can't get ahead of user thread. Spinning is + * simpler than blocking/waking. We shouldn't spin + * very long, since user thread shouldn't be blocking + * between lmGroupCommit & txEnd. + */ + WorkDone = 1; + + /* + * Remove first transaction from queue + */ + TxAnchor.unlock_queue = tblk->cqnext; + tblk->cqnext = 0; + if (TxAnchor.unlock_tail == tblk) + TxAnchor.unlock_tail = 0; + + LAZY_UNLOCK(flags); + txLazyCommit(tblk); + + /* + * We can be running indefinately if other processors + * are adding transactions to this list + */ + if (current->need_resched) + schedule(); + LAZY_LOCK(flags); + } + + if (WorkDone) + goto restart; + + add_wait_queue(&jfs_commit_thread_wait, &wq); + set_current_state(TASK_INTERRUPTIBLE); + LAZY_UNLOCK(flags); + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&jfs_commit_thread_wait, &wq); + } while (!jfs_stop_threads); + + if (TxAnchor.unlock_queue) + jERROR(1, ("jfs_lazycommit being killed with pending transactions!\n")); + else + jFYI(1, ("jfs_lazycommit being killed\n")); + complete(&jfsIOwait); + return 0; +} + +void txLazyUnlock(tblock_t * tblk) +{ + unsigned long flags; + + LAZY_LOCK(flags); + + if (TxAnchor.unlock_tail) + TxAnchor.unlock_tail->cqnext = tblk; + else + TxAnchor.unlock_queue = tblk; + TxAnchor.unlock_tail = tblk; + tblk->cqnext = 0; + LAZY_UNLOCK(flags); + wake_up(&jfs_commit_thread_wait); +} + +static void LogSyncRelease(metapage_t * mp) +{ + log_t *log = mp->log; + + assert(atomic_read(&mp->nohomeok)); + assert(log); + atomic_dec(&mp->nohomeok); + + if (atomic_read(&mp->nohomeok)) + return; + + hold_metapage(mp, 0); + + LOGSYNC_LOCK(log); + mp->log = NULL; + mp->lsn = 0; + mp->clsn = 0; + log->count--; + list_del_init(&mp->synclist); + LOGSYNC_UNLOCK(log); + + release_metapage(mp); +} + +/* + * txQuiesce + * + * Block all new transactions and push anonymous transactions to + * completion + * + * This does almost the same thing as jfs_sync below. We don't + * worry about deadlocking when TlocksLow is set, since we would + * expect jfs_sync to get us out of that jam. + */ +void txQuiesce(struct super_block *sb) +{ + struct inode *ip; + struct jfs_inode_info *jfs_ip; + log_t *log = JFS_SBI(sb)->log; + int rc; + tid_t tid; + + set_bit(log_QUIESCE, &log->flag); + + TXN_LOCK(); +restart: + while (!list_empty(&TxAnchor.anon_list)) { + jfs_ip = list_entry(TxAnchor.anon_list.next, + struct jfs_inode_info, + anon_inode_list); + ip = jfs_ip->inode; + + /* + * inode will be removed from anonymous list + * when it is committed + */ + TXN_UNLOCK(); + tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE); + down(&jfs_ip->commit_sem); + rc = txCommit(tid, 1, &ip, 0); + txEnd(tid); + up(&jfs_ip->commit_sem); + /* + * Just to be safe. I don't know how + * long we can run without blocking + */ + if (current->need_resched) + schedule(); + TXN_LOCK(); + } + + /* + * If jfs_sync is running in parallel, there could be some inodes + * on anon_list2. Let's check. + */ + if (!list_empty(&TxAnchor.anon_list2)) { + list_splice(&TxAnchor.anon_list2, &TxAnchor.anon_list); + INIT_LIST_HEAD(&TxAnchor.anon_list2); + goto restart; + } + TXN_UNLOCK(); +} + +/* + * txResume() + * + * Allows transactions to start again following txQuiesce + */ +void txResume(struct super_block *sb) +{ + log_t *log = JFS_SBI(sb)->log; + + clear_bit(log_QUIESCE, &log->flag); + TXN_WAKEUP(&log->syncwait); +} + +/* + * jfs_sync(void) + * + * To be run as a kernel daemon. This is awakened when tlocks run low. + * We write any inodes that have anonymous tlocks so they will become + * available. + */ +int jfs_sync(void) +{ + struct inode *ip; + struct jfs_inode_info *jfs_ip; + int rc; + tid_t tid; + + lock_kernel(); + + daemonize(); + current->tty = NULL; + strcpy(current->comm, "jfsSync"); + + unlock_kernel(); + + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + complete(&jfsIOwait); + + do { + DECLARE_WAITQUEUE(wq, current); + /* + * write each inode on the anonymous inode list + */ + TXN_LOCK(); + while (TlocksLow && !list_empty(&TxAnchor.anon_list)) { + jfs_ip = list_entry(TxAnchor.anon_list.next, + struct jfs_inode_info, + anon_inode_list); + ip = jfs_ip->inode; + + /* + * down_trylock returns 0 on success. This is + * inconsistent with spin_trylock. + */ + if (! down_trylock(&jfs_ip->commit_sem)) { + /* + * inode will be removed from anonymous list + * when it is committed + */ + TXN_UNLOCK(); + tid = txBegin(ip->i_sb, + COMMIT_INODE | COMMIT_FORCE); + rc = txCommit(tid, 1, &ip, 0); + txEnd(tid); + up(&jfs_ip->commit_sem); + /* + * Just to be safe. I don't know how + * long we can run without blocking + */ + if (current->need_resched) + schedule(); + TXN_LOCK(); + } else { + /* We can't get the commit semaphore. It may + * be held by a thread waiting for tlock's + * so let's not block here. Save it to + * put back on the anon_list. + */ + + /* Take off anon_list */ + list_del(&jfs_ip->anon_inode_list); + + /* Put on anon_list2 */ + list_add(&jfs_ip->anon_inode_list, + &TxAnchor.anon_list2); + } + } + /* Add anon_list2 back to anon_list */ + if (!list_empty(&TxAnchor.anon_list2)) { + list_splice(&TxAnchor.anon_list2, &TxAnchor.anon_list); + INIT_LIST_HEAD(&TxAnchor.anon_list2); + } + add_wait_queue(&jfs_sync_thread_wait, &wq); + set_current_state(TASK_INTERRUPTIBLE); + TXN_UNLOCK(); + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&jfs_sync_thread_wait, &wq); + } while (!jfs_stop_threads); + + jFYI(1, ("jfs_sync being killed\n")); + complete(&jfsIOwait); + return 0; +} + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG) +int jfs_txanchor_read(char *buffer, char **start, off_t offset, int length, + int *eof, void *data) +{ + int len = 0; + off_t begin; + char *freewait; + char *freelockwait; + char *lowlockwait; + + freewait = + waitqueue_active(&TxAnchor.freewait) ? "active" : "empty"; + freelockwait = + waitqueue_active(&TxAnchor.freelockwait) ? "active" : "empty"; + lowlockwait = + waitqueue_active(&TxAnchor.lowlockwait) ? "active" : "empty"; + + len += sprintf(buffer, + "JFS TxAnchor\n" + "============\n" + "freetid = %d\n" + "freewait = %s\n" + "freelock = %d\n" + "freelockwait = %s\n" + "lowlockwait = %s\n" + "tlocksInUse = %d\n" + "unlock_queue = 0x%p\n" + "unlock_tail = 0x%p\n", + TxAnchor.freetid, + freewait, + TxAnchor.freelock, + freelockwait, + lowlockwait, + TxAnchor.tlocksInUse, + TxAnchor.unlock_queue, + TxAnchor.unlock_tail); + + begin = offset; + *start = buffer + begin; + len -= begin; + + if (len > length) + len = length; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_txnmgr.h linux.20pre2-ac1/fs/jfs/jfs_txnmgr.h --- linux.20pre2/fs/jfs/jfs_txnmgr.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_txnmgr.h 2002-08-14 14:41:30.000000000 +0100 @@ -0,0 +1,316 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 _H_JFS_TXNMGR +#define _H_JFS_TXNMGR + +#include "jfs_logmgr.h" + +/* + * Hide implementation of TxBlock and TxLock + */ +#define tid_to_tblock(tid) (&TxBlock[tid]) + +#define lid_to_tlock(lid) (&TxLock[lid]) + +/* + * transaction block + */ +typedef struct tblock { + /* + * tblock_t and jbuf_t common area: struct logsyncblk + * + * the following 5 fields are the same as struct logsyncblk + * which is common to tblock and jbuf to form logsynclist + */ + u16 xflag; /* tx commit type */ + u16 flag; /* tx commit state */ + lid_t dummy; /* Must keep structures common */ + s32 lsn; /* recovery lsn */ + struct list_head synclist; /* logsynclist link */ + + /* lock management */ + struct super_block *sb; /* 4: super block */ + lid_t next; /* 2: index of first tlock of tid */ + lid_t last; /* 2: index of last tlock of tid */ + wait_queue_head_t waitor; /* 4: tids waiting on this tid */ + + /* log management */ + u32 logtid; /* 4: log transaction id */ + /* (32) */ + + /* commit management */ + struct tblock *cqnext; /* 4: commit queue link */ + s32 clsn; /* 4: commit lsn */ + struct lbuf *bp; /* 4: */ + s32 pn; /* 4: commit record log page number */ + s32 eor; /* 4: commit record eor */ + wait_queue_head_t gcwait; /* 4: group commit event list: + * ready transactions wait on this + * event for group commit completion. + */ + struct inode *ip; /* 4: inode being created or deleted */ + s32 rsrvd; /* 4: */ +} tblock_t; /* (64) */ + +extern struct tblock *TxBlock; /* transaction block table */ + +/* commit flags: tblk->xflag */ +#define COMMIT_SYNC 0x0001 /* synchronous commit */ +#define COMMIT_FORCE 0x0002 /* force pageout at end of commit */ +#define COMMIT_FLUSH 0x0004 /* init flush at end of commit */ +#define COMMIT_MAP 0x00f0 +#define COMMIT_PMAP 0x0010 /* update pmap */ +#define COMMIT_WMAP 0x0020 /* update wmap */ +#define COMMIT_PWMAP 0x0040 /* update pwmap */ +#define COMMIT_FREE 0x0f00 +#define COMMIT_DELETE 0x0100 /* inode delete */ +#define COMMIT_TRUNCATE 0x0200 /* file truncation */ +#define COMMIT_CREATE 0x0400 /* inode create */ +#define COMMIT_LAZY 0x0800 /* lazy commit */ +#define COMMIT_PAGE 0x1000 /* Identifies element as metapage */ +#define COMMIT_INODE 0x2000 /* Identifies element as inode */ + +/* group commit flags tblk->flag: see jfs_logmgr.h */ + +/* + * transaction lock + */ +typedef struct tlock { + lid_t next; /* index next lockword on tid locklist + * next lockword on freelist + */ + tid_t tid; /* transaction id holding lock */ + + u16 flag; /* 2: lock control */ + u16 type; /* 2: log type */ + + struct metapage *mp; /* 4: object page buffer locked */ + struct inode *ip; /* 4: object */ + /* (16) */ + + s16 lock[24]; /* 48: overlay area */ +} tlock_t; /* (64) */ + +extern struct tlock *TxLock; /* transaction lock table */ + +/* + * tlock flag + */ +/* txLock state */ +#define tlckPAGELOCK 0x8000 +#define tlckINODELOCK 0x4000 +#define tlckLINELOCK 0x2000 +#define tlckINLINELOCK 0x1000 +/* lmLog state */ +#define tlckLOG 0x0800 +/* updateMap state */ +#define tlckUPDATEMAP 0x0080 +/* freeLock state */ +#define tlckFREELOCK 0x0008 +#define tlckWRITEPAGE 0x0004 +#define tlckFREEPAGE 0x0002 + +/* + * tlock type + */ +#define tlckTYPE 0xfe00 +#define tlckINODE 0x8000 +#define tlckXTREE 0x4000 +#define tlckDTREE 0x2000 +#define tlckMAP 0x1000 +#define tlckEA 0x0800 +#define tlckACL 0x0400 +#define tlckDATA 0x0200 +#define tlckBTROOT 0x0100 + +#define tlckOPERATION 0x00ff +#define tlckGROW 0x0001 /* file grow */ +#define tlckREMOVE 0x0002 /* file delete */ +#define tlckTRUNCATE 0x0004 /* file truncate */ +#define tlckRELOCATE 0x0008 /* file/directory relocate */ +#define tlckENTRY 0x0001 /* directory insert/delete */ +#define tlckEXTEND 0x0002 /* directory extend in-line */ +#define tlckSPLIT 0x0010 /* splited page */ +#define tlckNEW 0x0020 /* new page from split */ +#define tlckFREE 0x0040 /* free page */ +#define tlckRELINK 0x0080 /* update sibling pointer */ + +/* + * linelock for lmLog() + * + * note: linelock_t and its variations are overlaid + * at tlock.lock: watch for alignment; + */ +typedef struct { + u8 offset; /* 1: */ + u8 length; /* 1: */ +} lv_t; /* (2) */ + +#define TLOCKSHORT 20 +#define TLOCKLONG 28 + +typedef struct { + u16 next; /* 2: next linelock */ + + s8 maxcnt; /* 1: */ + s8 index; /* 1: */ + + u16 flag; /* 2: */ + u8 type; /* 1: */ + u8 l2linesize; /* 1: log2 of linesize */ + /* (8) */ + + lv_t lv[20]; /* 40: */ +} linelock_t; /* (48) */ + +#define dtlock_t linelock_t +#define itlock_t linelock_t + +typedef struct { + u16 next; /* 2: */ + + s8 maxcnt; /* 1: */ + s8 index; /* 1: */ + + u16 flag; /* 2: */ + u8 type; /* 1: */ + u8 l2linesize; /* 1: log2 of linesize */ + /* (8) */ + + lv_t header; /* 2: */ + lv_t lwm; /* 2: low water mark */ + lv_t hwm; /* 2: high water mark */ + lv_t twm; /* 2: */ + /* (16) */ + + s32 pxdlock[8]; /* 32: */ +} xtlock_t; /* (48) */ + + +/* + * maplock for txUpdateMap() + * + * note: maplock_t and its variations are overlaid + * at tlock.lock/linelock: watch for alignment; + * N.B. next field may be set by linelock, and should not + * be modified by maplock; + * N.B. index of the first pxdlock specifies index of next + * free maplock (i.e., number of maplock) in the tlock; + */ +typedef struct { + u16 next; /* 2: */ + + u8 maxcnt; /* 2: */ + u8 index; /* 2: next free maplock index */ + + u16 flag; /* 2: */ + u8 type; /* 1: */ + u8 count; /* 1: number of pxd/xad */ + /* (8) */ + + pxd_t pxd; /* 8: */ +} maplock_t; /* (16): */ + +/* maplock flag */ +#define mlckALLOC 0x00f0 +#define mlckALLOCXADLIST 0x0080 +#define mlckALLOCPXDLIST 0x0040 +#define mlckALLOCXAD 0x0020 +#define mlckALLOCPXD 0x0010 +#define mlckFREE 0x000f +#define mlckFREEXADLIST 0x0008 +#define mlckFREEPXDLIST 0x0004 +#define mlckFREEXAD 0x0002 +#define mlckFREEPXD 0x0001 + +#define pxdlock_t maplock_t + +typedef struct { + u16 next; /* 2: */ + + u8 maxcnt; /* 2: */ + u8 index; /* 2: */ + + u16 flag; /* 2: */ + u8 type; /* 1: */ + u8 count; /* 1: number of pxd/xad */ + /* (8) */ + + /* + * We need xdlistlock_t to be 64 bits (8 bytes), regardless of + * whether void * is 32 or 64 bits + */ + union { + void *_xdlist; /* pxd/xad list */ + s64 pad; /* 8: Force 64-bit xdlist size */ + } union64; +} xdlistlock_t; /* (16): */ + +#define xdlist union64._xdlist + +/* + * commit + * + * parameter to the commit manager routines + */ +typedef struct commit { + tid_t tid; /* 4: tid = index of tblock */ + int flag; /* 4: flags */ + log_t *log; /* 4: log */ + struct super_block *sb; /* 4: superblock */ + + int nip; /* 4: number of entries in iplist */ + struct inode **iplist; /* 4: list of pointers to inodes */ + /* (32) */ + + /* log record descriptor on 64-bit boundary */ + lrd_t lrd; /* : log record descriptor */ +} commit_t; + +/* + * external declarations + */ +extern tlock_t *txLock(tid_t tid, struct inode *ip, struct metapage *mp, int flag); + +extern tlock_t *txMaplock(tid_t tid, struct inode *ip, int flag); + +extern int txCommit(tid_t tid, int nip, struct inode **iplist, int flag); + +extern tid_t txBegin(struct super_block *sb, int flag); + +extern void txBeginAnon(struct super_block *sb); + +extern void txEnd(tid_t tid); + +extern void txAbort(tid_t tid, int dirty); + +extern linelock_t *txLinelock(linelock_t * tlock); + +extern void txFreeMap(struct inode *ip, + maplock_t * maplock, tblock_t * tblk, int maptype); + +extern void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea); + +extern void txFreelock(struct inode *ip); + +extern int lmLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck); + +extern void txQuiesce(struct super_block *sb); + +extern void txResume(struct super_block *sb); +#endif /* _H_JFS_TXNMGR */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_types.h linux.20pre2-ac1/fs/jfs/jfs_types.h --- linux.20pre2/fs/jfs/jfs_types.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_types.h 2002-08-06 18:24:33.000000000 +0100 @@ -0,0 +1,186 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 _H_JFS_TYPES +#define _H_JFS_TYPES + +/* + * jfs_types.h: + * + * basic type/utility definitions + * + * note: this header file must be the 1st include file + * of JFS include list in all JFS .c file. + */ + +#include +#include + +#include "endian24.h" + +/* + * transaction and lock id's + */ +typedef uint tid_t; +typedef uint lid_t; + +/* + * Almost identical to Linux's timespec, but not quite + */ +struct timestruc_t { + u32 tv_sec; + u32 tv_nsec; +}; + +/* + * handy + */ + +#define LEFTMOSTONE 0x80000000 +#define HIGHORDER 0x80000000u /* high order bit on */ +#define ONES 0xffffffffu /* all bit on */ + +typedef int boolean_t; +#define TRUE 1 +#define FALSE 0 + +/* + * logical xd (lxd) + */ +typedef struct { + unsigned len:24; + unsigned off1:8; + u32 off2; +} lxd_t; + +/* lxd_t field construction */ +#define LXDlength(lxd, length32) ( (lxd)->len = length32 ) +#define LXDoffset(lxd, offset64)\ +{\ + (lxd)->off1 = ((s64)offset64) >> 32;\ + (lxd)->off2 = (offset64) & 0xffffffff;\ +} + +/* lxd_t field extraction */ +#define lengthLXD(lxd) ( (lxd)->len ) +#define offsetLXD(lxd)\ + ( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 ) + +/* lxd list */ +typedef struct { + s16 maxnlxd; + s16 nlxd; + lxd_t *lxd; +} lxdlist_t; + +/* + * physical xd (pxd) + */ +typedef struct { + unsigned len:24; + unsigned addr1:8; + u32 addr2; +} pxd_t; + +/* xd_t field construction */ + +#define PXDlength(pxd, length32) ((pxd)->len = __cpu_to_le24(length32)) +#define PXDaddress(pxd, address64)\ +{\ + (pxd)->addr1 = ((s64)address64) >> 32;\ + (pxd)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\ +} + +/* xd_t field extraction */ +#define lengthPXD(pxd) __le24_to_cpu((pxd)->len) +#define addressPXD(pxd)\ + ( ((s64)((pxd)->addr1)) << 32 | __le32_to_cpu((pxd)->addr2)) + +/* pxd list */ +typedef struct { + s16 maxnpxd; + s16 npxd; + pxd_t pxd[8]; +} pxdlist_t; + + +/* + * data extent descriptor (dxd) + */ +typedef struct { + unsigned flag:8; /* 1: flags */ + unsigned rsrvd:24; /* 3: */ + u32 size; /* 4: size in byte */ + unsigned len:24; /* 3: length in unit of fsblksize */ + unsigned addr1:8; /* 1: address in unit of fsblksize */ + u32 addr2; /* 4: address in unit of fsblksize */ +} dxd_t; /* - 16 - */ + +/* dxd_t flags */ +#define DXD_INDEX 0x80 /* B+-tree index */ +#define DXD_INLINE 0x40 /* in-line data extent */ +#define DXD_EXTENT 0x20 /* out-of-line single extent */ +#define DXD_FILE 0x10 /* out-of-line file (inode) */ +#define DXD_CORRUPT 0x08 /* Inconsistency detected */ + +/* dxd_t field construction + * Conveniently, the PXD macros work for DXD + */ +#define DXDlength PXDlength +#define DXDaddress PXDaddress +#define lengthDXD lengthPXD +#define addressDXD addressPXD + +/* + * directory entry argument + */ +typedef struct component_name { + int namlen; + wchar_t *name; +} component_t; + + +/* + * DASD limit information - stored in directory inode + */ +typedef struct dasd { + u8 thresh; /* Alert Threshold (in percent) */ + u8 delta; /* Alert Threshold delta (in percent) */ + u8 rsrvd1; + u8 limit_hi; /* DASD limit (in logical blocks) */ + u32 limit_lo; /* DASD limit (in logical blocks) */ + u8 rsrvd2[3]; + u8 used_hi; /* DASD usage (in logical blocks) */ + u32 used_lo; /* DASD usage (in logical blocks) */ +} dasd_t; + +#define DASDLIMIT(dasdp) \ + (((u64)((dasdp)->limit_hi) << 32) + __le32_to_cpu((dasdp)->limit_lo)) +#define setDASDLIMIT(dasdp, limit)\ +{\ + (dasdp)->limit_hi = ((u64)limit) >> 32;\ + (dasdp)->limit_lo = __cpu_to_le32(limit);\ +} +#define DASDUSED(dasdp) \ + (((u64)((dasdp)->used_hi) << 32) + __le32_to_cpu((dasdp)->used_lo)) +#define setDASDUSED(dasdp, used)\ +{\ + (dasdp)->used_hi = ((u64)used) >> 32;\ + (dasdp)->used_lo = __cpu_to_le32(used);\ +} + +#endif /* !_H_JFS_TYPES */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_umount.c linux.20pre2-ac1/fs/jfs/jfs_umount.c --- linux.20pre2/fs/jfs/jfs_umount.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_umount.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,153 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 + */ + +/* + * jfs_umount.c + * + * note: file system in transition to aggregate/fileset: + * (ref. jfs_mount.c) + * + * file system unmount is interpreted as mount of the single/only + * fileset in the aggregate and, if unmount of the last fileset, + * as unmount of the aggerate; + */ + +#include +#include "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_superblock.h" +#include "jfs_dmap.h" +#include "jfs_imap.h" +#include "jfs_metapage.h" +#include "jfs_debug.h" + +/* + * NAME: jfs_umount(vfsp, flags, crp) + * + * FUNCTION: vfs_umount() + * + * PARAMETERS: vfsp - virtual file system pointer + * flags - unmount for shutdown + * crp - credential + * + * RETURN : EBUSY - device has open files + */ +int jfs_umount(struct super_block *sb) +{ + int rc = 0; + log_t *log; + struct jfs_sb_info *sbi = JFS_SBI(sb); + struct inode *ipbmap = sbi->ipbmap; + struct inode *ipimap = sbi->ipimap; + struct inode *ipaimap = sbi->ipaimap; + struct inode *ipaimap2 = sbi->ipaimap2; + + jFYI(1, ("\n UnMount JFS: sb:0x%p\n", sb)); + + /* + * update superblock and close log + * + * if mounted read-write and log based recovery was enabled + */ + if ((log = sbi->log)) { + /* + * close log: + * + * remove file system from log active file system list. + */ + log = sbi->log; + rc = lmLogClose(sb, log); + } + + /* + * close fileset inode allocation map (aka fileset inode) + */ + jEVENT(0, ("jfs_umount: close ipimap:0x%p\n", ipimap)); + diUnmount(ipimap, 0); + + diFreeSpecial(ipimap); + sbi->ipimap = NULL; + + /* + * close secondary aggregate inode allocation map + */ + ipaimap2 = sbi->ipaimap2; + if (ipaimap2) { + jEVENT(0, ("jfs_umount: close ipaimap2:0x%p\n", ipaimap2)); + diUnmount(ipaimap2, 0); + diFreeSpecial(ipaimap2); + sbi->ipaimap2 = NULL; + } + + /* + * close aggregate inode allocation map + */ + ipaimap = sbi->ipaimap; + jEVENT(0, ("jfs_umount: close ipaimap:0x%p\n", ipaimap)); + diUnmount(ipaimap, 0); + diFreeSpecial(ipaimap); + sbi->ipaimap = NULL; + + /* + * close aggregate block allocation map + */ + jEVENT(0, ("jfs_umount: close ipbmap:%p\n", ipbmap)); + dbUnmount(ipbmap, 0); + + diFreeSpecial(ipbmap); + sbi->ipimap = NULL; + + /* + * ensure all file system file pages are propagated to their + * home blocks on disk (and their in-memory buffer pages are + * invalidated) BEFORE updating file system superblock state + * (to signify file system is unmounted cleanly, and thus in + * consistent state) and log superblock active file system + * list (to signify skip logredo()). + */ + if (log) /* log = NULL if read-only mount */ + rc = updateSuper(sb, FM_CLEAN); + + + jFYI(0, (" UnMount JFS Complete: %d\n", rc)); + return rc; +} + + +int jfs_umount_rw(struct super_block *sb) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + + if (!sbi->log) + return 0; + + /* + * close log: + * + * remove file system from log active file system list. + */ + lmLogClose(sb, sbi->log); + + dbSync(sbi->ipbmap); + diSync(sbi->ipimap); + + sbi->log = 0; + + return updateSuper(sb, FM_CLEAN); + +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_unicode.c linux.20pre2-ac1/fs/jfs/jfs_unicode.c --- linux.20pre2/fs/jfs/jfs_unicode.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_unicode.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,110 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 "jfs_types.h" +#include "jfs_filsys.h" +#include "jfs_unicode.h" +#include "jfs_debug.h" + +/* + * NAME: jfs_strfromUCS() + * + * FUNCTION: Convert little-endian unicode string to character string + * + */ +int jfs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ + int len, struct nls_table *codepage) +{ + int i; + int outlen = 0; + + for (i = 0; (i < len) && from[i]; i++) { + int charlen; + charlen = + codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], + NLS_MAX_CHARSET_SIZE); + if (charlen > 0) { + outlen += charlen; + } else { + to[outlen++] = '?'; + } + } + to[outlen] = 0; + jEVENT(0, ("jfs_strfromUCS returning %d - '%s'\n", outlen, to)); + return outlen; +} + +/* + * NAME: jfs_strtoUCS() + * + * FUNCTION: Convert character string to unicode string + * + */ +int jfs_strtoUCS(wchar_t * to, + const char *from, int len, struct nls_table *codepage) +{ + int charlen; + int i; + + jEVENT(0, ("jfs_strtoUCS - '%s'\n", from)); + + for (i = 0; len && *from; i++, from += charlen, len -= charlen) { + charlen = codepage->char2uni(from, len, &to[i]); + if (charlen < 1) { + jERROR(1, ("jfs_strtoUCS: char2uni returned %d.\n", + charlen)); + jERROR(1, ("charset = %s, char = 0x%x\n", + codepage->charset, (unsigned char) *from)); + to[i] = 0x003f; /* a question mark */ + charlen = 1; + } + } + + jEVENT(0, (" returning %d\n", i)); + + to[i] = 0; + return i; +} + +/* + * NAME: get_UCSname() + * + * FUNCTION: Allocate and translate to unicode string + * + */ +int get_UCSname(component_t * uniName, struct dentry *dentry, + struct nls_table *nls_tab) +{ + int length = dentry->d_name.len; + + if (length > JFS_NAME_MAX) + return ENAMETOOLONG; + + uniName->name = + kmalloc((length + 1) * sizeof(wchar_t), GFP_NOFS); + + if (uniName->name == NULL) + return ENOSPC; + + uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name, + length, nls_tab); + + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_unicode.h linux.20pre2-ac1/fs/jfs/jfs_unicode.h --- linux.20pre2/fs/jfs/jfs_unicode.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_unicode.h 2002-08-06 18:24:34.000000000 +0100 @@ -0,0 +1,139 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 _H_JFS_UNICODE +#define _H_JFS_UNICODE + +#include +#include "jfs_types.h" + +typedef struct { + wchar_t start; + wchar_t end; + signed char *table; +} UNICASERANGE; + +extern signed char UniUpperTable[512]; +extern UNICASERANGE UniUpperRange[]; +extern int get_UCSname(component_t *, struct dentry *, struct nls_table *); +extern int jfs_strfromUCS_le(char *, const wchar_t *, int, struct nls_table *); + +#define free_UCSname(COMP) kfree((COMP)->name) + +/* + * UniStrcpy: Copy a string + */ +static inline wchar_t *UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2) +{ + wchar_t *anchor = ucs1; /* save the start of result string */ + + while ((*ucs1++ = *ucs2++)); + return anchor; +} + + + +/* + * UniStrncpy: Copy length limited string with pad + */ +static inline wchar_t *UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, + size_t n) +{ + wchar_t *anchor = ucs1; + + while (n-- && *ucs2) /* Copy the strings */ + *ucs1++ = *ucs2++; + + n++; + while (n--) /* Pad with nulls */ + *ucs1++ = 0; + return anchor; +} + +/* + * UniStrncmp_le: Compare length limited string - native to little-endian + */ +static inline int UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, + size_t n) +{ + if (!n) + return 0; /* Null strings are equal */ + while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { + ucs1++; + ucs2++; + } + return (int) *ucs1 - (int) __le16_to_cpu(*ucs2); +} + +/* + * UniStrncpy_le: Copy length limited string with pad to little-endian + */ +static inline wchar_t *UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, + size_t n) +{ + wchar_t *anchor = ucs1; + + while (n-- && *ucs2) /* Copy the strings */ + *ucs1++ = __le16_to_cpu(*ucs2++); + + n++; + while (n--) /* Pad with nulls */ + *ucs1++ = 0; + return anchor; +} + + +/* + * UniToupper: Convert a unicode character to upper case + */ +static inline wchar_t UniToupper(wchar_t uc) +{ + UNICASERANGE *rp; + + if (uc < sizeof(UniUpperTable)) { /* Latin characters */ + return uc + UniUpperTable[uc]; /* Use base tables */ + } else { + rp = UniUpperRange; /* Use range tables */ + while (rp->start) { + if (uc < rp->start) /* Before start of range */ + return uc; /* Uppercase = input */ + if (uc <= rp->end) /* In range */ + return uc + rp->table[uc - rp->start]; + rp++; /* Try next range */ + } + } + return uc; /* Past last range */ +} + + +/* + * UniStrupr: Upper case a unicode string + */ +static inline wchar_t *UniStrupr(wchar_t * upin) +{ + wchar_t *up; + + up = upin; + while (*up) { /* For all characters */ + *up = UniToupper(*up); + up++; + } + return upin; /* Return input pointer */ +} + +#endif /* !_H_JFS_UNICODE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_uniupr.c linux.20pre2-ac1/fs/jfs/jfs_uniupr.c --- linux.20pre2/fs/jfs/jfs_uniupr.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_uniupr.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,134 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 "jfs_unicode.h" + +/* + * Latin upper case + */ +signed char UniUpperTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */ + 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 060-06f */ + -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, 0, 0, 0, 0, 0, /* 070-07f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */ + -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 0e0-0ef */ + -32,-32,-32,-32,-32,-32,-32, 0,-32,-32,-32,-32,-32,-32,-32,121, /* 0f0-0ff */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */ + 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */ + -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */ + 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */ + 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */ + 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */ + -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */ + 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */ + -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,-79, 0, -1, /* 1d0-1df */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ + 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ +}; + +/* Upper case range - Greek */ +static signed char UniCaseRangeU03a0[47] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-38,-37,-37,-37, /* 3a0-3af */ + 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 3b0-3bf */ + -32,-32,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-64,-63,-63, +}; + +/* Upper case range - Cyrillic */ +static signed char UniCaseRangeU0430[48] = { + -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 430-43f */ + -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 440-44f */ + 0,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80, 0,-80,-80, /* 450-45f */ +}; + +/* Upper case range - Extended cyrillic */ +static signed char UniCaseRangeU0490[61] = { + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */ + 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, +}; + +/* Upper case range - Extended latin and greek */ +static signed char UniCaseRangeU1e00[509] = { + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */ + 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0,-59, 0, -1, 0, -1, /* 1e90-1e9f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */ + 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */ + 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */ + 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */ + 74, 74, 86, 86, 86, 86,100,100, 0, 0,112,112,126,126, 0, 0, /* 1f70-1f7f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */ + 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */ + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */ + 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */ + 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */ + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* Upper case range - Wide latin */ +static signed char UniCaseRangeUff40[27] = { + 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* ff40-ff4f */ + -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, +}; + +/* + * Upper Case Range + */ +UNICASERANGE UniUpperRange[] = { + { 0x03a0, 0x03ce, UniCaseRangeU03a0 }, + { 0x0430, 0x045f, UniCaseRangeU0430 }, + { 0x0490, 0x04cc, UniCaseRangeU0490 }, + { 0x1e00, 0x1ffc, UniCaseRangeU1e00 }, + { 0xff40, 0xff5a, UniCaseRangeUff40 }, + { 0, 0, 0 } +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_xtree.c linux.20pre2-ac1/fs/jfs/jfs_xtree.c --- linux.20pre2/fs/jfs/jfs_xtree.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_xtree.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,4439 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 + */ +/* + * jfs_xtree.c: extent allocation descriptor B+-tree manager + */ + +#include +#include +#include "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_metapage.h" +#include "jfs_dmap.h" +#include "jfs_dinode.h" +#include "jfs_superblock.h" +#include "jfs_debug.h" + +/* + * xtree local flag + */ +#define XT_INSERT 0x00000001 + +/* + * xtree key/entry comparison: extent offset + * + * return: + * -1: k < start of extent + * 0: start_of_extent <= k <= end_of_extent + * 1: k > end_of_extent + */ +#define XT_CMP(CMP, K, X, OFFSET64)\ +{\ + OFFSET64 = offsetXAD(X);\ + (CMP) = ((K) >= OFFSET64 + lengthXAD(X)) ? 1 :\ + ((K) < OFFSET64) ? -1 : 0;\ +} + +/* write a xad entry */ +#define XT_PUTENTRY(XAD, FLAG, OFF, LEN, ADDR)\ +{\ + (XAD)->flag = (FLAG);\ + XADoffset((XAD), (OFF));\ + XADlength((XAD), (LEN));\ + XADaddress((XAD), (ADDR));\ +} + +#define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot) + +/* get page buffer for specified block address */ +#define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\ +{\ + BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\ + if (!(RC))\ + {\ + if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\ + (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\ + (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\ + {\ + jERROR(1,("XT_GETPAGE: xtree page corrupt\n"));\ + BT_PUTPAGE(MP);\ + updateSuper((IP)->i_sb, FM_DIRTY);\ + MP = NULL;\ + RC = EIO;\ + }\ + }\ +} + +/* for consistency */ +#define XT_PUTPAGE(MP) BT_PUTPAGE(MP) + +#define XT_GETSEARCH(IP, LEAF, BN, MP, P, INDEX) \ + BT_GETSEARCH(IP, LEAF, BN, MP, xtpage_t, P, INDEX, i_xtroot) +/* xtree entry parameter descriptor */ +typedef struct { + metapage_t *mp; + s16 index; + u8 flag; + s64 off; + s64 addr; + int len; + pxdlist_t *pxdlist; +} xtsplit_t; + + +/* + * statistics + */ +#ifdef CONFIG_JFS_STATISTICS +static struct { + uint search; + uint fastSearch; + uint split; +} xtStat; +#endif + + +/* + * forward references + */ +static int xtSearch(struct inode *ip, + s64 xoff, int *cmpp, btstack_t * btstack, int flag); + +static int xtSplitUp(tid_t tid, + struct inode *ip, + xtsplit_t * split, btstack_t * btstack); + +static int xtSplitPage(tid_t tid, + struct inode *ip, + xtsplit_t * split, metapage_t ** rmpp, s64 * rbnp); + +static int xtSplitRoot(tid_t tid, + struct inode *ip, + xtsplit_t * split, metapage_t ** rmpp); + +#ifdef _STILL_TO_PORT +static int xtDeleteUp(tid_t tid, + struct inode *ip, + metapage_t * fmp, + xtpage_t * fp, btstack_t * btstack); + +static int xtSearchNode(struct inode *ip, + xad_t * xad, + int *cmpp, btstack_t * btstack, int flag); + +static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * fp); +#endif /* _STILL_TO_PORT */ + +/* External references */ + +/* + * debug control + */ +/* #define _JFS_DEBUG_XTREE 1 */ + + +/* + * xtLookup() + * + * function: map a single page into a physical extent; + */ +int xtLookup(struct inode *ip, s64 lstart, + s64 llen, int *pflag, s64 * paddr, s32 * plen, int no_check) +{ + int rc = 0; + btstack_t btstack; + int cmp; + s64 bn; + metapage_t *mp; + xtpage_t *p; + int index; + xad_t *xad; + s64 size, xoff, xend; + int xlen; + s64 xaddr; + + *plen = 0; + + if (!no_check) { + /* is lookup offset beyond eof ? */ + size = ((u64) ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >> + JFS_SBI(ip->i_sb)->l2bsize; + if (lstart >= size) { + jERROR(1, + ("xtLookup: lstart (0x%lx) >= size (0x%lx)\n", + (ulong) lstart, (ulong) size)); + return 0; + } + } + + /* + * search for the xad entry covering the logical extent + */ +//search: + if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0))) { + jERROR(1, ("xtLookup: xtSearch returned %d\n", rc)); + return rc; + } + + /* + * compute the physical extent covering logical extent + * + * N.B. search may have failed (e.g., hole in sparse file), + * and returned the index of the next entry. + */ + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + /* is xad found covering start of logical extent ? + * lstart is a page start address, + * i.e., lstart cannot start in a hole; + */ + if (cmp) { + jFYI(1, ("xtLookup: cmp = %d\n", cmp)); + goto out; + } + + /* + * lxd covered by xad + */ + xad = &p->xad[index]; + xoff = offsetXAD(xad); + xlen = lengthXAD(xad); + xend = xoff + xlen; + xaddr = addressXAD(xad); + + jEVENT(0, + ("index = %d, xoff = 0x%lx, xlen = 0x%x, xaddr = 0x%lx\n", + index, (ulong) xoff, xlen, (ulong) xaddr)); + + /* initialize new pxd */ + *pflag = xad->flag; + *paddr = xaddr + (lstart - xoff); + /* a page must be fully covered by an xad */ + *plen = min(xend - lstart, llen); + + out: + XT_PUTPAGE(mp); + + return rc; +} + + +/* + * xtLookupList() + * + * function: map a single logical extent into a list of physical extent; + * + * parameter: + * struct inode *ip, + * lxdlist_t *lxdlist, lxd list (in) + * xadlist_t *xadlist, xad list (in/out) + * int flag) + * + * coverage of lxd by xad under assumption of + * . lxd's are ordered and disjoint. + * . xad's are ordered and disjoint. + * + * return: + * 0: success + * + * note: a page being written (even a single byte) is backed fully, + * except the last page which is only backed with blocks + * required to cover the last byte; + * the extent backing a page is fully contained within an xad; + */ +int xtLookupList(struct inode *ip, lxdlist_t * lxdlist, /* lxd list (in) */ + xadlist_t * xadlist, /* xad list (in/out) */ + int flag) +{ + int rc = 0; + btstack_t btstack; + int cmp; + s64 bn; + metapage_t *mp; + xtpage_t *p; + int index; + lxd_t *lxd; + xad_t *xad, *pxd; + s64 size, lstart, lend, xstart, xend, pstart; + s64 llen, xlen, plen; + s64 xaddr, paddr; + int nlxd, npxd, maxnpxd; + + npxd = xadlist->nxad = 0; + maxnpxd = xadlist->maxnxad; + pxd = xadlist->xad; + + nlxd = lxdlist->nlxd; + lxd = lxdlist->lxd; + + lstart = offsetLXD(lxd); + llen = lengthLXD(lxd); + lend = lstart + llen; + + size = (ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >> + JFS_SBI(ip->i_sb)->l2bsize; + + /* + * search for the xad entry covering the logical extent + */ + search: + if (lstart >= size) + return 0; + + if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0))) + return rc; + + /* + * compute the physical extent covering logical extent + * + * N.B. search may have failed (e.g., hole in sparse file), + * and returned the index of the next entry. + */ +//map: + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + /* is xad on the next sibling page ? */ + if (index == le16_to_cpu(p->header.nextindex)) { + if (p->header.flag & BT_ROOT) + goto mapend; + + if ((bn = le64_to_cpu(p->header.next)) == 0) + goto mapend; + + XT_PUTPAGE(mp); + + /* get next sibling page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + index = XTENTRYSTART; + } + + xad = &p->xad[index]; + + /* + * is lxd covered by xad ? + */ + compare: + xstart = offsetXAD(xad); + xlen = lengthXAD(xad); + xend = xstart + xlen; + xaddr = addressXAD(xad); + + compare1: + if (xstart < lstart) + goto compare2; + + /* (lstart <= xstart) */ + + /* lxd is NOT covered by xad */ + if (lend <= xstart) { + /* + * get next lxd + */ + if (--nlxd == 0) + goto mapend; + lxd++; + + lstart = offsetLXD(lxd); + llen = lengthLXD(lxd); + lend = lstart + llen; + if (lstart >= size) + goto mapend; + + /* compare with the current xad */ + goto compare1; + } + /* lxd is covered by xad */ + else { /* (xstart < lend) */ + + /* initialize new pxd */ + pstart = xstart; + plen = min(lend - xstart, xlen); + paddr = xaddr; + + goto cover; + } + + /* (xstart < lstart) */ + compare2: + /* lxd is covered by xad */ + if (lstart < xend) { + /* initialize new pxd */ + pstart = lstart; + plen = min(xend - lstart, llen); + paddr = xaddr + (lstart - xstart); + + goto cover; + } + /* lxd is NOT covered by xad */ + else { /* (xend <= lstart) */ + + /* + * get next xad + * + * linear search next xad covering lxd on + * the current xad page, and then tree search + */ + if (index == le16_to_cpu(p->header.nextindex) - 1) { + if (p->header.flag & BT_ROOT) + goto mapend; + + XT_PUTPAGE(mp); + goto search; + } else { + index++; + xad++; + + /* compare with new xad */ + goto compare; + } + } + + /* + * lxd is covered by xad and a new pxd has been initialized + * (lstart <= xstart < lend) or (xstart < lstart < xend) + */ + cover: + /* finalize pxd corresponding to current xad */ + XT_PUTENTRY(pxd, xad->flag, pstart, plen, paddr); + + if (++npxd >= maxnpxd) + goto mapend; + pxd++; + + /* + * lxd is fully covered by xad + */ + if (lend <= xend) { + /* + * get next lxd + */ + if (--nlxd == 0) + goto mapend; + lxd++; + + lstart = offsetLXD(lxd); + llen = lengthLXD(lxd); + lend = lstart + llen; + if (lstart >= size) + goto mapend; + + /* + * test for old xad covering new lxd + * (old xstart < new lstart) + */ + goto compare2; + } + /* + * lxd is partially covered by xad + */ + else { /* (xend < lend) */ + + /* + * get next xad + * + * linear search next xad covering lxd on + * the current xad page, and then next xad page search + */ + if (index == le16_to_cpu(p->header.nextindex) - 1) { + if (p->header.flag & BT_ROOT) + goto mapend; + + if ((bn = le64_to_cpu(p->header.next)) == 0) + goto mapend; + + XT_PUTPAGE(mp); + + /* get next sibling page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + index = XTENTRYSTART; + xad = &p->xad[index]; + } else { + index++; + xad++; + } + + /* + * test for new xad covering old lxd + * (old lstart < new xstart) + */ + goto compare; + } + + mapend: + xadlist->nxad = npxd; + +//out: + XT_PUTPAGE(mp); + + return rc; +} + + +/* + * xtSearch() + * + * function: search for the xad entry covering specified offset. + * + * parameters: + * ip - file object; + * xoff - extent offset; + * cmpp - comparison result: + * btstack - traverse stack; + * flag - search process flag (XT_INSERT); + * + * returns: + * btstack contains (bn, index) of search path traversed to the entry. + * *cmpp is set to result of comparison with the entry returned. + * the page containing the entry is pinned at exit. + */ +static int xtSearch(struct inode *ip, s64 xoff, /* offset of extent */ + int *cmpp, btstack_t * btstack, int flag) +{ + struct jfs_inode_info *jfs_ip = JFS_IP(ip); + int rc = 0; + int cmp = 1; /* init for empty page */ + s64 bn; /* block number */ + metapage_t *mp; /* page buffer */ + xtpage_t *p; /* page */ + xad_t *xad; + int base, index, lim, btindex; + btframe_t *btsp; + int nsplit = 0; /* number of pages to split */ + s64 t64; + + INCREMENT(xtStat.search); + + BT_CLR(btstack); + + btstack->nsplit = 0; + + /* + * search down tree from root: + * + * between two consecutive entries of and of + * internal page, child page Pi contains entry with k, Ki <= K < Kj. + * + * if entry with search key K is not found + * internal page search find the entry with largest key Ki + * less than K which point to the child page to search; + * leaf page search find the entry with smallest key Kj + * greater than K so that the returned index is the position of + * the entry to be shifted right for insertion of new entry. + * for empty tree, search key is greater than any key of the tree. + * + * by convention, root bn = 0. + */ + for (bn = 0;;) { + /* get/pin the page to search */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* try sequential access heuristics with the previous + * access entry in target leaf page: + * once search narrowed down into the target leaf, + * key must either match an entry in the leaf or + * key entry does not exist in the tree; + */ +//fastSearch: + if ((jfs_ip->btorder & BT_SEQUENTIAL) && + (p->header.flag & BT_LEAF) && + (index = jfs_ip->btindex) < + le16_to_cpu(p->header.nextindex)) { + xad = &p->xad[index]; + t64 = offsetXAD(xad); + if (xoff < t64 + lengthXAD(xad)) { + if (xoff >= t64) { + *cmpp = 0; + goto out; + } + + /* stop sequential access heuristics */ + goto binarySearch; + } else { /* (t64 + lengthXAD(xad)) <= xoff */ + + /* try next sequential entry */ + index++; + if (index < + le16_to_cpu(p->header.nextindex)) { + xad++; + t64 = offsetXAD(xad); + if (xoff < t64 + lengthXAD(xad)) { + if (xoff >= t64) { + *cmpp = 0; + goto out; + } + + /* miss: key falls between + * previous and this entry + */ + *cmpp = 1; + goto out; + } + + /* (xoff >= t64 + lengthXAD(xad)); + * matching entry may be further out: + * stop heuristic search + */ + /* stop sequential access heuristics */ + goto binarySearch; + } + + /* (index == p->header.nextindex); + * miss: key entry does not exist in + * the target leaf/tree + */ + *cmpp = 1; + goto out; + } + + /* + * if hit, return index of the entry found, and + * if miss, where new entry with search key is + * to be inserted; + */ + out: + /* compute number of pages to split */ + if (flag & XT_INSERT) { + if (p->header.nextindex == /* little-endian */ + p->header.maxentry) + nsplit++; + else + nsplit = 0; + btstack->nsplit = nsplit; + } + + /* save search result */ + btsp = btstack->top; + btsp->bn = bn; + btsp->index = index; + btsp->mp = mp; + + /* update sequential access heuristics */ + jfs_ip->btindex = index; + + INCREMENT(xtStat.fastSearch); + return 0; + } + + /* well, ... full search now */ + binarySearch: + lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART; + + /* + * binary search with search key K on the current page + */ + for (base = XTENTRYSTART; lim; lim >>= 1) { + index = base + (lim >> 1); + + XT_CMP(cmp, xoff, &p->xad[index], t64); + if (cmp == 0) { + /* + * search hit + */ + /* search hit - leaf page: + * return the entry found + */ + if (p->header.flag & BT_LEAF) { + *cmpp = cmp; + + /* compute number of pages to split */ + if (flag & XT_INSERT) { + if (p->header.nextindex == + p->header.maxentry) + nsplit++; + else + nsplit = 0; + btstack->nsplit = nsplit; + } + + /* save search result */ + btsp = btstack->top; + btsp->bn = bn; + btsp->index = index; + btsp->mp = mp; + + /* init sequential access heuristics */ + btindex = jfs_ip->btindex; + if (index == btindex || + index == btindex + 1) + jfs_ip->btorder = BT_SEQUENTIAL; + else + jfs_ip->btorder = BT_RANDOM; + jfs_ip->btindex = index; + + return 0; + } + + /* search hit - internal page: + * descend/search its child page + */ + goto next; + } + + if (cmp > 0) { + base = index + 1; + --lim; + } + } + + /* + * search miss + * + * base is the smallest index with key (Kj) greater than + * search key (K) and may be zero or maxentry index. + */ + /* + * search miss - leaf page: + * + * return location of entry (base) where new entry with + * search key K is to be inserted. + */ + if (p->header.flag & BT_LEAF) { + *cmpp = cmp; + + /* compute number of pages to split */ + if (flag & XT_INSERT) { + if (p->header.nextindex == + p->header.maxentry) + nsplit++; + else + nsplit = 0; + btstack->nsplit = nsplit; + } + + /* save search result */ + btsp = btstack->top; + btsp->bn = bn; + btsp->index = base; + btsp->mp = mp; + + /* init sequential access heuristics */ + btindex = jfs_ip->btindex; + if (base == btindex || base == btindex + 1) + jfs_ip->btorder = BT_SEQUENTIAL; + else + jfs_ip->btorder = BT_RANDOM; + jfs_ip->btindex = base; + + return 0; + } + + /* + * search miss - non-leaf page: + * + * if base is non-zero, decrement base by one to get the parent + * entry of the child page to search. + */ + index = base ? base - 1 : base; + + /* + * go down to child page + */ + next: + /* update number of pages to split */ + if (p->header.nextindex == p->header.maxentry) + nsplit++; + else + nsplit = 0; + + /* push (bn, index) of the parent page/entry */ + BT_PUSH(btstack, bn, index); + + /* get the child page block number */ + bn = addressXAD(&p->xad[index]); + + /* unpin the parent page */ + XT_PUTPAGE(mp); + } +} + +/* + * xtInsert() + * + * function: + * + * parameter: + * tid - transaction id; + * ip - file object; + * xflag - extent flag (XAD_NOTRECORDED): + * xoff - extent offset; + * xlen - extent length; + * xaddrp - extent address pointer (in/out): + * if (*xaddrp) + * caller allocated data extent at *xaddrp; + * else + * allocate data extent and return its xaddr; + * flag - + * + * return: + */ +int xtInsert(tid_t tid, /* transaction id */ + struct inode *ip, int xflag, s64 xoff, s32 xlen, s64 * xaddrp, + int flag) +{ + int rc = 0; + s64 xaddr, hint; + metapage_t *mp; /* meta-page buffer */ + xtpage_t *p; /* base B+-tree index page */ + s64 bn; + int index, nextindex; + btstack_t btstack; /* traverse stack */ + xtsplit_t split; /* split information */ + xad_t *xad; + int cmp; + tlock_t *tlck; + xtlock_t *xtlck; + + jFYI(1, + ("xtInsert: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen)); + + /* + * search for the entry location at which to insert: + * + * xtFastSearch() and xtSearch() both returns (leaf page + * pinned, index at which to insert). + * n.b. xtSearch() may return index of maxentry of + * the full page. + */ + if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT))) + return rc; + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + /* This test must follow XT_GETSEARCH since mp must be valid if + * we branch to out: */ + if (cmp == 0) { + rc = EEXIST; + goto out; + } + + /* + * allocate data extent requested + * + * allocation hint: last xad + */ + if ((xaddr = *xaddrp) == 0) { + if (index > XTENTRYSTART) { + xad = &p->xad[index - 1]; + hint = addressXAD(xad) + lengthXAD(xad) - 1; + } else + hint = 0; + if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr))) + goto out; + } + + /* + * insert entry for new extent + */ + xflag |= XAD_NEW; + + /* + * if the leaf page is full, split the page and + * propagate up the router entry for the new page from split + * + * The xtSplitUp() will insert the entry and unpin the leaf page. + */ + nextindex = le16_to_cpu(p->header.nextindex); + if (nextindex == le16_to_cpu(p->header.maxentry)) { + split.mp = mp; + split.index = index; + split.flag = xflag; + split.off = xoff; + split.len = xlen; + split.addr = xaddr; + split.pxdlist = NULL; + if ((rc = xtSplitUp(tid, ip, &split, &btstack))) { + /* undo data extent allocation */ + if (*xaddrp == 0) + dbFree(ip, xaddr, (s64) xlen); + return rc; + } + + *xaddrp = xaddr; + return 0; + } + + /* + * insert the new entry into the leaf page + */ + /* + * acquire a transaction lock on the leaf page; + * + * action: xad insertion/extension; + */ + BT_MARK_DIRTY(mp, ip); + + /* if insert into middle, shift right remaining entries. */ + if (index < nextindex) + memmove(&p->xad[index + 1], &p->xad[index], + (nextindex - index) * sizeof(xad_t)); + + /* insert the new entry: mark the entry NEW */ + xad = &p->xad[index]; + XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr); + + /* advance next available entry index */ + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1); + + /* Don't log it if there are no links to the file */ + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->lwm.offset = + (xtlck->lwm.offset) ? min(index, + (int)xtlck->lwm.offset) : index; + xtlck->lwm.length = + le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset; + } + + *xaddrp = xaddr; + + out: + /* unpin the leaf page */ + XT_PUTPAGE(mp); + + return rc; +} + + +/* + * xtSplitUp() + * + * function: + * split full pages as propagating insertion up the tree + * + * parameter: + * tid - transaction id; + * ip - file object; + * split - entry parameter descriptor; + * btstack - traverse stack from xtSearch() + * + * return: + */ +static int +xtSplitUp(tid_t tid, + struct inode *ip, xtsplit_t * split, btstack_t * btstack) +{ + int rc = 0; + metapage_t *smp; + xtpage_t *sp; /* split page */ + metapage_t *rmp; + s64 rbn; /* new right page block number */ + metapage_t *rcmp; + xtpage_t *rcp; /* right child page */ + s64 rcbn; /* right child page block number */ + int skip; /* index of entry of insertion */ + int nextindex; /* next available entry index of p */ + btframe_t *parent; /* parent page entry on traverse stack */ + xad_t *xad; + s64 xaddr; + int xlen; + int nsplit; /* number of pages split */ + pxdlist_t pxdlist; + pxd_t *pxd; + tlock_t *tlck; + xtlock_t *xtlck; + + smp = split->mp; + sp = XT_PAGE(ip, smp); + + /* is inode xtree root extension/inline EA area free ? */ + if ((sp->header.flag & BT_ROOT) && (!S_ISDIR(ip->i_mode)) && + (sp->header.maxentry < cpu_to_le16(XTROOTMAXSLOT)) && + (JFS_IP(ip)->mode2 & INLINEEA)) { + sp->header.maxentry = cpu_to_le16(XTROOTMAXSLOT); + JFS_IP(ip)->mode2 &= ~INLINEEA; + + BT_MARK_DIRTY(smp, ip); + /* + * acquire a transaction lock on the leaf page; + * + * action: xad insertion/extension; + */ + + /* if insert into middle, shift right remaining entries. */ + skip = split->index; + nextindex = le16_to_cpu(sp->header.nextindex); + if (skip < nextindex) + memmove(&sp->xad[skip + 1], &sp->xad[skip], + (nextindex - skip) * sizeof(xad_t)); + + /* insert the new entry: mark the entry NEW */ + xad = &sp->xad[skip]; + XT_PUTENTRY(xad, split->flag, split->off, split->len, + split->addr); + + /* advance next available entry index */ + sp->header.nextindex = + cpu_to_le16(le16_to_cpu(sp->header.nextindex) + 1); + + /* Don't log it if there are no links to the file */ + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->lwm.offset = (xtlck->lwm.offset) ? + min(skip, (int)xtlck->lwm.offset) : skip; + xtlck->lwm.length = + le16_to_cpu(sp->header.nextindex) - + xtlck->lwm.offset; + } + + return 0; + } + + /* + * allocate new index blocks to cover index page split(s) + * + * allocation hint: ? + */ + if (split->pxdlist == NULL) { + nsplit = btstack->nsplit; + split->pxdlist = &pxdlist; + pxdlist.maxnpxd = pxdlist.npxd = 0; + pxd = &pxdlist.pxd[0]; + xlen = JFS_SBI(ip->i_sb)->nbperpage; + for (; nsplit > 0; nsplit--, pxd++) { + if ((rc = dbAlloc(ip, (s64) 0, (s64) xlen, &xaddr)) + == 0) { + PXDaddress(pxd, xaddr); + PXDlength(pxd, xlen); + + pxdlist.maxnpxd++; + + continue; + } + + /* undo allocation */ + + XT_PUTPAGE(smp); + return rc; + } + } + + /* + * Split leaf page into and a new right page . + * + * The split routines insert the new entry into the leaf page, + * and acquire txLock as appropriate. + * return pinned and its block number . + */ + rc = (sp->header.flag & BT_ROOT) ? + xtSplitRoot(tid, ip, split, &rmp) : + xtSplitPage(tid, ip, split, &rmp, &rbn); + if (rc) + return EIO; + + XT_PUTPAGE(smp); + + /* + * propagate up the router entry for the leaf page just split + * + * insert a router entry for the new page into the parent page, + * propagate the insert/split up the tree by walking back the stack + * of (bn of parent page, index of child page entry in parent page) + * that were traversed during the search for the page that split. + * + * the propagation of insert/split up the tree stops if the root + * splits or the page inserted into doesn't have to split to hold + * the new entry. + * + * the parent entry for the split page remains the same, and + * a new entry is inserted at its right with the first key and + * block number of the new right page. + * + * There are a maximum of 3 pages pinned at any time: + * right child, left parent and right parent (when the parent splits) + * to keep the child page pinned while working on the parent. + * make sure that all pins are released at exit. + */ + while ((parent = BT_POP(btstack)) != NULL) { + /* parent page specified by stack frame */ + + /* keep current child pages pinned */ + rcmp = rmp; + rcbn = rbn; + rcp = XT_PAGE(ip, rcmp); + + /* + * insert router entry in parent for new right child page + */ + /* get/pin the parent page */ + XT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc); + if (rc) + goto errout2; + + /* + * The new key entry goes ONE AFTER the index of parent entry, + * because the split was to the right. + */ + skip = parent->index + 1; + + /* + * split or shift right remaining entries of the parent page + */ + nextindex = le16_to_cpu(sp->header.nextindex); + /* + * parent page is full - split the parent page + */ + if (nextindex == le16_to_cpu(sp->header.maxentry)) { + /* init for parent page split */ + split->mp = smp; + split->index = skip; /* index at insert */ + split->flag = XAD_NEW; + split->off = offsetXAD(&rcp->xad[XTENTRYSTART]); + split->len = JFS_SBI(ip->i_sb)->nbperpage; + split->addr = rcbn; + + /* unpin previous right child page */ + XT_PUTPAGE(rcmp); + + /* The split routines insert the new entry, + * and acquire txLock as appropriate. + * return pinned and its block number . + */ + rc = (sp->header.flag & BT_ROOT) ? + xtSplitRoot(tid, ip, split, &rmp) : + xtSplitPage(tid, ip, split, &rmp, &rbn); + if (rc) + goto errout1; + + XT_PUTPAGE(smp); + /* keep new child page pinned */ + } + /* + * parent page is not full - insert in parent page + */ + else { + /* + * insert router entry in parent for the right child + * page from the first entry of the right child page: + */ + /* + * acquire a transaction lock on the parent page; + * + * action: router xad insertion; + */ + BT_MARK_DIRTY(smp, ip); + + /* + * if insert into middle, shift right remaining entries + */ + if (skip < nextindex) + memmove(&sp->xad[skip + 1], &sp->xad[skip], + (nextindex - + skip) << L2XTSLOTSIZE); + + /* insert the router entry */ + xad = &sp->xad[skip]; + XT_PUTENTRY(xad, XAD_NEW, + offsetXAD(&rcp->xad[XTENTRYSTART]), + JFS_SBI(ip->i_sb)->nbperpage, rcbn); + + /* advance next available entry index. */ + sp->header.nextindex = + cpu_to_le16(le16_to_cpu(sp->header.nextindex) + + 1); + + /* Don't log it if there are no links to the file */ + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, smp, + tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->lwm.offset = (xtlck->lwm.offset) ? + min(skip, (int)xtlck->lwm.offset) : skip; + xtlck->lwm.length = + le16_to_cpu(sp->header.nextindex) - + xtlck->lwm.offset; + } + + /* unpin parent page */ + XT_PUTPAGE(smp); + + /* exit propagate up */ + break; + } + } + + /* unpin current right page */ + XT_PUTPAGE(rmp); + + return 0; + + /* + * If something fails in the above loop we were already walking back + * up the tree and the tree is now inconsistent. + * release all pages we're holding. + */ + errout1: + XT_PUTPAGE(smp); + + errout2: + XT_PUTPAGE(rcmp); + + return rc; +} + + +/* + * xtSplitPage() + * + * function: + * split a full non-root page into + * original/split/left page and new right page + * i.e., the original/split page remains as left page. + * + * parameter: + * int tid, + * struct inode *ip, + * xtsplit_t *split, + * metapage_t **rmpp, + * u64 *rbnp, + * + * return: + * Pointer to page in which to insert or NULL on error. + */ +static int +xtSplitPage(tid_t tid, struct inode *ip, + xtsplit_t * split, metapage_t ** rmpp, s64 * rbnp) +{ + int rc = 0; + metapage_t *smp; + xtpage_t *sp; + metapage_t *rmp; + xtpage_t *rp; /* new right page allocated */ + s64 rbn; /* new right page block number */ + metapage_t *mp; + xtpage_t *p; + s64 nextbn; + int skip, maxentry, middle, righthalf, n; + xad_t *xad; + pxdlist_t *pxdlist; + pxd_t *pxd; + tlock_t *tlck; + xtlock_t *sxtlck = 0, *rxtlck = 0; + + smp = split->mp; + sp = XT_PAGE(ip, smp); + + INCREMENT(xtStat.split); + + /* + * allocate the new right page for the split + */ + pxdlist = split->pxdlist; + pxd = &pxdlist->pxd[pxdlist->npxd]; + pxdlist->npxd++; + rbn = addressPXD(pxd); + rmp = get_metapage(ip, rbn, PSIZE, 1); + if (rmp == NULL) + return EIO; + + jEVENT(0, + ("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p\n", ip, smp, rmp)); + + BT_MARK_DIRTY(rmp, ip); + /* + * action: new page; + */ + + rp = (xtpage_t *) rmp->data; + rp->header.self = *pxd; + rp->header.flag = sp->header.flag & BT_TYPE; + rp->header.maxentry = sp->header.maxentry; /* little-endian */ + rp->header.nextindex = cpu_to_le16(XTENTRYSTART); + + BT_MARK_DIRTY(smp, ip); + /* Don't log it if there are no links to the file */ + if (!test_cflag(COMMIT_Nolink, ip)) { + /* + * acquire a transaction lock on the new right page; + */ + tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW); + rxtlck = (xtlock_t *) & tlck->lock; + rxtlck->lwm.offset = XTENTRYSTART; + /* + * acquire a transaction lock on the split page + */ + tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW); + sxtlck = (xtlock_t *) & tlck->lock; + } + + /* + * initialize/update sibling pointers of and + */ + nextbn = le64_to_cpu(sp->header.next); + rp->header.next = cpu_to_le64(nextbn); + rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self)); + sp->header.next = cpu_to_le64(rbn); + + skip = split->index; + + /* + * sequential append at tail (after last entry of last page) + * + * if splitting the last page on a level because of appending + * a entry to it (skip is maxentry), it's likely that the access is + * sequential. adding an empty page on the side of the level is less + * work and can push the fill factor much higher than normal. + * if we're wrong it's no big deal - we will do the split the right + * way next time. + * (it may look like it's equally easy to do a similar hack for + * reverse sorted data, that is, split the tree left, but it's not. + * Be my guest.) + */ + if (nextbn == 0 && skip == le16_to_cpu(sp->header.maxentry)) { + /* + * acquire a transaction lock on the new/right page; + * + * action: xad insertion; + */ + /* insert entry at the first entry of the new right page */ + xad = &rp->xad[XTENTRYSTART]; + XT_PUTENTRY(xad, split->flag, split->off, split->len, + split->addr); + + rp->header.nextindex = cpu_to_le16(XTENTRYSTART + 1); + + if (!test_cflag(COMMIT_Nolink, ip)) { + /* rxtlck->lwm.offset = XTENTRYSTART; */ + rxtlck->lwm.length = 1; + } + + *rmpp = rmp; + *rbnp = rbn; + + ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd)); + + jEVENT(0, ("xtSplitPage: sp:0x%p rp:0x%p\n", sp, rp)); + return 0; + } + + /* + * non-sequential insert (at possibly middle page) + */ + + /* + * update previous pointer of old next/right page of + */ + if (nextbn != 0) { + XT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc); + if (rc) { + XT_PUTPAGE(rmp); + return rc; + } + + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the next page; + * + * action:sibling pointer update; + */ + if (!test_cflag(COMMIT_Nolink, ip)) + tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK); + + p->header.prev = cpu_to_le64(rbn); + + /* sibling page may have been updated previously, or + * it may be updated later; + */ + + XT_PUTPAGE(mp); + } + + /* + * split the data between the split and new/right pages + */ + maxentry = le16_to_cpu(sp->header.maxentry); + middle = maxentry >> 1; + righthalf = maxentry - middle; + + /* + * skip index in old split/left page - insert into left page: + */ + if (skip <= middle) { + /* move right half of split page to the new right page */ + memmove(&rp->xad[XTENTRYSTART], &sp->xad[middle], + righthalf << L2XTSLOTSIZE); + + /* shift right tail of left half to make room for new entry */ + if (skip < middle) + memmove(&sp->xad[skip + 1], &sp->xad[skip], + (middle - skip) << L2XTSLOTSIZE); + + /* insert new entry */ + xad = &sp->xad[skip]; + XT_PUTENTRY(xad, split->flag, split->off, split->len, + split->addr); + + /* update page header */ + sp->header.nextindex = cpu_to_le16(middle + 1); + if (!test_cflag(COMMIT_Nolink, ip)) { + sxtlck->lwm.offset = (sxtlck->lwm.offset) ? + min(skip, (int)sxtlck->lwm.offset) : skip; + } + + rp->header.nextindex = + cpu_to_le16(XTENTRYSTART + righthalf); + } + /* + * skip index in new right page - insert into right page: + */ + else { + /* move left head of right half to right page */ + n = skip - middle; + memmove(&rp->xad[XTENTRYSTART], &sp->xad[middle], + n << L2XTSLOTSIZE); + + /* insert new entry */ + n += XTENTRYSTART; + xad = &rp->xad[n]; + XT_PUTENTRY(xad, split->flag, split->off, split->len, + split->addr); + + /* move right tail of right half to right page */ + if (skip < maxentry) + memmove(&rp->xad[n + 1], &sp->xad[skip], + (maxentry - skip) << L2XTSLOTSIZE); + + /* update page header */ + sp->header.nextindex = cpu_to_le16(middle); + if (!test_cflag(COMMIT_Nolink, ip)) { + sxtlck->lwm.offset = (sxtlck->lwm.offset) ? + min(middle, (int)sxtlck->lwm.offset) : middle; + } + + rp->header.nextindex = cpu_to_le16(XTENTRYSTART + + righthalf + 1); + } + + if (!test_cflag(COMMIT_Nolink, ip)) { + sxtlck->lwm.length = le16_to_cpu(sp->header.nextindex) - + sxtlck->lwm.offset; + + /* rxtlck->lwm.offset = XTENTRYSTART; */ + rxtlck->lwm.length = le16_to_cpu(rp->header.nextindex) - + XTENTRYSTART; + } + + *rmpp = rmp; + *rbnp = rbn; + + ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd)); + + jEVENT(0, ("xtSplitPage: sp:0x%p rp:0x%p\n", sp, rp)); + return rc; +} + + +/* + * xtSplitRoot() + * + * function: + * split the full root page into + * original/root/split page and new right page + * i.e., root remains fixed in tree anchor (inode) and + * the root is copied to a single new right child page + * since root page << non-root page, and + * the split root page contains a single entry for the + * new right child page. + * + * parameter: + * int tid, + * struct inode *ip, + * xtsplit_t *split, + * metapage_t **rmpp) + * + * return: + * Pointer to page in which to insert or NULL on error. + */ +static int +xtSplitRoot(tid_t tid, + struct inode *ip, xtsplit_t * split, metapage_t ** rmpp) +{ + xtpage_t *sp; + metapage_t *rmp; + xtpage_t *rp; + s64 rbn; + int skip, nextindex; + xad_t *xad; + pxd_t *pxd; + pxdlist_t *pxdlist; + tlock_t *tlck; + xtlock_t *xtlck; + + sp = &JFS_IP(ip)->i_xtroot; + + INCREMENT(xtStat.split); + + /* + * allocate a single (right) child page + */ + pxdlist = split->pxdlist; + pxd = &pxdlist->pxd[pxdlist->npxd]; + pxdlist->npxd++; + rbn = addressPXD(pxd); + rmp = get_metapage(ip, rbn, PSIZE, 1); + if (rmp == NULL) + return EIO; + + jEVENT(0, ("xtSplitRoot: ip:0x%p rmp:0x%p\n", ip, rmp)); + + /* + * acquire a transaction lock on the new right page; + * + * action: new page; + */ + BT_MARK_DIRTY(rmp, ip); + + rp = (xtpage_t *) rmp->data; + rp->header.flag = + (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL; + rp->header.self = *pxd; + rp->header.nextindex = cpu_to_le16(XTENTRYSTART); + rp->header.maxentry = cpu_to_le16(PSIZE >> L2XTSLOTSIZE); + + /* initialize sibling pointers */ + rp->header.next = 0; + rp->header.prev = 0; + + /* + * copy the in-line root page into new right page extent + */ + nextindex = le16_to_cpu(sp->header.maxentry); + memmove(&rp->xad[XTENTRYSTART], &sp->xad[XTENTRYSTART], + (nextindex - XTENTRYSTART) << L2XTSLOTSIZE); + + /* + * insert the new entry into the new right/child page + * (skip index in the new right page will not change) + */ + skip = split->index; + /* if insert into middle, shift right remaining entries */ + if (skip != nextindex) + memmove(&rp->xad[skip + 1], &rp->xad[skip], + (nextindex - skip) * sizeof(xad_t)); + + xad = &rp->xad[skip]; + XT_PUTENTRY(xad, split->flag, split->off, split->len, split->addr); + + /* update page header */ + rp->header.nextindex = cpu_to_le16(nextindex + 1); + + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->lwm.offset = XTENTRYSTART; + xtlck->lwm.length = le16_to_cpu(rp->header.nextindex) - + XTENTRYSTART; + } + + /* + * reset the root + * + * init root with the single entry for the new right page + * set the 1st entry offset to 0, which force the left-most key + * at any level of the tree to be less than any search key. + */ + /* + * acquire a transaction lock on the root page (in-memory inode); + * + * action: root split; + */ + BT_MARK_DIRTY(split->mp, ip); + + xad = &sp->xad[XTENTRYSTART]; + XT_PUTENTRY(xad, XAD_NEW, 0, JFS_SBI(ip->i_sb)->nbperpage, rbn); + + /* update page header of root */ + sp->header.flag &= ~BT_LEAF; + sp->header.flag |= BT_INTERNAL; + + sp->header.nextindex = cpu_to_le16(XTENTRYSTART + 1); + + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, split->mp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->lwm.offset = XTENTRYSTART; + xtlck->lwm.length = 1; + } + + *rmpp = rmp; + + ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd)); + + jEVENT(0, ("xtSplitRoot: sp:0x%p rp:0x%p\n", sp, rp)); + return 0; +} + + +/* + * xtExtend() + * + * function: extend in-place; + * + * note: existing extent may or may not have been committed. + * caller is responsible for pager buffer cache update, and + * working block allocation map update; + * update pmap: alloc whole extended extent; + */ +int xtExtend(tid_t tid, /* transaction id */ + struct inode *ip, s64 xoff, /* delta extent offset */ + s32 xlen, /* delta extent length */ + int flag) +{ + int rc = 0; + int cmp; + metapage_t *mp; /* meta-page buffer */ + xtpage_t *p; /* base B+-tree index page */ + s64 bn; + int index, nextindex, len; + btstack_t btstack; /* traverse stack */ + xtsplit_t split; /* split information */ + xad_t *xad; + s64 xaddr; + tlock_t *tlck; + xtlock_t *xtlck = 0; + int rootsplit = 0; + + jFYI(1, + ("xtExtend: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen)); + + /* there must exist extent to be extended */ + if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT))) + return rc; + assert(cmp == 0); + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + /* extension must be contiguous */ + xad = &p->xad[index]; + jFYI(0, ("xtExtend: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n", + (ulong) offsetXAD(xad), lengthXAD(xad), + (ulong) addressXAD(xad))); + assert((offsetXAD(xad) + lengthXAD(xad)) == xoff); + + /* + * acquire a transaction lock on the leaf page; + * + * action: xad insertion/extension; + */ + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + } + + /* extend will overflow extent ? */ + xlen = lengthXAD(xad) + xlen; + if ((len = xlen - MAXXLEN) <= 0) + goto extendOld; + + /* + * extent overflow: insert entry for new extent + */ +//insertNew: + xoff = offsetXAD(xad) + MAXXLEN; + xaddr = addressXAD(xad) + MAXXLEN; + nextindex = le16_to_cpu(p->header.nextindex); + + /* + * if the leaf page is full, insert the new entry and + * propagate up the router entry for the new page from split + * + * The xtSplitUp() will insert the entry and unpin the leaf page. + */ + if (nextindex == le16_to_cpu(p->header.maxentry)) { + rootsplit = p->header.flag & BT_ROOT; + + /* xtSpliUp() unpins leaf pages */ + split.mp = mp; + split.index = index + 1; + split.flag = XAD_NEW; + split.off = xoff; /* split offset */ + split.len = len; + split.addr = xaddr; + split.pxdlist = NULL; + if ((rc = xtSplitUp(tid, ip, &split, &btstack))) + return rc; + + /* + * if leaf root has been split, original root has been + * copied to new child page, i.e., original entry now + * resides on the new child page; + */ + if (rootsplit) { + if (p->header.nextindex == + cpu_to_le16(XTENTRYSTART + 1)) { + xad = &p->xad[XTENTRYSTART]; + bn = addressXAD(xad); + + /* get new child page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, + tlckXTREE | + tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + } + } + } else + /* get back old page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + } + /* + * insert the new entry into the leaf page + */ + else { + /* insert the new entry: mark the entry NEW */ + xad = &p->xad[index + 1]; + XT_PUTENTRY(xad, XAD_NEW, xoff, len, xaddr); + + /* advance next available entry index */ + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1); + } + + /* get back old entry */ + xad = &p->xad[index]; + xlen = MAXXLEN; + + /* + * extend old extent + */ + extendOld: + XADlength(xad, xlen); + if (!(xad->flag & XAD_NEW)) + xad->flag |= XAD_EXTENDED; + + if (!test_cflag(COMMIT_Nolink, ip)) { + xtlck->lwm.offset = + (xtlck->lwm.offset) ? min(index, + (int)xtlck->lwm.offset) : index; + xtlck->lwm.length = + le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset; + } + + /* unpin the leaf page */ + XT_PUTPAGE(mp); + + return rc; +} + + +/* + * xtTailgate() + * + * function: split existing 'tail' extent + * (split offset >= start offset of tail extent), and + * relocate and extend the split tail half; + * + * note: existing extent may or may not have been committed. + * caller is responsible for pager buffer cache update, and + * working block allocation map update; + * update pmap: free old split tail extent, alloc new extent; + */ +int xtTailgate(tid_t tid, /* transaction id */ + struct inode *ip, s64 xoff, /* split/new extent offset */ + s32 xlen, /* new extent length */ + s64 xaddr, /* new extent address */ + int flag) +{ + int rc = 0; + int cmp; + metapage_t *mp; /* meta-page buffer */ + xtpage_t *p; /* base B+-tree index page */ + s64 bn; + int index, nextindex, llen, rlen; + btstack_t btstack; /* traverse stack */ + xtsplit_t split; /* split information */ + xad_t *xad; + tlock_t *tlck; + xtlock_t *xtlck = 0; + tlock_t *mtlck; + maplock_t *pxdlock; + int rootsplit = 0; + +/* +printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n", + (ulong)xoff, xlen, (ulong)xaddr); +*/ + + /* there must exist extent to be tailgated */ + if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT))) + return rc; + assert(cmp == 0); + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + /* entry found must be last entry */ + nextindex = le16_to_cpu(p->header.nextindex); + assert(index == nextindex - 1); + + BT_MARK_DIRTY(mp, ip); + /* + * acquire tlock of the leaf page containing original entry + */ + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + } + + /* completely replace extent ? */ + xad = &p->xad[index]; +/* +printf("xtTailgate: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n", + (ulong)offsetXAD(xad), lengthXAD(xad), (ulong)addressXAD(xad)); +*/ + if ((llen = xoff - offsetXAD(xad)) == 0) + goto updateOld; + + /* + * partially replace extent: insert entry for new extent + */ +//insertNew: + /* + * if the leaf page is full, insert the new entry and + * propagate up the router entry for the new page from split + * + * The xtSplitUp() will insert the entry and unpin the leaf page. + */ + if (nextindex == le16_to_cpu(p->header.maxentry)) { + rootsplit = p->header.flag & BT_ROOT; + + /* xtSpliUp() unpins leaf pages */ + split.mp = mp; + split.index = index + 1; + split.flag = XAD_NEW; + split.off = xoff; /* split offset */ + split.len = xlen; + split.addr = xaddr; + split.pxdlist = NULL; + if ((rc = xtSplitUp(tid, ip, &split, &btstack))) + return rc; + + /* + * if leaf root has been split, original root has been + * copied to new child page, i.e., original entry now + * resides on the new child page; + */ + if (rootsplit) { + if (p->header.nextindex == + cpu_to_le16(XTENTRYSTART + 1)) { + xad = &p->xad[XTENTRYSTART]; + bn = addressXAD(xad); + + /* get new child page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, + tlckXTREE | + tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + } + } + } else + /* get back old page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + } + /* + * insert the new entry into the leaf page + */ + else { + /* insert the new entry: mark the entry NEW */ + xad = &p->xad[index + 1]; + XT_PUTENTRY(xad, XAD_NEW, xoff, xlen, xaddr); + + /* advance next available entry index */ + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1); + } + + /* get back old XAD */ + xad = &p->xad[index]; + + /* + * truncate/relocate old extent at split offset + */ + updateOld: + /* update dmap for old/committed/truncated extent */ + rlen = lengthXAD(xad) - llen; + if (!(xad->flag & XAD_NEW)) { + /* free from PWMAP at commit */ + if (!test_cflag(COMMIT_Nolink, ip)) { + mtlck = txMaplock(tid, ip, tlckMAP); + pxdlock = (maplock_t *) & mtlck->lock; + pxdlock->flag = mlckFREEPXD; + PXDaddress(&pxdlock->pxd, addressXAD(xad) + llen); + PXDlength(&pxdlock->pxd, rlen); + pxdlock->index = 1; + } + jEVENT(0, + ("xtTailgate: free extent xaddr:0x%lx xlen:0x%x\n", + (ulong) addressPXD(&pxdlock->pxd), + lengthPXD(&pxdlock->pxd))); + } else + /* free from WMAP */ + dbFree(ip, addressXAD(xad) + llen, (s64) rlen); + + if (llen) + /* truncate */ + XADlength(xad, llen); + else + /* replace */ + XT_PUTENTRY(xad, XAD_NEW, xoff, xlen, xaddr); + + if (!test_cflag(COMMIT_Nolink, ip)) { + xtlck->lwm.offset = (xtlck->lwm.offset) ? + min(index, (int)xtlck->lwm.offset) : index; + xtlck->lwm.length = le16_to_cpu(p->header.nextindex) - + xtlck->lwm.offset; + } + + /* unpin the leaf page */ + XT_PUTPAGE(mp); + + return rc; +} + + +/* + * xtUpdate() + * + * function: update XAD; + * + * update extent for allocated_but_not_recorded or + * compressed extent; + * + * parameter: + * nxad - new XAD; + * logical extent of the specified XAD must be completely + * contained by an existing XAD; + */ +int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad) +{ /* new XAD */ + int rc = 0; + int cmp; + metapage_t *mp; /* meta-page buffer */ + xtpage_t *p; /* base B+-tree index page */ + s64 bn; + int index0, index, newindex, nextindex; + btstack_t btstack; /* traverse stack */ + xtsplit_t split; /* split information */ + xad_t *xad, *lxad, *rxad; + int xflag; + s64 nxoff, xoff; + int nxlen, xlen, lxlen, rxlen; + s64 nxaddr, xaddr; + tlock_t *tlck; + xtlock_t *xtlck = 0; + int rootsplit = 0, newpage = 0; + + /* there must exist extent to be tailgated */ + nxoff = offsetXAD(nxad); + nxlen = lengthXAD(nxad); + nxaddr = addressXAD(nxad); +/* +printf("xtUpdate: nxflag:0x%x nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n", + nxad->flag, (ulong)nxoff, nxlen, (ulong)nxaddr); +*/ + if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT))) + return rc; + assert(cmp == 0); + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); + + BT_MARK_DIRTY(mp, ip); + /* + * acquire tlock of the leaf page containing original entry + */ + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + } + + xad = &p->xad[index0]; + xflag = xad->flag; + xoff = offsetXAD(xad); + xlen = lengthXAD(xad); + xaddr = addressXAD(xad); +/* +printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n", + xflag, (ulong)xoff, xlen, (ulong)xaddr); +*/ + + /* nXAD must be completely contained within XAD */ + assert(xoff <= nxoff); + assert(nxoff + nxlen <= xoff + xlen); + + index = index0; + newindex = index + 1; + nextindex = le16_to_cpu(p->header.nextindex); + +#ifdef _JFS_WIP_NOCOALESCE + if (xoff < nxoff) + goto updateRight; + + /* + * replace XAD with nXAD + */ + replace: /* (nxoff == xoff) */ + if (nxlen == xlen) { + /* replace XAD with nXAD:recorded */ + *xad = *nxad; + xad->flag = xflag & ~XAD_NOTRECORDED; + + goto out; + } else /* (nxlen < xlen) */ + goto updateLeft; +#endif /* _JFS_WIP_NOCOALESCE */ + +/* #ifdef _JFS_WIP_COALESCE */ + if (xoff < nxoff) + goto coalesceRight; + + /* + * coalesce with left XAD + */ +//coalesceLeft: /* (xoff == nxoff) */ + /* is XAD first entry of page ? */ + if (index == XTENTRYSTART) + goto replace; + + /* is nXAD logically and physically contiguous with lXAD ? */ + lxad = &p->xad[index - 1]; + lxlen = lengthXAD(lxad); + if (!(lxad->flag & XAD_NOTRECORDED) && + (nxoff == offsetXAD(lxad) + lxlen) && + (nxaddr == addressXAD(lxad) + lxlen) && + (lxlen + nxlen < MAXXLEN)) { + /* extend right lXAD */ + index0 = index - 1; + XADlength(lxad, lxlen + nxlen); + + /* If we just merged two extents together, need to make sure the + * right extent gets logged. If the left one is marked XAD_NEW, + * then we know it will be logged. Otherwise, mark as + * XAD_EXTENDED + */ + if (!(lxad->flag & XAD_NEW)) + lxad->flag |= XAD_EXTENDED; + + if (xlen > nxlen) { + /* truncate XAD */ + XADoffset(xad, xoff + nxlen); + XADlength(xad, xlen - nxlen); + XADaddress(xad, xaddr + nxlen); + goto out; + } else { /* (xlen == nxlen) */ + + /* remove XAD */ + if (index < nextindex - 1) + memmove(&p->xad[index], &p->xad[index + 1], + (nextindex - index - + 1) << L2XTSLOTSIZE); + + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) - + 1); + + index = index0; + newindex = index + 1; + nextindex = le16_to_cpu(p->header.nextindex); + xoff = nxoff = offsetXAD(lxad); + xlen = nxlen = lxlen + nxlen; + xaddr = nxaddr = addressXAD(lxad); + goto coalesceRight; + } + } + + /* + * replace XAD with nXAD + */ + replace: /* (nxoff == xoff) */ + if (nxlen == xlen) { + /* replace XAD with nXAD:recorded */ + *xad = *nxad; + xad->flag = xflag & ~XAD_NOTRECORDED; + + goto coalesceRight; + } else /* (nxlen < xlen) */ + goto updateLeft; + + /* + * coalesce with right XAD + */ + coalesceRight: /* (xoff <= nxoff) */ + /* is XAD last entry of page ? */ + if (newindex == nextindex) { + if (xoff == nxoff) + goto out; + goto updateRight; + } + + /* is nXAD logically and physically contiguous with rXAD ? */ + rxad = &p->xad[index + 1]; + rxlen = lengthXAD(rxad); + if (!(rxad->flag & XAD_NOTRECORDED) && + (nxoff + nxlen == offsetXAD(rxad)) && + (nxaddr + nxlen == addressXAD(rxad)) && + (rxlen + nxlen < MAXXLEN)) { + /* extend left rXAD */ + XADoffset(rxad, nxoff); + XADlength(rxad, rxlen + nxlen); + XADaddress(rxad, nxaddr); + + /* If we just merged two extents together, need to make sure + * the left extent gets logged. If the right one is marked + * XAD_NEW, then we know it will be logged. Otherwise, mark as + * XAD_EXTENDED + */ + if (!(rxad->flag & XAD_NEW)) + rxad->flag |= XAD_EXTENDED; + + if (xlen > nxlen) + /* truncate XAD */ + XADlength(xad, xlen - nxlen); + else { /* (xlen == nxlen) */ + + /* remove XAD */ + memmove(&p->xad[index], &p->xad[index + 1], + (nextindex - index - 1) << L2XTSLOTSIZE); + + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) - + 1); + } + + goto out; + } else if (xoff == nxoff) + goto out; + + assert(xoff < nxoff); +/* #endif _JFS_WIP_COALESCE */ + + /* + * split XAD into (lXAD, nXAD): + * + * |---nXAD---> + * --|----------XAD----------|-- + * |-lXAD-| + */ + updateRight: /* (xoff < nxoff) */ + /* truncate old XAD as lXAD:not_recorded */ + xad = &p->xad[index]; + XADlength(xad, nxoff - xoff); + + /* insert nXAD:recorded */ + if (nextindex == le16_to_cpu(p->header.maxentry)) { +/* +printf("xtUpdate.updateRight.split p:0x%p\n", p); +*/ + rootsplit = p->header.flag & BT_ROOT; + + /* xtSpliUp() unpins leaf pages */ + split.mp = mp; + split.index = newindex; + split.flag = xflag & ~XAD_NOTRECORDED; + split.off = nxoff; + split.len = nxlen; + split.addr = nxaddr; + split.pxdlist = NULL; + if ((rc = xtSplitUp(tid, ip, &split, &btstack))) + return rc; + + /* + * if leaf root has been split, original root has been + * copied to new child page, i.e., original entry now + * resides on the new child page; + */ + if (rootsplit) { + if (p->header.nextindex == + cpu_to_le16(XTENTRYSTART + 1)) { + xad = &p->xad[XTENTRYSTART]; + bn = addressXAD(xad); + + /* get new child page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, + tlckXTREE | + tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + } + } + } else { + /* get back old page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + + /* is nXAD on new page ? */ + if (newindex > + (le16_to_cpu(p->header.maxentry) >> 1)) { + newindex = + newindex - + le16_to_cpu(p->header.nextindex) + + XTENTRYSTART; + newpage = 1; + } + } + } else { + /* if insert into middle, shift right remaining entries */ + if (newindex < nextindex) + memmove(&p->xad[newindex + 1], &p->xad[newindex], + (nextindex - newindex) << L2XTSLOTSIZE); + + /* insert the entry */ + xad = &p->xad[newindex]; + *xad = *nxad; + xad->flag = xflag & ~XAD_NOTRECORDED; + + /* advance next available entry index. */ + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1); + } + + /* + * does nXAD force 3-way split ? + * + * |---nXAD--->| + * --|----------XAD-------------|-- + * |-lXAD-| |-rXAD -| + */ + if (nxoff + nxlen == xoff + xlen) + goto out; + + /* reorient nXAD as XAD for further split XAD into (nXAD, rXAD) */ + if (newpage) { + /* close out old page */ + if (!test_cflag(COMMIT_Nolink, ip)) { + xtlck->lwm.offset = (xtlck->lwm.offset) ? + min(index0, (int)xtlck->lwm.offset) : index0; + xtlck->lwm.length = + le16_to_cpu(p->header.nextindex) - + xtlck->lwm.offset; + } + + bn = le64_to_cpu(p->header.next); + XT_PUTPAGE(mp); + + /* get new right page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + } + + index0 = index = newindex; + } else + index++; + + newindex = index + 1; + nextindex = le16_to_cpu(p->header.nextindex); + xlen = xlen - (nxoff - xoff); + xoff = nxoff; + xaddr = nxaddr; + + /* recompute split pages */ + if (nextindex == le16_to_cpu(p->header.maxentry)) { +/* +printf("xtUpdate: updateRight+Left recompute split pages: p:0x%p\n", p); +*/ + XT_PUTPAGE(mp); + + if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT))) + return rc; + assert(cmp == 0); + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); + assert(index0 == index); + } + + /* + * split XAD into (nXAD, rXAD) + * + * ---nXAD---| + * --|----------XAD----------|-- + * |-rXAD-| + */ + updateLeft: /* (nxoff == xoff) && (nxlen < xlen) */ + /* update old XAD with nXAD:recorded */ + xad = &p->xad[index]; + *xad = *nxad; + xad->flag = xflag & ~XAD_NOTRECORDED; + + /* insert rXAD:not_recorded */ + xoff = xoff + nxlen; + xlen = xlen - nxlen; + xaddr = xaddr + nxlen; + if (nextindex == le16_to_cpu(p->header.maxentry)) { + rootsplit = p->header.flag & BT_ROOT; + +/* +printf("xtUpdate.updateLeft.split p:0x%p\n", p); +*/ + /* xtSpliUp() unpins leaf pages */ + split.mp = mp; + split.index = newindex; + split.flag = xflag; + split.off = xoff; + split.len = xlen; + split.addr = xaddr; + split.pxdlist = NULL; + if ((rc = xtSplitUp(tid, ip, &split, &btstack))) + return rc; + + /* + * if leaf root has been split, original root has been + * copied to new child page, i.e., original entry now + * resides on the new child page; + */ + if (rootsplit) { + if (p->header.nextindex == + cpu_to_le16(XTENTRYSTART + 1)) { + xad = &p->xad[XTENTRYSTART]; + bn = addressXAD(xad); + + /* get new child page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, + tlckXTREE | + tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + } + } + } else + /* get back old page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + } else { + /* if insert into middle, shift right remaining entries */ + if (newindex < nextindex) + memmove(&p->xad[newindex + 1], &p->xad[newindex], + (nextindex - newindex) << L2XTSLOTSIZE); + + /* insert the entry */ + xad = &p->xad[newindex]; + XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr); + + /* advance next available entry index. */ + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1); + } + + out: + if (!test_cflag(COMMIT_Nolink, ip)) { + xtlck->lwm.offset = (xtlck->lwm.offset) ? + min(index0, (int)xtlck->lwm.offset) : index0; + xtlck->lwm.length = le16_to_cpu(p->header.nextindex) - + xtlck->lwm.offset; + } + + /* unpin the leaf page */ + XT_PUTPAGE(mp); + + return rc; +} + + +/* + * xtAppend() + * + * function: grow in append mode from contiguous region specified ; + * + * parameter: + * tid - transaction id; + * ip - file object; + * xflag - extent flag: + * xoff - extent offset; + * maxblocks - max extent length; + * xlen - extent length (in/out); + * xaddrp - extent address pointer (in/out): + * flag - + * + * return: + */ +int xtAppend(tid_t tid, /* transaction id */ + struct inode *ip, int xflag, s64 xoff, s32 maxblocks, + s32 * xlenp, /* (in/out) */ + s64 * xaddrp, /* (in/out) */ + int flag) +{ + int rc = 0; + metapage_t *mp; /* meta-page buffer */ + xtpage_t *p; /* base B+-tree index page */ + s64 bn, xaddr; + int index, nextindex; + btstack_t btstack; /* traverse stack */ + xtsplit_t split; /* split information */ + xad_t *xad; + int cmp; + tlock_t *tlck; + xtlock_t *xtlck; + int nsplit, nblocks, xlen; + pxdlist_t pxdlist; + pxd_t *pxd; + + xaddr = *xaddrp; + xlen = *xlenp; + jEVENT(0, + ("xtAppend: xoff:0x%lx maxblocks:%d xlen:%d xaddr:0x%lx\n", + (ulong) xoff, maxblocks, xlen, (ulong) xaddr)); + + /* + * search for the entry location at which to insert: + * + * xtFastSearch() and xtSearch() both returns (leaf page + * pinned, index at which to insert). + * n.b. xtSearch() may return index of maxentry of + * the full page. + */ + if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT))) + return rc; + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + + if (cmp == 0) { + rc = EEXIST; + goto out; + } +//insert: + /* + * insert entry for new extent + */ + xflag |= XAD_NEW; + + /* + * if the leaf page is full, split the page and + * propagate up the router entry for the new page from split + * + * The xtSplitUp() will insert the entry and unpin the leaf page. + */ + nextindex = le16_to_cpu(p->header.nextindex); + if (nextindex < le16_to_cpu(p->header.maxentry)) + goto insertLeaf; + + /* + * allocate new index blocks to cover index page split(s) + */ + nsplit = btstack.nsplit; + split.pxdlist = &pxdlist; + pxdlist.maxnpxd = pxdlist.npxd = 0; + pxd = &pxdlist.pxd[0]; + nblocks = JFS_SBI(ip->i_sb)->nbperpage; + for (; nsplit > 0; nsplit--, pxd++, xaddr += nblocks, maxblocks -= nblocks) { + if ((rc = dbAllocBottomUp(ip, xaddr, (s64) nblocks)) == 0) { + PXDaddress(pxd, xaddr); + PXDlength(pxd, nblocks); + + pxdlist.maxnpxd++; + + continue; + } + + /* undo allocation */ + + goto out; + } + + xlen = min(xlen, maxblocks); + + /* + * allocate data extent requested + */ + if ((rc = dbAllocBottomUp(ip, xaddr, (s64) xlen))) + goto out; + + split.mp = mp; + split.index = index; + split.flag = xflag; + split.off = xoff; + split.len = xlen; + split.addr = xaddr; + if ((rc = xtSplitUp(tid, ip, &split, &btstack))) { + /* undo data extent allocation */ + dbFree(ip, *xaddrp, (s64) * xlenp); + + return rc; + } + + *xaddrp = xaddr; + *xlenp = xlen; + return 0; + + /* + * insert the new entry into the leaf page + */ + insertLeaf: + /* + * allocate data extent requested + */ + if ((rc = dbAllocBottomUp(ip, xaddr, (s64) xlen))) + goto out; + + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the leaf page; + * + * action: xad insertion/extension; + */ + tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + + /* insert the new entry: mark the entry NEW */ + xad = &p->xad[index]; + XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr); + + /* advance next available entry index */ + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1); + + xtlck->lwm.offset = + (xtlck->lwm.offset) ? min(index,(int) xtlck->lwm.offset) : index; + xtlck->lwm.length = le16_to_cpu(p->header.nextindex) - + xtlck->lwm.offset; + + *xaddrp = xaddr; + *xlenp = xlen; + + out: + /* unpin the leaf page */ + XT_PUTPAGE(mp); + + return rc; +} +#ifdef _STILL_TO_PORT + +/* - TBD for defragmentaion/reorganization - + * + * xtDelete() + * + * function: + * delete the entry with the specified key. + * + * N.B.: whole extent of the entry is assumed to be deleted. + * + * parameter: + * + * return: + * ENOENT: if the entry is not found. + * + * exception: + */ +int xtDelete(tid_t tid, struct inode *ip, s64 xoff, s32 xlen, int flag) +{ + int rc = 0; + btstack_t btstack; + int cmp; + s64 bn; + metapage_t *mp; + xtpage_t *p; + int index, nextindex; + tlock_t *tlck; + xtlock_t *xtlck; + + /* + * find the matching entry; xtSearch() pins the page + */ + if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0))) + return rc; + + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + if (cmp) { + /* unpin the leaf page */ + XT_PUTPAGE(mp); + return ENOENT; + } + + /* + * delete the entry from the leaf page + */ + nextindex = le16_to_cpu(p->header.nextindex); + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) - 1); + + /* + * if the leaf page bocome empty, free the page + */ + if (p->header.nextindex == cpu_to_le16(XTENTRYSTART)) + return (xtDeleteUp(tid, ip, mp, p, &btstack)); + + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the leaf page; + * + * action:xad deletion; + */ + tlck = txLock(tid, ip, mp, tlckXTREE); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->lwm.offset = + (xtlck->lwm.offset) ? min(index, xtlck->lwm.offset) : index; + + /* if delete from middle, shift left/compact the remaining entries */ + if (index < nextindex - 1) + memmove(&p->xad[index], &p->xad[index + 1], + (nextindex - index - 1) * sizeof(xad_t)); + + XT_PUTPAGE(mp); + + return 0; +} + + +/* - TBD for defragmentaion/reorganization - + * + * xtDeleteUp() + * + * function: + * free empty pages as propagating deletion up the tree + * + * parameter: + * + * return: + */ +static int +xtDeleteUp(tid_t tid, + struct inode *ip, + metapage_t * fmp, xtpage_t * fp, btstack_t * btstack) +{ + int rc = 0; + metapage_t *mp; + xtpage_t *p; + int index, nextindex; + s64 xaddr; + int xlen; + btframe_t *parent; + tlock_t *tlck; + xtlock_t *xtlck; + + /* + * keep root leaf page which has become empty + */ + if (fp->header.flag & BT_ROOT) { + /* keep the root page */ + fp->header.flag &= ~BT_INTERNAL; + fp->header.flag |= BT_LEAF; + fp->header.nextindex = cpu_to_le16(XTENTRYSTART); + + /* XT_PUTPAGE(fmp); */ + + return 0; + } + + /* + * free non-root leaf page + */ + if ((rc = xtRelink(tid, ip, fp))) + return rc; + + xaddr = addressPXD(&fp->header.self); + xlen = lengthPXD(&fp->header.self); + /* free the page extent */ + dbFree(ip, xaddr, (s64) xlen); + + /* free the buffer page */ + discard_metapage(fmp); + + /* + * propagate page deletion up the index tree + * + * If the delete from the parent page makes it empty, + * continue all the way up the tree. + * stop if the root page is reached (which is never deleted) or + * if the entry deletion does not empty the page. + */ + while ((parent = BT_POP(btstack)) != NULL) { + /* get/pin the parent page */ + XT_GETPAGE(ip, parent->bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + index = parent->index; + + /* delete the entry for the freed child page from parent. + */ + nextindex = le16_to_cpu(p->header.nextindex); + + /* + * the parent has the single entry being deleted: + * free the parent page which has become empty. + */ + if (nextindex == 1) { + if (p->header.flag & BT_ROOT) { + /* keep the root page */ + p->header.flag &= ~BT_INTERNAL; + p->header.flag |= BT_LEAF; + p->header.nextindex = + cpu_to_le16(XTENTRYSTART); + + /* XT_PUTPAGE(fmp); */ + + break; + } else { + /* free the parent page */ + if ((rc = xtRelink(tid, ip, p))) + return rc; + + xaddr = addressPXD(&p->header.self); + /* free the page extent */ + dbFree(ip, xaddr, + (s64) JFS_SBI(ip->i_sb)->nbperpage); + + /* unpin/free the buffer page */ + discard_metapage(fmp); + + /* propagate up */ + continue; + } + } + /* + * the parent has other entries remaining: + * delete the router entry from the parent page. + */ + else { + BT_MARK_DIRTY(mp, ip); + /* + * acquire a transaction lock on the leaf page; + * + * action:xad deletion; + */ + tlck = txLock(tid, ip, mp, tlckXTREE); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->lwm.offset = + (xtlck->lwm.offset) ? min(index, + xtlck->lwm. + offset) : index; + + /* if delete from middle, + * shift left/compact the remaining entries in the page + */ + if (index < nextindex - 1) + memmove(&p->xad[index], &p->xad[index + 1], + (nextindex - index - + 1) << L2XTSLOTSIZE); + + p->header.nextindex = + cpu_to_le16(le16_to_cpu(p->header.nextindex) - + 1); + jEVENT(0, + ("xtDeleteUp(entry): 0x%lx[%d]\n", + (ulong) parent->bn, index)); + } + + /* unpin the parent page */ + XT_PUTPAGE(mp); + + /* exit propagation up */ + break; + } + + return 0; +} + + +/* + * NAME: xtRelocate() + * + * FUNCTION: relocate xtpage or data extent of regular file; + * This function is mainly used by defragfs utility. + * + * NOTE: This routine does not have the logic to handle + * uncommitted allocated extent. The caller should call + * txCommit() to commit all the allocation before call + * this routine. + */ +xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */ + s64 nxaddr, /* new xaddr */ + int xtype) +{ /* extent type: XTPAGE or DATAEXT */ + int rc = 0; + tblock_t *tblk; + tlock_t *tlck; + xtlock_t *xtlck; + metapage_t *mp, *pmp, *lmp, *rmp; /* meta-page buffer */ + xtpage_t *p, *pp, *rp, *lp; /* base B+-tree index page */ + xad_t *xad; + pxd_t *pxd; + s64 xoff, xsize; + int xlen; + s64 oxaddr, sxaddr, dxaddr, nextbn, prevbn; + cbuf_t *cp; + s64 offset, nbytes, nbrd, pno; + int nb, npages, nblks; + s64 bn; + int cmp; + int index; + pxdlock_t *pxdlock; + btstack_t btstack; /* traverse stack */ + + xtype = xtype & EXTENT_TYPE; + + xoff = offsetXAD(oxad); + oxaddr = addressXAD(oxad); + xlen = lengthXAD(oxad); + + /* validate extent offset */ + offset = xoff << JFS_SBI(ip->i_sb)->l2bsize; + if (offset >= ip->i_size) + return ESTALE; /* stale extent */ + + jEVENT(0, + ("xtRelocate: xtype:%d xoff:0x%lx xlen:0x%x xaddr:0x%lx:0x%lx\n", + xtype, (ulong) xoff, xlen, (ulong) oxaddr, + (ulong) nxaddr)); + + /* + * 1. get and validate the parent xtpage/xad entry + * covering the source extent to be relocated; + */ + if (xtype == DATAEXT) { + /* search in leaf entry */ + rc = xtSearch(ip, xoff, &cmp, &btstack, 0); + if (rc) + return rc; + if (cmp) { + XT_PUTPAGE(pmp); + return ESTALE; + } + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); + + /* validate for exact match with a single entry */ + xad = &pp->xad[index]; + if (addressXAD(xad) != oxaddr || lengthXAD(xad) != xlen) { + XT_PUTPAGE(pmp); + return ESTALE; + } + } else { /* (xtype == XTPAGE) */ + + /* search in internal entry */ + rc = xtSearchNode(ip, oxad, &cmp, &btstack, 0); + if (rc) + return rc; + if (cmp) { + XT_PUTPAGE(pmp); + return ESTALE; + } + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); + + /* xtSearchNode() validated for exact match with a single entry + */ + xad = &pp->xad[index]; + } + jEVENT(0, ("xtRelocate: parent xad entry validated.\n")); + + /* + * 2. relocate the extent + */ + if (xtype == DATAEXT) { + /* if the extent is allocated-but-not-recorded + * there is no real data to be moved in this extent, + */ + if (xad->flag & XAD_NOTRECORDED) + goto out; + else + /* release xtpage for cmRead()/xtLookup() */ + XT_PUTPAGE(pmp); + + /* + * cmRelocate() + * + * copy target data pages to be relocated; + * + * data extent must start at page boundary and + * multiple of page size (except the last data extent); + * read in each page of the source data extent into cbuf, + * update the cbuf extent descriptor of the page to be + * homeward bound to new dst data extent + * copy the data from the old extent to new extent. + * copy is essential for compressed files to avoid problems + * that can arise if there was a change in compression + * algorithms. + * it is a good strategy because it may disrupt cache + * policy to keep the pages in memory afterwards. + */ + offset = xoff << JFS_SBI(ip->i_sb)->l2bsize; + assert((offset & CM_OFFSET) == 0); + nbytes = xlen << JFS_SBI(ip->i_sb)->l2bsize; + pno = offset >> CM_L2BSIZE; + npages = (nbytes + (CM_BSIZE - 1)) >> CM_L2BSIZE; +/* + npages = ((offset + nbytes - 1) >> CM_L2BSIZE) - + (offset >> CM_L2BSIZE) + 1; +*/ + sxaddr = oxaddr; + dxaddr = nxaddr; + + /* process the request one cache buffer at a time */ + for (nbrd = 0; nbrd < nbytes; nbrd += nb, + offset += nb, pno++, npages--) { + /* compute page size */ + nb = min(nbytes - nbrd, CM_BSIZE); + + /* get the cache buffer of the page */ + if (rc = cmRead(ip, offset, npages, &cp)) + break; + + assert(addressPXD(&cp->cm_pxd) == sxaddr); + assert(!cp->cm_modified); + + /* bind buffer with the new extent address */ + nblks = nb >> JFS_IP(ip->i_sb)->l2bsize; + cmSetXD(ip, cp, pno, dxaddr, nblks); + + /* release the cbuf, mark it as modified */ + cmPut(cp, TRUE); + + dxaddr += nblks; + sxaddr += nblks; + } + + /* get back parent page */ + rc = xtSearch(ip, xoff, &cmp, &btstack, 0); + XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); + jEVENT(0, ("xtRelocate: target data extent relocated.\n")); + } else { /* (xtype == XTPAGE) */ + + /* + * read in the target xtpage from the source extent; + */ + XT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc); + if (rc) { + XT_PUTPAGE(pmp); + return rc; + } + + /* + * read in sibling pages if any to update sibling pointers; + */ + rmp = NULL; + if (p->header.next) { + nextbn = le64_to_cpu(p->header.next); + XT_GETPAGE(ip, nextbn, rmp, PSIZE, rp, rc); + if (rc) { + XT_PUTPAGE(pmp); + XT_PUTPAGE(mp); + return (rc); + } + } + + lmp = NULL; + if (p->header.prev) { + prevbn = le64_to_cpu(p->header.prev); + XT_GETPAGE(ip, prevbn, lmp, PSIZE, lp, rc); + if (rc) { + XT_PUTPAGE(pmp); + XT_PUTPAGE(mp); + if (rmp) + XT_PUTPAGE(rmp); + return (rc); + } + } + + /* at this point, all xtpages to be updated are in memory */ + + /* + * update sibling pointers of sibling xtpages if any; + */ + if (lmp) { + BT_MARK_DIRTY(lmp, ip); + tlck = + txLock(tid, ip, lmp, tlckXTREE | tlckRELINK); + lp->header.next = cpu_to_le64(nxaddr); + XT_PUTPAGE(lmp); + } + + if (rmp) { + BT_MARK_DIRTY(rmp, ip); + tlck = + txLock(tid, ip, rmp, tlckXTREE | tlckRELINK); + rp->header.prev = cpu_to_le64(nxaddr); + XT_PUTPAGE(rmp); + } + + /* + * update the target xtpage to be relocated + * + * update the self address of the target page + * and write to destination extent; + * redo image covers the whole xtpage since it is new page + * to the destination extent; + * update of bmap for the free of source extent + * of the target xtpage itself: + * update of bmap for the allocation of destination extent + * of the target xtpage itself: + * update of bmap for the extents covered by xad entries in + * the target xtpage is not necessary since they are not + * updated; + * if not committed before this relocation, + * target page may contain XAD_NEW entries which must + * be scanned for bmap update (logredo() always + * scan xtpage REDOPAGE image for bmap update); + * if committed before this relocation (tlckRELOCATE), + * scan may be skipped by commit() and logredo(); + */ + BT_MARK_DIRTY(mp, ip); + /* tlckNEW init xtlck->lwm.offset = XTENTRYSTART; */ + tlck = txLock(tid, ip, mp, tlckXTREE | tlckNEW); + xtlck = (xtlock_t *) & tlck->lock; + + /* update the self address in the xtpage header */ + pxd = &p->header.self; + PXDaddress(pxd, nxaddr); + + /* linelock for the after image of the whole page */ + xtlck->lwm.length = + le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset; + + /* update the buffer extent descriptor of target xtpage */ + xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize; + bmSetXD(mp, nxaddr, xsize); + + /* unpin the target page to new homeward bound */ + XT_PUTPAGE(mp); + jEVENT(0, ("xtRelocate: target xtpage relocated.\n")); + } + + /* + * 3. acquire maplock for the source extent to be freed; + * + * acquire a maplock saving the src relocated extent address; + * to free of the extent at commit time; + */ + out: + /* if DATAEXT relocation, write a LOG_UPDATEMAP record for + * free PXD of the source data extent (logredo() will update + * bmap for free of source data extent), and update bmap for + * free of the source data extent; + */ + if (xtype == DATAEXT) + tlck = txMaplock(tid, ip, tlckMAP); + /* if XTPAGE relocation, write a LOG_NOREDOPAGE record + * for the source xtpage (logredo() will init NoRedoPage + * filter and will also update bmap for free of the source + * xtpage), and update bmap for free of the source xtpage; + * N.B. We use tlckMAP instead of tlkcXTREE because there + * is no buffer associated with this lock since the buffer + * has been redirected to the target location. + */ + else /* (xtype == XTPAGE) */ + tlck = txMaplock(tid, ip, tlckMAP | tlckRELOCATE); + + pxdlock = (pxdlock_t *) & tlck->lock; + pxdlock->flag = mlckFREEPXD; + PXDaddress(&pxdlock->pxd, oxaddr); + PXDlength(&pxdlock->pxd, xlen); + pxdlock->index = 1; + + /* + * 4. update the parent xad entry for relocation; + * + * acquire tlck for the parent entry with XAD_NEW as entry + * update which will write LOG_REDOPAGE and update bmap for + * allocation of XAD_NEW destination extent; + */ + jEVENT(0, ("xtRelocate: update parent xad entry.\n")); + BT_MARK_DIRTY(pmp, ip); + tlck = txLock(tid, ip, pmp, tlckXTREE | tlckGROW); + xtlck = (xtlock_t *) & tlck->lock; + + /* update the XAD with the new destination extent; */ + xad = &pp->xad[index]; + xad->flag |= XAD_NEW; + XADaddress(xad, nxaddr); + + xtlck->lwm.offset = min(index, xtlck->lwm.offset); + xtlck->lwm.length = le16_to_cpu(pp->header.nextindex) - + xtlck->lwm.offset; + + /* unpin the parent xtpage */ + XT_PUTPAGE(pmp); + + return rc; +} + + +/* + * xtSearchNode() + * + * function: search for the internal xad entry covering specified extent. + * This function is mainly used by defragfs utility. + * + * parameters: + * ip - file object; + * xad - extent to find; + * cmpp - comparison result: + * btstack - traverse stack; + * flag - search process flag; + * + * returns: + * btstack contains (bn, index) of search path traversed to the entry. + * *cmpp is set to result of comparison with the entry returned. + * the page containing the entry is pinned at exit. + */ +static int xtSearchNode(struct inode *ip, xad_t * xad, /* required XAD entry */ + int *cmpp, btstack_t * btstack, int flag) +{ + int rc = 0; + s64 xoff, xaddr; + int xlen; + int cmp = 1; /* init for empty page */ + s64 bn; /* block number */ + metapage_t *mp; /* meta-page buffer */ + xtpage_t *p; /* page */ + int base, index, lim; + btframe_t *btsp; + s64 t64; + + BT_CLR(btstack); + + xoff = offsetXAD(xad); + xlen = lengthXAD(xad); + xaddr = addressXAD(xad); + + /* + * search down tree from root: + * + * between two consecutive entries of and of + * internal page, child page Pi contains entry with k, Ki <= K < Kj. + * + * if entry with search key K is not found + * internal page search find the entry with largest key Ki + * less than K which point to the child page to search; + * leaf page search find the entry with smallest key Kj + * greater than K so that the returned index is the position of + * the entry to be shifted right for insertion of new entry. + * for empty tree, search key is greater than any key of the tree. + * + * by convention, root bn = 0. + */ + for (bn = 0;;) { + /* get/pin the page to search */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + if (p->header.flag & BT_LEAF) + return ESTALE; + + lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART; + + /* + * binary search with search key K on the current page + */ + for (base = XTENTRYSTART; lim; lim >>= 1) { + index = base + (lim >> 1); + + XT_CMP(cmp, xoff, &p->xad[index], t64); + if (cmp == 0) { + /* + * search hit + * + * verify for exact match; + */ + if (xaddr == addressXAD(&p->xad[index]) && + xoff == offsetXAD(&p->xad[index])) { + *cmpp = cmp; + + /* save search result */ + btsp = btstack->top; + btsp->bn = bn; + btsp->index = index; + btsp->mp = mp; + + return 0; + } + + /* descend/search its child page */ + goto next; + } + + if (cmp > 0) { + base = index + 1; + --lim; + } + } + + /* + * search miss - non-leaf page: + * + * base is the smallest index with key (Kj) greater than + * search key (K) and may be zero or maxentry index. + * if base is non-zero, decrement base by one to get the parent + * entry of the child page to search. + */ + index = base ? base - 1 : base; + + /* + * go down to child page + */ + next: + /* get the child page block number */ + bn = addressXAD(&p->xad[index]); + + /* unpin the parent page */ + XT_PUTPAGE(mp); + } +} + + +/* + * xtRelink() + * + * function: + * link around a freed page. + * + * Parameter: + * int tid, + * struct inode *ip, + * xtpage_t *p) + * + * returns: + */ +static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * p) +{ + int rc = 0; + metapage_t *mp; + s64 nextbn, prevbn; + tlock_t *tlck; + + nextbn = le64_to_cpu(p->header.next); + prevbn = le64_to_cpu(p->header.prev); + + /* update prev pointer of the next page */ + if (nextbn != 0) { + XT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* + * acquire a transaction lock on the page; + * + * action: update prev pointer; + */ + BT_MARK_DIRTY(mp, ip); + tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK); + + /* the page may already have been tlock'd */ + + p->header.prev = cpu_to_le64(prevbn); + + XT_PUTPAGE(mp); + } + + /* update next pointer of the previous page */ + if (prevbn != 0) { + XT_GETPAGE(ip, prevbn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* + * acquire a transaction lock on the page; + * + * action: update next pointer; + */ + BT_MARK_DIRTY(mp, ip); + tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK); + + /* the page may already have been tlock'd */ + + p->header.next = le64_to_cpu(nextbn); + + XT_PUTPAGE(mp); + } + + return 0; +} +#endif /* _STILL_TO_PORT */ + + +/* + * xtInitRoot() + * + * initialize file root (inline in inode) + */ +void xtInitRoot(tid_t tid, struct inode *ip) +{ + xtpage_t *p; + tlock_t *tlck; + + /* + * acquire a transaction lock on the root + * + * action: + */ + tlck = txLock(tid, ip, (metapage_t *) &JFS_IP(ip)->bxflag, + tlckXTREE | tlckNEW); + p = &JFS_IP(ip)->i_xtroot; + + p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF; + p->header.nextindex = cpu_to_le16(XTENTRYSTART); + + if (S_ISDIR(ip->i_mode)) + p->header.maxentry = cpu_to_le16(XTROOTINITSLOT_DIR); + else { + p->header.maxentry = cpu_to_le16(XTROOTINITSLOT); + ip->i_size = 0; + } + + + return; +} + + +/* + * We can run into a deadlock truncating a file with a large number of + * xtree pages (large fragmented file). A robust fix would entail a + * reservation system where we would reserve a number of metadata pages + * and tlocks which we would be guaranteed without a deadlock. Without + * this, a partial fix is to limit number of metadata pages we will lock + * in a single transaction. Currently we will truncate the file so that + * no more than 50 leaf pages will be locked. The caller of xtTruncate + * will be responsible for ensuring that the current transaction gets + * committed, and that subsequent transactions are created to truncate + * the file further if needed. + */ +#define MAX_TRUNCATE_LEAVES 50 + +/* + * xtTruncate() + * + * function: + * traverse for truncation logging backward bottom up; + * terminate at the last extent entry at the current subtree + * root page covering new down size. + * truncation may occur within the last extent entry. + * + * parameter: + * int tid, + * struct inode *ip, + * s64 newsize, + * int type) {PWMAP, PMAP, WMAP; DELETE, TRUNCATE} + * + * return: + * + * note: + * PWMAP: + * 1. truncate (non-COMMIT_NOLINK file) + * by jfs_truncate() or jfs_open(O_TRUNC): + * xtree is updated; + * 2. truncate index table of directory when last entry removed + * map update via tlock at commit time; + * PMAP: + * Call xtTruncate_pmap instead + * WMAP: + * 1. remove (free zero link count) on last reference release + * (pmap has been freed at commit zero link count); + * 2. truncate (COMMIT_NOLINK file, i.e., tmp file): + * xtree is updated; + * map update directly at truncation time; + * + * if (DELETE) + * no LOG_NOREDOPAGE is required (NOREDOFILE is sufficient); + * else if (TRUNCATE) + * must write LOG_NOREDOPAGE for deleted index page; + * + * pages may already have been tlocked by anonymous transactions + * during file growth (i.e., write) before truncation; + * + * except last truncated entry, deleted entries remains as is + * in the page (nextindex is updated) for other use + * (e.g., log/update allocation map): this avoid copying the page + * info but delay free of pages; + * + */ +s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag) +{ + int rc = 0; + s64 teof; + metapage_t *mp; + xtpage_t *p; + s64 bn; + int index, nextindex; + xad_t *xad; + s64 xoff, xaddr; + int xlen, len, freexlen; + btstack_t btstack; + btframe_t *parent; + tblock_t *tblk = 0; + tlock_t *tlck = 0; + xtlock_t *xtlck = 0; + xdlistlock_t xadlock; /* maplock for COMMIT_WMAP */ + pxdlock_t *pxdlock; /* maplock for COMMIT_WMAP */ + s64 nfreed; + int freed, log; + int locked_leaves = 0; + + /* save object truncation type */ + if (tid) { + tblk = tid_to_tblock(tid); + tblk->xflag |= flag; + } + + nfreed = 0; + + flag &= COMMIT_MAP; + assert(flag != COMMIT_PMAP); + + if (flag == COMMIT_PWMAP) + log = 1; + else { + log = 0; + xadlock.flag = mlckFREEXADLIST; + xadlock.index = 1; + } + + /* + * if the newsize is not an integral number of pages, + * the file between newsize and next page boundary will + * be cleared. + * if truncating into a file hole, it will cause + * a full block to be allocated for the logical block. + */ + + /* + * release page blocks of truncated region + * + * free the data blocks from the leaf index blocks. + * delete the parent index entries corresponding to + * the freed child data/index blocks. + * free the index blocks themselves which aren't needed + * in new sized file. + * + * index blocks are updated only if the blocks are to be + * retained in the new sized file. + * if type is PMAP, the data and index pages are NOT + * freed, and the data and index blocks are NOT freed + * from working map. + * (this will allow continued access of data/index of + * temporary file (zerolink count file truncated to zero-length)). + */ + teof = (newsize + (JFS_SBI(ip->i_sb)->bsize - 1)) >> + JFS_SBI(ip->i_sb)->l2bsize; + + /* clear stack */ + BT_CLR(&btstack); + + /* + * start with root + * + * root resides in the inode + */ + bn = 0; + + /* + * first access of each page: + */ + getPage: + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return -rc; + + /* process entries backward from last index */ + index = le16_to_cpu(p->header.nextindex) - 1; + + if (p->header.flag & BT_INTERNAL) + goto getChild; + + /* + * leaf page + */ + + /* Since this is the rightmost leaf, and we may have already freed + * a page that was formerly to the right, let's make sure that the + * next pointer is zero. + */ + p->header.next = 0; + + freed = 0; + + /* does region covered by leaf page precede Teof ? */ + xad = &p->xad[index]; + xoff = offsetXAD(xad); + xlen = lengthXAD(xad); + if (teof >= xoff + xlen) { + XT_PUTPAGE(mp); + goto getParent; + } + + /* (re)acquire tlock of the leaf page */ + if (log) { + if (++locked_leaves > MAX_TRUNCATE_LEAVES) { + /* + * We need to limit the size of the transaction + * to avoid exhausting pagecache & tlocks + */ + XT_PUTPAGE(mp); + newsize = (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize; + goto getParent; + } + tlck = txLock(tid, ip, mp, tlckXTREE); + tlck->type = tlckXTREE | tlckTRUNCATE; + xtlck = (xtlock_t *) & tlck->lock; + xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1; + } + BT_MARK_DIRTY(mp, ip); + + /* + * scan backward leaf page entries + */ + for (; index >= XTENTRYSTART; index--) { + xad = &p->xad[index]; + xoff = offsetXAD(xad); + xlen = lengthXAD(xad); + xaddr = addressXAD(xad); + + /* + * entry beyond eof: continue scan of current page + * xad + * ---|---=======-------> + * eof + */ + if (teof < xoff) { + nfreed += xlen; + continue; + } + + /* + * (xoff <= teof): last entry to be deleted from page; + * If other entries remain in page: keep and update the page. + */ + + /* + * eof == entry_start: delete the entry + * xad + * -------|=======-------> + * eof + * + */ + if (teof == xoff) { + nfreed += xlen; + + if (index == XTENTRYSTART) + break; + + nextindex = index; + } + /* + * eof within the entry: truncate the entry. + * xad + * -------===|===-------> + * eof + */ + else if (teof < xoff + xlen) { + /* update truncated entry */ + len = teof - xoff; + freexlen = xlen - len; + XADlength(xad, len); + + /* save pxd of truncated extent in tlck */ + xaddr += len; + if (log) { /* COMMIT_PWMAP */ + xtlck->lwm.offset = (xtlck->lwm.offset) ? + min(index, (int)xtlck->lwm.offset) : index; + xtlck->lwm.length = index + 1 - + xtlck->lwm.offset; + xtlck->twm.offset = index; + pxdlock = (pxdlock_t *) & xtlck->pxdlock; + pxdlock->flag = mlckFREEPXD; + PXDaddress(&pxdlock->pxd, xaddr); + PXDlength(&pxdlock->pxd, freexlen); + } + /* free truncated extent */ + else { /* COMMIT_WMAP */ + + pxdlock = (pxdlock_t *) & xadlock; + pxdlock->flag = mlckFREEPXD; + PXDaddress(&pxdlock->pxd, xaddr); + PXDlength(&pxdlock->pxd, freexlen); + txFreeMap(ip, pxdlock, 0, COMMIT_WMAP); + + /* reset map lock */ + xadlock.flag = mlckFREEXADLIST; + } + + /* current entry is new last entry; */ + nextindex = index + 1; + + nfreed += freexlen; + } + /* + * eof beyond the entry: + * xad + * -------=======---|---> + * eof + */ + else { /* (xoff + xlen < teof) */ + + nextindex = index + 1; + } + + if (nextindex < le16_to_cpu(p->header.nextindex)) { + if (!log) { /* COMMIT_WAMP */ + xadlock.xdlist = &p->xad[nextindex]; + xadlock.count = + le16_to_cpu(p->header.nextindex) - + nextindex; + txFreeMap(ip, (maplock_t *) & xadlock, 0, + COMMIT_WMAP); + } + p->header.nextindex = cpu_to_le16(nextindex); + } + + XT_PUTPAGE(mp); + + /* assert(freed == 0); */ + goto getParent; + } /* end scan of leaf page entries */ + + freed = 1; + + /* + * leaf page become empty: free the page if type != PMAP + */ + if (log) { /* COMMIT_PWMAP */ + /* txCommit() with tlckFREE: + * free data extents covered by leaf [XTENTRYSTART:hwm); + * invalidate leaf if COMMIT_PWMAP; + * if (TRUNCATE), will write LOG_NOREDOPAGE; + */ + tlck->type = tlckXTREE | tlckFREE; + } else { /* COMMIT_WAMP */ + + /* free data extents covered by leaf */ + xadlock.xdlist = &p->xad[XTENTRYSTART]; + xadlock.count = + le16_to_cpu(p->header.nextindex) - XTENTRYSTART; + txFreeMap(ip, (maplock_t *) & xadlock, 0, COMMIT_WMAP); + } + + if (p->header.flag & BT_ROOT) { + p->header.flag &= ~BT_INTERNAL; + p->header.flag |= BT_LEAF; + p->header.nextindex = cpu_to_le16(XTENTRYSTART); + + XT_PUTPAGE(mp); /* debug */ + goto out; + } else { + if (log) { /* COMMIT_PWMAP */ + /* page will be invalidated at tx completion + */ + XT_PUTPAGE(mp); + } else { /* COMMIT_WMAP */ + + if (mp->lid) + lid_to_tlock(mp->lid)->flag |= tlckFREELOCK; + + /* invalidate empty leaf page */ + discard_metapage(mp); + } + } + + /* + * the leaf page become empty: delete the parent entry + * for the leaf page if the parent page is to be kept + * in the new sized file. + */ + + /* + * go back up to the parent page + */ + getParent: + /* pop/restore parent entry for the current child page */ + if ((parent = BT_POP(&btstack)) == NULL) + /* current page must have been root */ + goto out; + + /* get back the parent page */ + bn = parent->bn; + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return -rc; + + index = parent->index; + + /* + * child page was not empty: + */ + if (freed == 0) { + /* has any entry deleted from parent ? */ + if (index < le16_to_cpu(p->header.nextindex) - 1) { + /* (re)acquire tlock on the parent page */ + if (log) { /* COMMIT_PWMAP */ + /* txCommit() with tlckTRUNCATE: + * free child extents covered by parent [); + */ + tlck = txLock(tid, ip, mp, tlckXTREE); + xtlck = (xtlock_t *) & tlck->lock; + if (!(tlck->type & tlckTRUNCATE)) { + xtlck->hwm.offset = + le16_to_cpu(p->header. + nextindex) - 1; + tlck->type = + tlckXTREE | tlckTRUNCATE; + } + } else { /* COMMIT_WMAP */ + + /* free child extents covered by parent */ + xadlock.xdlist = &p->xad[index + 1]; + xadlock.count = + le16_to_cpu(p->header.nextindex) - + index - 1; + txFreeMap(ip, (maplock_t *) & xadlock, 0, + COMMIT_WMAP); + } + BT_MARK_DIRTY(mp, ip); + + p->header.nextindex = cpu_to_le16(index + 1); + } + XT_PUTPAGE(mp); + goto getParent; + } + + /* + * child page was empty: + */ + nfreed += lengthXAD(&p->xad[index]); + + /* + * During working map update, child page's tlock must be handled + * before parent's. This is because the parent's tlock will cause + * the child's disk space to be marked available in the wmap, so + * it's important that the child page be released by that time. + * + * ToDo: tlocks should be on doubly-linked list, so we can + * quickly remove it and add it to the end. + */ + + /* + * Move parent page's tlock to the end of the tid's tlock list + */ + if (log && mp->lid && (tblk->last != mp->lid) && + lid_to_tlock(mp->lid)->tid) { + lid_t lid = mp->lid; + tlock_t *prev; + + tlck = lid_to_tlock(lid); + + if (tblk->next == lid) + tblk->next = tlck->next; + else { + for (prev = lid_to_tlock(tblk->next); + prev->next != lid; + prev = lid_to_tlock(prev->next)) { + assert(prev->next); + } + prev->next = tlck->next; + } + lid_to_tlock(tblk->last)->next = lid; + tlck->next = 0; + tblk->last = lid; + } + + /* + * parent page become empty: free the page + */ + if (index == XTENTRYSTART) { + if (log) { /* COMMIT_PWMAP */ + /* txCommit() with tlckFREE: + * free child extents covered by parent; + * invalidate parent if COMMIT_PWMAP; + */ + tlck = txLock(tid, ip, mp, tlckXTREE); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->hwm.offset = + le16_to_cpu(p->header.nextindex) - 1; + tlck->type = tlckXTREE | tlckFREE; + } else { /* COMMIT_WMAP */ + + /* free child extents covered by parent */ + xadlock.xdlist = &p->xad[XTENTRYSTART]; + xadlock.count = + le16_to_cpu(p->header.nextindex) - + XTENTRYSTART; + txFreeMap(ip, (maplock_t *) & xadlock, 0, + COMMIT_WMAP); + } + BT_MARK_DIRTY(mp, ip); + + if (p->header.flag & BT_ROOT) { + p->header.flag &= ~BT_INTERNAL; + p->header.flag |= BT_LEAF; + p->header.nextindex = cpu_to_le16(XTENTRYSTART); + if (le16_to_cpu(p->header.maxentry) == XTROOTMAXSLOT) { + /* + * Shrink root down to allow inline + * EA (otherwise fsck complains) + */ + p->header.maxentry = + cpu_to_le16(XTROOTINITSLOT); + JFS_IP(ip)->mode2 |= INLINEEA; + } + + XT_PUTPAGE(mp); /* debug */ + goto out; + } else { + if (log) { /* COMMIT_PWMAP */ + /* page will be invalidated at tx completion + */ + XT_PUTPAGE(mp); + } else { /* COMMIT_WMAP */ + + if (mp->lid) + lid_to_tlock(mp->lid)->flag |= + tlckFREELOCK; + + /* invalidate parent page */ + discard_metapage(mp); + } + + /* parent has become empty and freed: + * go back up to its parent page + */ + /* freed = 1; */ + goto getParent; + } + } + /* + * parent page still has entries for front region; + */ + else { + /* try truncate region covered by preceding entry + * (process backward) + */ + index--; + + /* go back down to the child page corresponding + * to the entry + */ + goto getChild; + } + + /* + * internal page: go down to child page of current entry + */ + getChild: + /* save current parent entry for the child page */ + BT_PUSH(&btstack, bn, index); + + /* get child page */ + xad = &p->xad[index]; + bn = addressXAD(xad); + + /* + * first access of each internal entry: + */ + /* release parent page */ + XT_PUTPAGE(mp); + + /* process the child page */ + goto getPage; + + out: + /* + * update file resource stat + */ + /* set size + */ + if (S_ISDIR(ip->i_mode) && !newsize) + ip->i_size = 1; /* fsck hates zero-length directories */ + else + ip->i_size = newsize; + + /* update nblocks to reflect freed blocks */ + ip->i_blocks -= LBLK2PBLK(ip->i_sb, nfreed); + + /* + * free tlock of invalidated pages + */ + if (flag == COMMIT_WMAP) + txFreelock(ip); + + return newsize; +} + + +/* + * xtTruncate_pmap() + * + * function: + * Perform truncate to zero lenghth for deleted file, leaving the + * the xtree and working map untouched. This allows the file to + * be accessed via open file handles, while the delete of the file + * is committed to disk. + * + * parameter: + * tid_t tid, + * struct inode *ip, + * s64 committed_size) + * + * return: new committed size + * + * note: + * + * To avoid deadlock by holding too many transaction locks, the + * truncation may be broken up into multiple transactions. + * The committed_size keeps track of part of the file has been + * freed from the pmaps. + */ +s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size) +{ + s64 bn; + btstack_t btstack; + int cmp; + int index; + int locked_leaves = 0; + metapage_t *mp; + xtpage_t *p; + btframe_t *parent; + int rc; + tblock_t *tblk; + tlock_t *tlck = 0; + xad_t *xad; + int xlen; + s64 xoff; + xtlock_t *xtlck = 0; + + /* save object truncation type */ + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_PMAP; + + /* clear stack */ + BT_CLR(&btstack); + + if (committed_size) { + xoff = (committed_size >> JFS_SBI(ip->i_sb)->l2bsize) - 1; + rc = xtSearch(ip, xoff, &cmp, &btstack, 0); + if (rc) + return -rc; + assert(cmp == 0); + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + } else { + /* + * start with root + * + * root resides in the inode + */ + bn = 0; + + /* + * first access of each page: + */ + getPage: + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return -rc; + + /* process entries backward from last index */ + index = le16_to_cpu(p->header.nextindex) - 1; + + if (p->header.flag & BT_INTERNAL) + goto getChild; + } + + /* + * leaf page + */ + + if (++locked_leaves > MAX_TRUNCATE_LEAVES) { + /* + * We need to limit the size of the transaction + * to avoid exhausting pagecache & tlocks + */ + xad = &p->xad[index]; + xoff = offsetXAD(xad); + xlen = lengthXAD(xad); + XT_PUTPAGE(mp); + return (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize; + } + tlck = txLock(tid, ip, mp, tlckXTREE); + tlck->type = tlckXTREE | tlckFREE; + xtlck = (xtlock_t *) & tlck->lock; + xtlck->hwm.offset = index; + + + XT_PUTPAGE(mp); + + /* + * go back up to the parent page + */ + getParent: + /* pop/restore parent entry for the current child page */ + if ((parent = BT_POP(&btstack)) == NULL) + /* current page must have been root */ + goto out; + + /* get back the parent page */ + bn = parent->bn; + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return -rc; + + index = parent->index; + + /* + * parent page become empty: free the page + */ + if (index == XTENTRYSTART) { + /* txCommit() with tlckFREE: + * free child extents covered by parent; + * invalidate parent if COMMIT_PWMAP; + */ + tlck = txLock(tid, ip, mp, tlckXTREE); + xtlck = (xtlock_t *) & tlck->lock; + xtlck->hwm.offset = + le16_to_cpu(p->header.nextindex) - 1; + tlck->type = tlckXTREE | tlckFREE; + + XT_PUTPAGE(mp); + + if (p->header.flag & BT_ROOT) { + + goto out; + } else { + goto getParent; + } + } + /* + * parent page still has entries for front region; + */ + else + index--; + /* + * internal page: go down to child page of current entry + */ + getChild: + /* save current parent entry for the child page */ + BT_PUSH(&btstack, bn, index); + + /* get child page */ + xad = &p->xad[index]; + bn = addressXAD(xad); + + /* + * first access of each internal entry: + */ + /* release parent page */ + XT_PUTPAGE(mp); + + /* process the child page */ + goto getPage; + + out: + + return 0; +} + + +#ifdef _JFS_DEBUG_XTREE +/* + * xtDisplayTree() + * + * function: traverse forward + */ +int xtDisplayTree(struct inode *ip) +{ + int rc = 0; + metapage_t *mp; + xtpage_t *p; + s64 bn, pbn; + int index, lastindex, v, h; + xad_t *xad; + btstack_t btstack; + btframe_t *btsp; + btframe_t *parent; + + printk("display B+-tree.\n"); + + /* clear stack */ + btsp = btstack.stack; + + /* + * start with root + * + * root resides in the inode + */ + bn = 0; + v = h = 0; + + /* + * first access of each page: + */ + getPage: + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* process entries forward from first index */ + index = XTENTRYSTART; + lastindex = le16_to_cpu(p->header.nextindex) - 1; + + if (p->header.flag & BT_INTERNAL) { + /* + * first access of each internal page + */ + goto getChild; + } else { /* (p->header.flag & BT_LEAF) */ + + /* + * first access of each leaf page + */ + printf("leaf page "); + xtDisplayPage(ip, bn, p); + + /* unpin the leaf page */ + XT_PUTPAGE(mp); + } + + /* + * go back up to the parent page + */ + getParent: + /* pop/restore parent entry for the current child page */ + if ((parent = (btsp == btstack.stack ? NULL : --btsp)) == NULL) + /* current page must have been root */ + return; + + /* + * parent page scan completed + */ + if ((index = parent->index) == (lastindex = parent->lastindex)) { + /* go back up to the parent page */ + goto getParent; + } + + /* + * parent page has entries remaining + */ + /* get back the parent page */ + bn = parent->bn; + /* v = parent->level; */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* get next parent entry */ + index++; + + /* + * internal page: go down to child page of current entry + */ + getChild: + /* push/save current parent entry for the child page */ + btsp->bn = pbn = bn; + btsp->index = index; + btsp->lastindex = lastindex; + /* btsp->level = v; */ + /* btsp->node = h; */ + ++btsp; + + /* get child page */ + xad = &p->xad[index]; + bn = addressXAD(xad); + + /* + * first access of each internal entry: + */ + /* release parent page */ + XT_PUTPAGE(mp); + + printk("traverse down 0x%lx[%d]->0x%lx\n", (ulong) pbn, index, + (ulong) bn); + v++; + h = index; + + /* process the child page */ + goto getPage; +} + + +/* + * xtDisplayPage() + * + * function: display page + */ +int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p) +{ + int rc = 0; + metapage_t *mp; + xad_t *xad; + s64 xaddr, xoff; + int xlen, i, j; + + if (p == NULL) { + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + } + + /* display page control */ + printf("bn:0x%lx flag:0x%x nextindex:%d\n", + (ulong) bn, p->header.flag, + le16_to_cpu(p->header.nextindex)); + + /* display entries */ + xad = &p->xad[XTENTRYSTART]; + for (i = XTENTRYSTART, j = 1; i < le16_to_cpu(p->header.nextindex); + i++, xad++, j++) { + xoff = offsetXAD(xad); + xaddr = addressXAD(xad); + xlen = lengthXAD(xad); + printf("\t[%d] 0x%lx:0x%lx(0x%x)", i, (ulong) xoff, + (ulong) xaddr, xlen); + + if (j == 4) { + printf("\n"); + j = 0; + } + } + + printf("\n"); +} +#endif /* _JFS_DEBUG_XTREE */ + + +#ifdef _JFS_WIP +/* + * xtGather() + * + * function: + * traverse for allocation acquiring tlock at commit time + * (vs at the time of update) logging backward top down + * + * note: + * problem - establishing that all new allocation have been + * processed both for append and random write in sparse file + * at the current entry at the current subtree root page + * + */ +int xtGather(t) +btree_t *t; +{ + int rc = 0; + xtpage_t *p; + u64 bn; + int index; + btentry_t *e; + btstack_t btstack; + struct btsf *parent; + + /* clear stack */ + BT_CLR(&btstack); + + /* + * start with root + * + * root resides in the inode + */ + bn = 0; + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* new root is NOT pointed by a new entry + if (p->header.flag & NEW) + allocate new page lock; + write a NEWPAGE log; + */ + + dopage: + /* + * first access of each page: + */ + /* process entries backward from last index */ + index = le16_to_cpu(p->header.nextindex) - 1; + + if (p->header.flag & BT_LEAF) { + /* + * first access of each leaf page + */ + /* process leaf page entries backward */ + for (; index >= XTENTRYSTART; index--) { + e = &p->xad[index]; + /* + * if newpage, log NEWPAGE. + * + if (e->flag & XAD_NEW) { + nfound =+ entry->length; + update current page lock for the entry; + newpage(entry); + * + * if moved, log move. + * + } else if (e->flag & XAD_MOVED) { + reset flag; + update current page lock for the entry; + } + */ + } + + /* unpin the leaf page */ + XT_PUTPAGE(mp); + + /* + * go back up to the parent page + */ + getParent: + /* restore parent entry for the current child page */ + if ((parent = BT_POP(&btstack)) == NULL) + /* current page must have been root */ + return 0; + + if ((index = parent->index) == XTENTRYSTART) { + /* + * parent page scan completed + */ + /* go back up to the parent page */ + goto getParent; + } else { + /* + * parent page has entries remaining + */ + /* get back the parent page */ + bn = parent->bn; + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return EIO; + + /* first subroot page which + * covers all new allocated blocks + * itself not new/modified. + * (if modified from split of descendent, + * go down path of split page) + + if (nfound == nnew && + !(p->header.flag & (NEW | MOD))) + exit scan; + */ + + /* process parent page entries backward */ + index--; + } + } else { + /* + * first access of each internal page + */ + } + + /* + * internal page: go down to child page of current entry + */ + + /* save current parent entry for the child page */ + BT_PUSH(&btstack, bn, index); + + /* get current entry for the child page */ + e = &p->xad[index]; + + /* + * first access of each internal entry: + */ + /* + * if new entry, log btree_tnewentry. + * + if (e->flag & XAD_NEW) + update parent page lock for the entry; + */ + + /* release parent page */ + XT_PUTPAGE(mp); + + /* get child page */ + bn = e->bn; + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + /* + * first access of each non-root page: + */ + /* + * if new, log btree_newpage. + * + if (p->header.flag & NEW) + allocate new page lock; + write a NEWPAGE log (next, prev); + */ + + /* process the child page */ + goto dopage; + + out: + return 0; +} +#endif /* _JFS_WIP */ + + +#ifdef CONFIG_JFS_STATISTICS +int jfs_xtstat_read(char *buffer, char **start, off_t offset, int length, + int *eof, void *data) +{ + int len = 0; + off_t begin; + + len += sprintf(buffer, + "JFS Xtree statistics\n" + "====================\n" + "searches = %d\n" + "fast searches = %d\n" + "splits = %d\n", + xtStat.search, + xtStat.fastSearch, + xtStat.split); + + begin = offset; + *start = buffer + begin; + len -= begin; + + if (len > length) + len = length; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/jfs_xtree.h linux.20pre2-ac1/fs/jfs/jfs_xtree.h --- linux.20pre2/fs/jfs/jfs_xtree.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/jfs_xtree.h 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,138 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 _H_JFS_XTREE +#define _H_JFS_XTREE + +/* + * jfs_xtree.h: extent allocation descriptor B+-tree manager + */ + +#include "jfs_btree.h" + + +/* + * extent allocation descriptor (xad) + */ +typedef struct xad { + unsigned flag:8; /* 1: flag */ + unsigned rsvrd:16; /* 2: reserved */ + unsigned off1:8; /* 1: offset in unit of fsblksize */ + u32 off2; /* 4: offset in unit of fsblksize */ + unsigned len:24; /* 3: length in unit of fsblksize */ + unsigned addr1:8; /* 1: address in unit of fsblksize */ + u32 addr2; /* 4: address in unit of fsblksize */ +} xad_t; /* (16) */ + +#define MAXXLEN ((1 << 24) - 1) + +#define XTSLOTSIZE 16 +#define L2XTSLOTSIZE 4 + +/* xad_t field construction */ +#define XADoffset(xad, offset64)\ +{\ + (xad)->off1 = ((u64)offset64) >> 32;\ + (xad)->off2 = __cpu_to_le32((offset64) & 0xffffffff);\ +} +#define XADaddress(xad, address64)\ +{\ + (xad)->addr1 = ((u64)address64) >> 32;\ + (xad)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\ +} +#define XADlength(xad, length32) (xad)->len = __cpu_to_le24(length32) + +/* xad_t field extraction */ +#define offsetXAD(xad)\ + ( ((s64)((xad)->off1)) << 32 | __le32_to_cpu((xad)->off2)) +#define addressXAD(xad)\ + ( ((s64)((xad)->addr1)) << 32 | __le32_to_cpu((xad)->addr2)) +#define lengthXAD(xad) __le24_to_cpu((xad)->len) + +/* xad list */ +typedef struct { + s16 maxnxad; + s16 nxad; + xad_t *xad; +} xadlist_t; + +/* xad_t flags */ +#define XAD_NEW 0x01 /* new */ +#define XAD_EXTENDED 0x02 /* extended */ +#define XAD_COMPRESSED 0x04 /* compressed with recorded length */ +#define XAD_NOTRECORDED 0x08 /* allocated but not recorded */ +#define XAD_COW 0x10 /* copy-on-write */ + + +/* possible values for maxentry */ +#define XTROOTINITSLOT_DIR 6 +#define XTROOTINITSLOT 10 +#define XTROOTMAXSLOT 18 +#define XTPAGEMAXSLOT 256 +#define XTENTRYSTART 2 + +/* + * xtree page: + */ +typedef union { + struct xtheader { + s64 next; /* 8: */ + s64 prev; /* 8: */ + + u8 flag; /* 1: */ + u8 rsrvd1; /* 1: */ + s16 nextindex; /* 2: next index = number of entries */ + s16 maxentry; /* 2: max number of entries */ + s16 rsrvd2; /* 2: */ + + pxd_t self; /* 8: self */ + } header; /* (32) */ + + xad_t xad[XTROOTMAXSLOT]; /* 16 * maxentry: xad array */ +} xtpage_t; + +/* + * external declaration + */ +extern int xtLookup(struct inode *ip, s64 lstart, s64 llen, + int *pflag, s64 * paddr, int *plen, int flag); +extern int xtLookupList(struct inode *ip, lxdlist_t * lxdlist, + xadlist_t * xadlist, int flag); +extern void xtInitRoot(tid_t tid, struct inode *ip); +extern int xtInsert(tid_t tid, struct inode *ip, + int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag); +extern int xtExtend(tid_t tid, struct inode *ip, s64 xoff, int xlen, + int flag); +extern int xtTailgate(tid_t tid, struct inode *ip, + s64 xoff, int xlen, s64 xaddr, int flag); +extern int xtUpdate(tid_t tid, struct inode *ip, struct xad *nxad); +extern int xtDelete(tid_t tid, struct inode *ip, s64 xoff, int xlen, + int flag); +extern s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int type); +extern s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size); +extern int xtRelocate(tid_t tid, struct inode *ip, + xad_t * oxad, s64 nxaddr, int xtype); +extern int xtAppend(tid_t tid, + struct inode *ip, int xflag, s64 xoff, int maxblocks, + int *xlenp, s64 * xaddrp, int flag); + +#ifdef _JFS_DEBUG_XTREE +extern int xtDisplayTree(struct inode *ip); +extern int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p); +#endif /* _JFS_DEBUG_XTREE */ + +#endif /* !_H_JFS_XTREE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/Makefile linux.20pre2-ac1/fs/jfs/Makefile --- linux.20pre2/fs/jfs/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/Makefile 2002-08-06 18:01:05.000000000 +0100 @@ -0,0 +1,15 @@ +# +# Makefile for the Linux JFS filesystem routines. +# + +O_TARGET := jfs.o +obj-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ + jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ + jfs_unicode.o jfs_dtree.o jfs_inode.o \ + jfs_extent.o symlink.o jfs_metapage.o \ + jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o resize.o +obj-m := $(O_TARGET) + +EXTRA_CFLAGS += -D_JFS_4K + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/namei.c linux.20pre2-ac1/fs/jfs/namei.c --- linux.20pre2/fs/jfs/namei.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/namei.c 2002-08-06 17:59:43.000000000 +0100 @@ -0,0 +1,1441 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 "jfs_incore.h" +#include "jfs_inode.h" +#include "jfs_dinode.h" +#include "jfs_dmap.h" +#include "jfs_unicode.h" +#include "jfs_metapage.h" +#include "jfs_debug.h" + +extern struct inode_operations jfs_file_inode_operations; +extern struct inode_operations jfs_symlink_inode_operations; +extern struct file_operations jfs_file_operations; +extern struct address_space_operations jfs_aops; + +extern int jfs_fsync(struct file *, struct dentry *, int); +extern void jfs_truncate_nolock(struct inode *, loff_t); + +/* + * forward references + */ +struct inode_operations jfs_dir_inode_operations; +struct file_operations jfs_dir_operations; + +s64 commitZeroLink(tid_t, struct inode *); + +/* + * NAME: jfs_create(dip, dentry, mode) + * + * FUNCTION: create a regular file in the parent directory + * with name = and mode = + * + * PARAMETER: dip - parent directory vnode + * dentry - dentry of new file + * mode - create mode (rwxrwxrwx). + * + * RETURN: Errors from subroutines + * + */ +int jfs_create(struct inode *dip, struct dentry *dentry, int mode) +{ + int rc = 0; + tid_t tid; /* transaction id */ + struct inode *ip = NULL; /* child directory inode */ + ino_t ino; + component_t dname; /* child directory name */ + btstack_t btstack; + struct inode *iplist[2]; + tblock_t *tblk; + + jFYI(1, ("jfs_create: dip:0x%p name:%s\n", dip, dentry->d_name.name)); + + /* + * search parent directory for entry/freespace + * (dtSearch() returns parent directory page pinned) + */ + if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) + goto out1; + + /* + * Either iAlloc() or txBegin() may block. Deadlock can occur if we + * block there while holding dtree page, so we allocate the inode & + * begin the transaction before we search the directory. + */ + ip = ialloc(dip, mode); + if (ip == NULL) { + rc = ENOSPC; + goto out2; + } + + tid = txBegin(dip->i_sb, 0); + + down(&JFS_IP(dip)->commit_sem); + down(&JFS_IP(ip)->commit_sem); + + if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { + jERROR(1, ("jfs_create: dtSearch returned %d\n", rc)); + goto out3; + } + + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_CREATE; + tblk->ip = ip; + + iplist[0] = dip; + iplist[1] = ip; + + /* + * initialize the child XAD tree root in-line in inode + */ + xtInitRoot(tid, ip); + + /* + * create entry in parent directory for child directory + * (dtInsert() releases parent directory page) + */ + ino = ip->i_ino; + if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { + jERROR(1, ("jfs_create: dtInsert returned %d\n", rc)); + if (rc == EIO) + txAbort(tid, 1); /* Marks Filesystem dirty */ + else + txAbort(tid, 0); /* Filesystem full */ + goto out3; + } + + ip->i_op = &jfs_file_inode_operations; + ip->i_fop = &jfs_file_operations; + ip->i_mapping->a_ops = &jfs_aops; + + insert_inode_hash(ip); + mark_inode_dirty(ip); + d_instantiate(dentry, ip); + + dip->i_ctime = dip->i_mtime = CURRENT_TIME; + + mark_inode_dirty(dip); + + rc = txCommit(tid, 2, &iplist[0], 0); + + out3: + txEnd(tid); + up(&JFS_IP(dip)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + if (rc) { + ip->i_nlink = 0; + iput(ip); + } + + out2: + free_UCSname(&dname); + + out1: + + jFYI(1, ("jfs_create: rc:%d\n", -rc)); + return -rc; +} + + +/* + * NAME: jfs_mkdir(dip, dentry, mode) + * + * FUNCTION: create a child directory in the parent directory + * with name = and mode = + * + * PARAMETER: dip - parent directory vnode + * dentry - dentry of child directory + * mode - create mode (rwxrwxrwx). + * + * RETURN: Errors from subroutines + * + * note: + * EACCESS: user needs search+write permission on the parent directory + */ +int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) +{ + int rc = 0; + tid_t tid; /* transaction id */ + struct inode *ip = NULL; /* child directory inode */ + ino_t ino; + component_t dname; /* child directory name */ + btstack_t btstack; + struct inode *iplist[2]; + tblock_t *tblk; + + jFYI(1, ("jfs_mkdir: dip:0x%p name:%s\n", dip, dentry->d_name.name)); + + /* link count overflow on parent directory ? */ + if (dip->i_nlink == JFS_LINK_MAX) { + rc = EMLINK; + goto out1; + } + + /* + * search parent directory for entry/freespace + * (dtSearch() returns parent directory page pinned) + */ + if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) + goto out1; + + /* + * Either iAlloc() or txBegin() may block. Deadlock can occur if we + * block there while holding dtree page, so we allocate the inode & + * begin the transaction before we search the directory. + */ + ip = ialloc(dip, S_IFDIR | mode); + if (ip == NULL) { + rc = ENOSPC; + goto out2; + } + + tid = txBegin(dip->i_sb, 0); + + down(&JFS_IP(dip)->commit_sem); + down(&JFS_IP(ip)->commit_sem); + + if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { + jERROR(1, ("jfs_mkdir: dtSearch returned %d\n", rc)); + goto out3; + } + + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_CREATE; + tblk->ip = ip; + + iplist[0] = dip; + iplist[1] = ip; + + /* + * initialize the child directory in-line in inode + */ + dtInitRoot(tid, ip, dip->i_ino); + + /* + * create entry in parent directory for child directory + * (dtInsert() releases parent directory page) + */ + ino = ip->i_ino; + if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { + jERROR(1, ("jfs_mkdir: dtInsert returned %d\n", rc)); + + if (rc == EIO) + txAbort(tid, 1); /* Marks Filesystem dirty */ + else + txAbort(tid, 0); /* Filesystem full */ + goto out3; + } + + ip->i_nlink = 2; /* for '.' */ + ip->i_op = &jfs_dir_inode_operations; + ip->i_fop = &jfs_dir_operations; + ip->i_mapping->a_ops = &jfs_aops; + ip->i_mapping->gfp_mask = GFP_NOFS; + + insert_inode_hash(ip); + mark_inode_dirty(ip); + d_instantiate(dentry, ip); + + /* update parent directory inode */ + dip->i_nlink++; /* for '..' from child directory */ + dip->i_ctime = dip->i_mtime = CURRENT_TIME; + mark_inode_dirty(dip); + + rc = txCommit(tid, 2, &iplist[0], 0); + + out3: + txEnd(tid); + up(&JFS_IP(dip)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + if (rc) { + ip->i_nlink = 0; + iput(ip); + } + + out2: + free_UCSname(&dname); + + out1: + + jFYI(1, ("jfs_mkdir: rc:%d\n", -rc)); + return -rc; +} + +/* + * NAME: jfs_rmdir(dip, dentry) + * + * FUNCTION: remove a link to child directory + * + * PARAMETER: dip - parent inode + * dentry - child directory dentry + * + * RETURN: EINVAL - if name is . or .. + * EINVAL - if . or .. exist but are invalid. + * errors from subroutines + * + * note: + * if other threads have the directory open when the last link + * is removed, the "." and ".." entries, if present, are removed before + * rmdir() returns and no new entries may be created in the directory, + * but the directory is not removed until the last reference to + * the directory is released (cf.unlink() of regular file). + */ +int jfs_rmdir(struct inode *dip, struct dentry *dentry) +{ + int rc; + tid_t tid; /* transaction id */ + struct inode *ip = dentry->d_inode; + ino_t ino; + component_t dname; + struct inode *iplist[2]; + tblock_t *tblk; + + jFYI(1, ("jfs_rmdir: dip:0x%p name:%s\n", dip, dentry->d_name.name)); + + /* directory must be empty to be removed */ + if (!dtEmpty(ip)) { + rc = ENOTEMPTY; + goto out; + } + + if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) { + goto out; + } + + tid = txBegin(dip->i_sb, 0); + + down(&JFS_IP(dip)->commit_sem); + down(&JFS_IP(ip)->commit_sem); + + iplist[0] = dip; + iplist[1] = ip; + + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_DELETE; + tblk->ip = ip; + + /* + * delete the entry of target directory from parent directory + */ + ino = ip->i_ino; + if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) { + jERROR(1, ("jfs_rmdir: dtDelete returned %d\n", rc)); + if (rc == EIO) + txAbort(tid, 1); + txEnd(tid); + up(&JFS_IP(dip)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + + goto out2; + } + + /* update parent directory's link count corresponding + * to ".." entry of the target directory deleted + */ + dip->i_nlink--; + dip->i_ctime = dip->i_mtime = CURRENT_TIME; + mark_inode_dirty(dip); + + /* + * OS/2 could have created EA and/or ACL + */ + /* free EA from both persistent and working map */ + if (JFS_IP(ip)->ea.flag & DXD_EXTENT) { + /* free EA pages */ + txEA(tid, ip, &JFS_IP(ip)->ea, NULL); + } + JFS_IP(ip)->ea.flag = 0; + + /* free ACL from both persistent and working map */ + if (JFS_IP(ip)->acl.flag & DXD_EXTENT) { + /* free ACL pages */ + txEA(tid, ip, &JFS_IP(ip)->acl, NULL); + } + JFS_IP(ip)->acl.flag = 0; + + /* mark the target directory as deleted */ + ip->i_nlink = 0; + mark_inode_dirty(ip); + + rc = txCommit(tid, 2, &iplist[0], 0); + + txEnd(tid); + + up(&JFS_IP(dip)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + + /* + * Truncating the directory index table is not guaranteed. It + * may need to be done iteratively + */ + if (test_cflag(COMMIT_Stale, dip)) { + if (dip->i_size > 1) + jfs_truncate_nolock(dip, 0); + + clear_cflag(COMMIT_Stale, dip); + } + + d_delete(dentry); + + out2: + free_UCSname(&dname); + + out: + jFYI(1, ("jfs_rmdir: rc:%d\n", rc)); + return -rc; +} + +/* + * NAME: jfs_unlink(dip, dentry) + * + * FUNCTION: remove a link to object named by + * from parent directory + * + * PARAMETER: dip - inode of parent directory + * dentry - dentry of object to be removed + * + * RETURN: errors from subroutines + * + * note: + * temporary file: if one or more processes have the file open + * when the last link is removed, the link will be removed before + * unlink() returns, but the removal of the file contents will be + * postponed until all references to the files are closed. + * + * JFS does NOT support unlink() on directories. + * + */ +int jfs_unlink(struct inode *dip, struct dentry *dentry) +{ + int rc; + tid_t tid; /* transaction id */ + struct inode *ip = dentry->d_inode; + ino_t ino; + component_t dname; /* object name */ + struct inode *iplist[2]; + tblock_t *tblk; + s64 new_size = 0; + int commit_flag; + + jFYI(1, ("jfs_unlink: dip:0x%p name:%s\n", dip, dentry->d_name.name)); + + if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) + goto out; + + IWRITE_LOCK(ip); + + tid = txBegin(dip->i_sb, 0); + + down(&JFS_IP(dip)->commit_sem); + down(&JFS_IP(ip)->commit_sem); + + iplist[0] = dip; + iplist[1] = ip; + + /* + * delete the entry of target file from parent directory + */ + ino = ip->i_ino; + if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) { + jERROR(1, ("jfs_unlink: dtDelete returned %d\n", rc)); + if (rc == EIO) + txAbort(tid, 1); /* Marks FS Dirty */ + txEnd(tid); + up(&JFS_IP(dip)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + IWRITE_UNLOCK(ip); + goto out1; + } + + ASSERT(ip->i_nlink); + + ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME; + mark_inode_dirty(dip); + + /* update target's inode */ + ip->i_nlink--; + mark_inode_dirty(ip); + + /* + * commit zero link count object + */ + if (ip->i_nlink == 0) { + assert(!test_cflag(COMMIT_Nolink, ip)); + /* free block resources */ + if ((new_size = commitZeroLink(tid, ip)) < 0) { + txAbort(tid, 1); /* Marks FS Dirty */ + txEnd(tid); + up(&JFS_IP(dip)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + IWRITE_UNLOCK(ip); + rc = -new_size; /* We return -rc */ + goto out1; + } + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_DELETE; + tblk->ip = ip; + } + + /* + * Incomplete truncate of file data can + * result in timing problems unless we synchronously commit the + * transaction. + */ + if (new_size) + commit_flag = COMMIT_SYNC; + else + commit_flag = 0; + + /* + * If xtTruncate was incomplete, commit synchronously to avoid + * timing complications + */ + rc = txCommit(tid, 2, &iplist[0], commit_flag); + + txEnd(tid); + + up(&JFS_IP(dip)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + + + while (new_size && (rc == 0)) { + tid = txBegin(dip->i_sb, 0); + down(&JFS_IP(ip)->commit_sem); + new_size = xtTruncate_pmap(tid, ip, new_size); + if (new_size < 0) { + txAbort(tid, 1); /* Marks FS Dirty */ + rc = -new_size; /* We return -rc */ + } else + rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC); + txEnd(tid); + up(&JFS_IP(ip)->commit_sem); + } + + if (ip->i_nlink == 0) + set_cflag(COMMIT_Nolink, ip); + + if (!test_cflag(COMMIT_Holdlock, ip)) + IWRITE_UNLOCK(ip); + + /* + * Truncating the directory index table is not guaranteed. It + * may need to be done iteratively + */ + if (test_cflag(COMMIT_Stale, dip)) { + if (dip->i_size > 1) + jfs_truncate_nolock(dip, 0); + + clear_cflag(COMMIT_Stale, dip); + } + + d_delete(dentry); + + out1: + free_UCSname(&dname); + out: + jFYI(1, ("jfs_unlink: rc:%d\n", -rc)); + return -rc; +} + +/* + * NAME: commitZeroLink() + * + * FUNCTION: for non-directory, called by jfs_remove(), + * truncate a regular file, directory or symbolic + * link to zero length. return 0 if type is not + * one of these. + * + * if the file is currently associated with a VM segment + * only permanent disk and inode map resources are freed, + * and neither the inode nor indirect blocks are modified + * so that the resources can be later freed in the work + * map by ctrunc1. + * if there is no VM segment on entry, the resources are + * freed in both work and permanent map. + * (? for temporary file - memory object is cached even + * after no reference: + * reference count > 0 - ) + * + * PARAMETERS: cd - pointer to commit data structure. + * current inode is the one to truncate. + * + * RETURN : Errors from subroutines + */ +s64 commitZeroLink(tid_t tid, struct inode *ip) +{ + int filetype; + tblock_t *tblk; + + jFYI(1, ("commitZeroLink: tid = %d, ip = 0x%p\n", tid, ip)); + + filetype = ip->i_mode & S_IFMT; + switch (filetype) { + case S_IFREG: + break; + case S_IFLNK: + /* fast symbolic link */ + if (ip->i_size <= 256) { + ip->i_size = 0; + return 0; + } + break; + default: + assert(filetype != S_IFDIR); + return 0; + } + + set_cflag(COMMIT_Freewmap, ip); + + /* mark transaction of block map update type */ + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_PMAP; + + /* + * free EA + */ + if (JFS_IP(ip)->ea.flag & DXD_EXTENT) + /* acquire maplock on EA to be freed from block map */ + txEA(tid, ip, &JFS_IP(ip)->ea, NULL); + + /* + * free ACL + */ + if (JFS_IP(ip)->acl.flag & DXD_EXTENT) + /* acquire maplock on EA to be freed from block map */ + txEA(tid, ip, &JFS_IP(ip)->acl, NULL); + + /* + * free xtree/data (truncate to zero length): + * free xtree/data pages from cache if COMMIT_PWMAP, + * free xtree/data blocks from persistent block map, and + * free xtree/data blocks from working block map if COMMIT_PWMAP; + */ + if (ip->i_size) + return xtTruncate_pmap(tid, ip, 0); + + return 0; +} + + +/* + * NAME: freeZeroLink() + * + * FUNCTION: for non-directory, called by iClose(), + * free resources of a file from cache and WORKING map + * for a file previously committed with zero link count + * while associated with a pager object, + * + * PARAMETER: ip - pointer to inode of file. + * + * RETURN: 0 -ok + */ +int freeZeroLink(struct inode *ip) +{ + int rc = 0; + int type; + + jFYI(1, ("freeZeroLink: ip = 0x%p\n", ip)); + + /* return if not reg or symbolic link or if size is + * already ok. + */ + type = ip->i_mode & S_IFMT; + + switch (type) { + case S_IFREG: + break; + case S_IFLNK: + /* if its contained in inode nothing to do */ + if (ip->i_size <= 256) + return 0; + break; + default: + return 0; + } + + /* + * free EA + */ + if (JFS_IP(ip)->ea.flag & DXD_EXTENT) { + s64 xaddr; + int xlen; + maplock_t maplock; /* maplock for COMMIT_WMAP */ + pxdlock_t *pxdlock; /* maplock for COMMIT_WMAP */ + + /* free EA pages from cache */ + xaddr = addressDXD(&JFS_IP(ip)->ea); + xlen = lengthDXD(&JFS_IP(ip)->ea); +#ifdef _STILL_TO_PORT + bmExtentInvalidate(ip, xaddr, xlen); +#endif + + /* free EA extent from working block map */ + maplock.index = 1; + pxdlock = (pxdlock_t *) & maplock; + pxdlock->flag = mlckFREEPXD; + PXDaddress(&pxdlock->pxd, xaddr); + PXDlength(&pxdlock->pxd, xlen); + txFreeMap(ip, pxdlock, 0, COMMIT_WMAP); + } + + /* + * free ACL + */ + if (JFS_IP(ip)->acl.flag & DXD_EXTENT) { + s64 xaddr; + int xlen; + maplock_t maplock; /* maplock for COMMIT_WMAP */ + pxdlock_t *pxdlock; /* maplock for COMMIT_WMAP */ + + /* free ACL pages from cache */ + xaddr = addressDXD(&JFS_IP(ip)->acl); + xlen = lengthDXD(&JFS_IP(ip)->acl); +#ifdef _STILL_TO_PORT + bmExtentInvalidate(ip, xaddr, xlen); +#endif + + /* free ACL extent from working block map */ + maplock.index = 1; + pxdlock = (pxdlock_t *) & maplock; + pxdlock->flag = mlckFREEPXD; + PXDaddress(&pxdlock->pxd, xaddr); + PXDlength(&pxdlock->pxd, xlen); + txFreeMap(ip, pxdlock, 0, COMMIT_WMAP); + } + + /* + * free xtree/data (truncate to zero length): + * free xtree/data pages from cache, and + * free xtree/data blocks from working block map; + */ + if (ip->i_size) + rc = xtTruncate(0, ip, 0, COMMIT_WMAP); + + return rc; +} + +/* + * NAME: jfs_link(vp, dvp, name, crp) + * + * FUNCTION: create a link to by the name = + * in the parent directory + * + * PARAMETER: vp - target object + * dvp - parent directory of new link + * name - name of new link to target object + * crp - credential + * + * RETURN: Errors from subroutines + * + * note: + * JFS does NOT support link() on directories (to prevent circular + * path in the directory hierarchy); + * EPERM: the target object is a directory, and either the caller + * does not have appropriate privileges or the implementation prohibits + * using link() on directories [XPG4.2]. + * + * JFS does NOT support links between file systems: + * EXDEV: target object and new link are on different file systems and + * implementation does not support links between file systems [XPG4.2]. + */ +int jfs_link(struct dentry *old_dentry, + struct inode *dir, struct dentry *dentry) +{ + int rc; + tid_t tid; + struct inode *ip = old_dentry->d_inode; + ino_t ino; + component_t dname; + btstack_t btstack; + struct inode *iplist[2]; + + jFYI(1, + ("jfs_link: %s %s\n", old_dentry->d_name.name, + dentry->d_name.name)); + + /* JFS does NOT support link() on directories */ + if (S_ISDIR(ip->i_mode)) + return -EPERM; + + tid = txBegin(ip->i_sb, 0); + + down(&JFS_IP(dir)->commit_sem); + down(&JFS_IP(ip)->commit_sem); + + if (ip->i_nlink == JFS_LINK_MAX) { + rc = EMLINK; + goto out; + } + + /* + * scan parent directory for entry/freespace + */ + if ((rc = get_UCSname(&dname, dentry, JFS_SBI(ip->i_sb)->nls_tab))) + goto out; + + if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) + goto out; + + /* + * create entry for new link in parent directory + */ + ino = ip->i_ino; + if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) + goto out; + + /* update object inode */ + ip->i_nlink++; /* for new link */ + ip->i_ctime = CURRENT_TIME; + mark_inode_dirty(dir); + atomic_inc(&ip->i_count); + d_instantiate(dentry, ip); + + iplist[0] = ip; + iplist[1] = dir; + rc = txCommit(tid, 2, &iplist[0], 0); + + out: + txEnd(tid); + + up(&JFS_IP(dir)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + + jFYI(1, ("jfs_link: rc:%d\n", rc)); + return -rc; +} + +/* + * NAME: jfs_symlink(dip, dentry, name) + * + * FUNCTION: creates a symbolic link to by name + * in directory + * + * PARAMETER: dip - parent directory vnode + * dentry - dentry of symbolic link + * name - the path name of the existing object + * that will be the source of the link + * + * RETURN: errors from subroutines + * + * note: + * ENAMETOOLONG: pathname resolution of a symbolic link produced + * an intermediate result whose length exceeds PATH_MAX [XPG4.2] +*/ + +int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) +{ + int rc; + tid_t tid; + ino_t ino = 0; + component_t dname; + int ssize; /* source pathname size */ + btstack_t btstack; + struct inode *ip = dentry->d_inode; + unchar *i_fastsymlink; + s64 xlen = 0; + int bmask = 0, xsize; + s64 xaddr; + metapage_t *mp; + struct super_block *sb; + tblock_t *tblk; + + struct inode *iplist[2]; + + jFYI(1, ("jfs_symlink: dip:0x%p name:%s\n", dip, name)); + + ssize = strlen(name) + 1; + + /* + * search parent directory for entry/freespace + * (dtSearch() returns parent directory page pinned) + */ + + if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) + goto out1; + + /* + * allocate on-disk/in-memory inode for symbolic link: + * (iAlloc() returns new, locked inode) + */ + ip = ialloc(dip, S_IFLNK | 0777); + if (ip == NULL) { + rc = ENOSPC; + goto out2; + } + + tid = txBegin(dip->i_sb, 0); + + down(&JFS_IP(dip)->commit_sem); + down(&JFS_IP(ip)->commit_sem); + + if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) + goto out3; + + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_CREATE; + tblk->ip = ip; + + /* + * create entry for symbolic link in parent directory + */ + + ino = ip->i_ino; + + + + if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) { + jERROR(1, ("jfs_symlink: dtInsert returned %d\n", rc)); + /* discard ne inode */ + goto out3; + + } + + /* fix symlink access permission + * (dir_create() ANDs in the u.u_cmask, + * but symlinks really need to be 777 access) + */ + ip->i_mode |= 0777; + + /* + * write symbolic link target path name + */ + xtInitRoot(tid, ip); + + /* + * write source path name inline in on-disk inode (fast symbolic link) + */ + + if (ssize <= IDATASIZE) { + ip->i_op = &jfs_symlink_inode_operations; + + i_fastsymlink = JFS_IP(ip)->i_inline; + memcpy(i_fastsymlink, name, ssize); + ip->i_size = ssize - 1; + jFYI(1, + ("jfs_symlink: fast symlink added ssize:%d name:%s \n", + ssize, name)); + } + /* + * write source path name in a single extent + */ + else { + jFYI(1, ("jfs_symlink: allocate extent ip:0x%p\n", ip)); + + ip->i_op = &page_symlink_inode_operations; + ip->i_mapping->a_ops = &jfs_aops; + + /* + * even though the data of symlink object (source + * path name) is treated as non-journaled user data, + * it is read/written thru buffer cache for performance. + */ + sb = ip->i_sb; + bmask = JFS_SBI(sb)->bsize - 1; + xsize = (ssize + bmask) & ~bmask; + xaddr = 0; + xlen = xsize >> JFS_SBI(sb)->l2bsize; + if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0)) == 0) { + ip->i_size = ssize - 1; + while (ssize) { + int copy_size = min(ssize, PSIZE); + + mp = get_metapage(ip, xaddr, PSIZE, 1); + + if (mp == NULL) { + dtDelete(tid, dip, &dname, &ino, + JFS_REMOVE); + rc = EIO; + goto out3; + } + memcpy(mp->data, name, copy_size); + flush_metapage(mp); +#if 0 + mark_buffer_uptodate(bp, 1); + mark_buffer_dirty(bp, 1); + if (IS_SYNC(dip)) { + ll_rw_block(WRITE, 1, &bp); + wait_on_buffer(bp); + } + brelse(bp); +#endif /* 0 */ + ssize -= copy_size; + xaddr += JFS_SBI(sb)->nbperpage; + } + ip->i_blocks = LBLK2PBLK(sb, xlen); + } else { + dtDelete(tid, dip, &dname, &ino, JFS_REMOVE); + rc = ENOSPC; + goto out3; + } + } + + insert_inode_hash(ip); + mark_inode_dirty(ip); + d_instantiate(dentry, ip); + + /* + * commit update of parent directory and link object + * + * if extent allocation failed (ENOSPC), + * the parent inode is committed regardless to avoid + * backing out parent directory update (by dtInsert()) + * and subsequent dtDelete() which is harmless wrt + * integrity concern. + * the symlink inode will be freed by iput() at exit + * as it has a zero link count (by dtDelete()) and + * no permanant resources. + */ + + iplist[0] = dip; + if (rc == 0) { + iplist[1] = ip; + rc = txCommit(tid, 2, &iplist[0], 0); + } else + rc = txCommit(tid, 1, &iplist[0], 0); + + out3: + txEnd(tid); + up(&JFS_IP(dip)->commit_sem); + up(&JFS_IP(ip)->commit_sem); + if (rc) { + ip->i_nlink = 0; + iput(ip); + } + + out2: + free_UCSname(&dname); + + out1: + jFYI(1, ("jfs_symlink: rc:%d\n", -rc)); + return -rc; +} + + +/* + * NAME: jfs_rename + * + * FUNCTION: rename a file or directory + */ +int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + btstack_t btstack; + ino_t ino; + component_t new_dname; + struct inode *new_ip; + component_t old_dname; + struct inode *old_ip; + int rc; + tid_t tid; + tlock_t *tlck; + dtlock_t *dtlck; + lv_t *lv; + int ipcount; + struct inode *iplist[4]; + tblock_t *tblk; + s64 new_size = 0; + int commit_flag; + + + jFYI(1, + ("jfs_rename: %s %s\n", old_dentry->d_name.name, + new_dentry->d_name.name)); + + old_ip = old_dentry->d_inode; + new_ip = new_dentry->d_inode; + + if ((rc = get_UCSname(&old_dname, old_dentry, + JFS_SBI(old_dir->i_sb)->nls_tab))) + goto out1; + + if ((rc = get_UCSname(&new_dname, new_dentry, + JFS_SBI(old_dir->i_sb)->nls_tab))) + goto out2; + + /* + * Make sure source inode number is what we think it is + */ + rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP); + if (rc || (ino != old_ip->i_ino)) { + rc = ENOENT; + goto out3; + } + + /* + * Make sure dest inode number (if any) is what we think it is + */ + rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP); + if (rc == 0) { + if ((new_ip == 0) || (ino != new_ip->i_ino)) { + rc = ESTALE; + goto out3; + } + } else if (rc != ENOENT) + goto out3; + else if (new_ip) { + /* no entry exists, but one was expected */ + rc = ESTALE; + goto out3; + } + + if (S_ISDIR(old_ip->i_mode)) { + if (new_ip) { + if (!dtEmpty(new_ip)) { + rc = ENOTEMPTY; + goto out3; + } + } else if ((new_dir != old_dir) && + (new_dir->i_nlink == JFS_LINK_MAX)) { + rc = EMLINK; + goto out3; + } + } else if (new_ip) + IWRITE_LOCK(new_ip); + + /* + * The real work starts here + */ + tid = txBegin(new_dir->i_sb, 0); + + down(&JFS_IP(new_dir)->commit_sem); + down(&JFS_IP(old_ip)->commit_sem); + if (old_dir != new_dir) + down(&JFS_IP(old_dir)->commit_sem); + + if (new_ip) { + down(&JFS_IP(new_ip)->commit_sem); + /* + * Change existing directory entry to new inode number + */ + ino = new_ip->i_ino; + rc = dtModify(tid, new_dir, &new_dname, &ino, + old_ip->i_ino, JFS_RENAME); + if (rc) + goto out4; + new_ip->i_nlink--; + if (S_ISDIR(new_ip->i_mode)) { + new_ip->i_nlink--; + assert(new_ip->i_nlink == 0); + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_DELETE; + tblk->ip = new_ip; + } else if (new_ip->i_nlink == 0) { + assert(!test_cflag(COMMIT_Nolink, new_ip)); + /* free block resources */ + if ((new_size = commitZeroLink(tid, new_ip)) < 0) { + txAbort(tid, 1); /* Marks FS Dirty */ + rc = -new_size; /* We return -rc */ + goto out4; + } + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_DELETE; + tblk->ip = new_ip; + } else { + new_ip->i_ctime = CURRENT_TIME; + mark_inode_dirty(new_ip); + } + } else { + /* + * Add new directory entry + */ + rc = dtSearch(new_dir, &new_dname, &ino, &btstack, + JFS_CREATE); + if (rc) { + jERROR(1, + ("jfs_rename didn't expect dtSearch to fail w/rc = %d\n", + rc)); + goto out4; + } + + ino = old_ip->i_ino; + rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack); + if (rc) { + jERROR(1, + ("jfs_rename: dtInsert failed w/rc = %d\n", + rc)); + goto out4; + } + if (S_ISDIR(old_ip->i_mode)) + new_dir->i_nlink++; + } + /* + * Remove old directory entry + */ + + ino = old_ip->i_ino; + rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE); + if (rc) { + jERROR(1, + ("jfs_rename did not expect dtDelete to return rc = %d\n", + rc)); + txAbort(tid, 1); /* Marks Filesystem dirty */ + goto out4; + } + if (S_ISDIR(old_ip->i_mode)) { + old_dir->i_nlink--; + if (old_dir != new_dir) { + /* + * Change inode number of parent for moved directory + */ + + JFS_IP(old_ip)->i_dtroot.header.idotdot = + cpu_to_le32(new_dir->i_ino); + + /* Linelock header of dtree */ + tlck = txLock(tid, old_ip, + (metapage_t *) & JFS_IP(old_ip)->bxflag, + tlckDTREE | tlckBTROOT); + dtlck = (dtlock_t *) & tlck->lock; + ASSERT(dtlck->index == 0); + lv = (lv_t *) & dtlck->lv[0]; + lv->offset = 0; + lv->length = 1; + dtlck->index++; + } + } + + /* + * Update ctime on changed/moved inodes & mark dirty + */ + old_ip->i_ctime = CURRENT_TIME; + mark_inode_dirty(old_ip); + + new_dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(new_dir); + + /* Build list of inodes modified by this transaction */ + ipcount = 0; + iplist[ipcount++] = old_ip; + if (new_ip) + iplist[ipcount++] = new_ip; + iplist[ipcount++] = old_dir; + + if (old_dir != new_dir) { + iplist[ipcount++] = new_dir; + old_dir->i_ctime = CURRENT_TIME; + mark_inode_dirty(old_dir); + } + + /* + * Incomplete truncate of file data can + * result in timing problems unless we synchronously commit the + * transaction. + */ + if (new_size) + commit_flag = COMMIT_SYNC; + else + commit_flag = 0; + + rc = txCommit(tid, ipcount, iplist, commit_flag); + + /* + * Don't unlock new_ip if COMMIT_HOLDLOCK is set + */ + if (new_ip && test_cflag(COMMIT_Holdlock, new_ip)) { + up(&JFS_IP(new_ip)->commit_sem); + new_ip = 0; + } + + out4: + txEnd(tid); + + up(&JFS_IP(new_dir)->commit_sem); + up(&JFS_IP(old_ip)->commit_sem); + if (old_dir != new_dir) + up(&JFS_IP(old_dir)->commit_sem); + if (new_ip) + up(&JFS_IP(new_ip)->commit_sem); + + while (new_size && (rc == 0)) { + tid = txBegin(new_ip->i_sb, 0); + down(&JFS_IP(new_ip)->commit_sem); + new_size = xtTruncate_pmap(tid, new_ip, new_size); + if (new_size < 0) { + txAbort(tid, 1); + rc = -new_size; /* We return -rc */ + } else + rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC); + txEnd(tid); + up(&JFS_IP(new_ip)->commit_sem); + } + if (new_ip && (new_ip->i_nlink == 0)) + set_cflag(COMMIT_Nolink, new_ip); + out3: + free_UCSname(&new_dname); + out2: + free_UCSname(&old_dname); + out1: + if (new_ip && !S_ISDIR(new_ip->i_mode)) + IWRITE_UNLOCK(new_ip); + /* + * Truncating the directory index table is not guaranteed. It + * may need to be done iteratively + */ + if (test_cflag(COMMIT_Stale, old_dir)) { + if (old_dir->i_size > 1) + jfs_truncate_nolock(old_dir, 0); + + clear_cflag(COMMIT_Stale, old_dir); + } + + jFYI(1, ("jfs_rename: returning %d\n", rc)); + return -rc; +} + + +/* + * NAME: jfs_mknod + * + * FUNCTION: Create a special file (device) + */ +int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) +{ + btstack_t btstack; + component_t dname; + ino_t ino; + struct inode *ip; + struct inode *iplist[2]; + int rc; + tid_t tid; + tblock_t *tblk; + + jFYI(1, ("jfs_mknod: %s\n", dentry->d_name.name)); + + if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dir->i_sb)->nls_tab))) + goto out; + + ip = ialloc(dir, mode); + if (ip == NULL) { + rc = ENOSPC; + goto out1; + } + + tid = txBegin(dir->i_sb, 0); + + down(&JFS_IP(dir)->commit_sem); + down(&JFS_IP(ip)->commit_sem); + + if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) + goto out3; + + tblk = tid_to_tblock(tid); + tblk->xflag |= COMMIT_CREATE; + tblk->ip = ip; + + ino = ip->i_ino; + if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) + goto out3; + + init_special_inode(ip, ip->i_mode, rdev); + + insert_inode_hash(ip); + mark_inode_dirty(ip); + d_instantiate(dentry, ip); + + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + + mark_inode_dirty(dir); + + iplist[0] = dir; + iplist[1] = ip; + rc = txCommit(tid, 2, iplist, 0); + + out3: + txEnd(tid); + up(&JFS_IP(ip)->commit_sem); + up(&JFS_IP(dir)->commit_sem); + if (rc) { + ip->i_nlink = 0; + iput(ip); + } + + out1: + free_UCSname(&dname); + + out: + jFYI(1, ("jfs_mknod: returning %d\n", rc)); + return -rc; +} + +static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry) +{ + btstack_t btstack; + ino_t inum; + struct inode *ip; + component_t key; + const char *name = dentry->d_name.name; + int len = dentry->d_name.len; + int rc; + + jFYI(1, ("jfs_lookup: name = %s\n", name)); + + + if ((name[0] == '.') && (len == 1)) + inum = dip->i_ino; + else if (strcmp(name, "..") == 0) + inum = PARENT(dip); + else { + if ((rc = + get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab))) + return ERR_PTR(-rc); + rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP); + free_UCSname(&key); + if (rc == ENOENT) { + d_add(dentry, NULL); + return ERR_PTR(0); + } else if (rc) { + jERROR(1, + ("jfs_lookup: dtSearch returned %d\n", rc)); + return ERR_PTR(-rc); + } + } + + ip = iget(dip->i_sb, inum); + if (ip == NULL) { + jERROR(1, + ("jfs_lookup: iget failed on inum %d\n", + (uint) inum)); + return ERR_PTR(-EACCES); + } + + d_add(dentry, ip); + + return ERR_PTR(0); +} + +struct inode_operations jfs_dir_inode_operations = { + create: jfs_create, + lookup: jfs_lookup, + link: jfs_link, + unlink: jfs_unlink, + symlink: jfs_symlink, + mkdir: jfs_mkdir, + rmdir: jfs_rmdir, + mknod: jfs_mknod, + rename: jfs_rename, +}; + +struct file_operations jfs_dir_operations = { + read: generic_read_dir, + readdir: jfs_readdir, + fsync: jfs_fsync, +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/resize.c linux.20pre2-ac1/fs/jfs/resize.c --- linux.20pre2/fs/jfs/resize.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/resize.c 2002-08-06 18:01:05.000000000 +0100 @@ -0,0 +1,530 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * + * 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 "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_metapage.h" +#include "jfs_dinode.h" +#include "jfs_imap.h" +#include "jfs_dmap.h" +#include "jfs_superblock.h" +#include "jfs_txnmgr.h" +#include "jfs_debug.h" + +extern s64 jfs_get_volume_size(struct super_block *); + +#define BITSPERPAGE (PSIZE << 3) +#define L2MEGABYTE 20 +#define MEGABYTE (1 << L2MEGABYTE) +#define MEGABYTE32 (MEGABYTE << 5) + +/* convert block number to bmap file page number */ +#define BLKTODMAPN(b)\ + (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1) + +/* + * jfs_extendfs() + * + * function: extend file system; + * + * |-------------------------------|----------|----------| + * file system space fsck inline log + * workspace space + * + * input: + * new LVSize: in LV blocks (required) + * new LogSize: in LV blocks (optional) + * new FSSize: in LV blocks (optional) + * + * new configuration: + * 1. set new LogSize as specified or default from new LVSize; + * 2. compute new FSCKSize from new LVSize; + * 3. set new FSSize as MIN(FSSize, LVSize-(LogSize+FSCKSize)) where + * assert(new FSSize >= old FSSize), + * i.e., file system must not be shrinked; + */ +int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) +{ + int rc = 0; + struct jfs_sb_info *sbi = JFS_SBI(sb); + struct inode *ipbmap = sbi->ipbmap; + struct inode *ipbmap2; + struct inode *ipimap = sbi->ipimap; + log_t *log = sbi->log; + bmap_t *bmp = sbi->bmap; + s64 newLogAddress, newFSCKAddress; + int newFSCKSize; + s64 newMapSize = 0, mapSize; + s64 XAddress, XSize, nblocks, xoff, xaddr, t64; + s64 oldLVSize; + s64 newFSSize; + s64 VolumeSize; + int newNpages = 0, nPages, newPage, xlen, t32; + int tid; + int log_formatted = 0; + struct inode *iplist[1]; + struct jfs_superblock *j_sb, *j_sb2; + metapage_t *sbp, *sb2p; + uint old_agsize; + struct buffer_head *bh; + + /* If the volume hasn't grown, get out now */ + + if (sbi->mntflag & JFS_INLINELOG) + oldLVSize = addressPXD(&sbi->logpxd) + lengthPXD(&sbi->logpxd); + else + oldLVSize = addressPXD(&sbi->fsckpxd) + + lengthPXD(&sbi->fsckpxd); + + if (oldLVSize >= newLVSize) { + printk(KERN_WARNING + "jfs_extendfs: volume hasn't grown, returning\n"); + goto out; + } + + VolumeSize = jfs_get_volume_size(sb); + if (VolumeSize) { + if (newLVSize > VolumeSize) { + printk(KERN_WARNING "jfs_extendfs: invalid size\n"); + rc = -EINVAL; + goto out; + } + } else { + /* check the device */ + bh = sb_bread(sb, newLVSize - 1); + if (!bh) { + printk(KERN_WARNING "jfs_extendfs: invalid size\n"); + rc = -EINVAL; + goto out; + } + bforget(bh); + } + + /* Can't extend write-protected drive */ + + if (isReadOnly(ipbmap)) { + printk(KERN_WARNING "jfs_extendfs: read-only file system\n"); + rc = -EROFS; + goto out; + } + + /* + * reconfigure LV spaces + * --------------------- + * + * validate new size, or, if not specified, determine new size + */ + + /* + * reconfigure inline log space: + */ + if ((sbi->mntflag & JFS_INLINELOG)) { + if (newLogSize == 0) { + /* + * no size specified: default to 1/256 of aggregate + * size; rounded up to a megabyte boundary; + */ + newLogSize = newLVSize >> 8; + t32 = (1 << (20 - sbi->l2bsize)) - 1; + newLogSize = (newLogSize + t32) & ~t32; + newLogSize = + min(newLogSize, MEGABYTE32 >> sbi->l2bsize); + } else { + /* + * convert the newLogSize to fs blocks. + * + * Since this is given in megabytes, it will always be + * an even number of pages. + */ + newLogSize = (newLogSize * MEGABYTE) >> sbi->l2bsize; + } + + } else + newLogSize = 0; + + newLogAddress = newLVSize - newLogSize; + + /* + * reconfigure fsck work space: + * + * configure it to the end of the logical volume regardless of + * whether file system extends to the end of the aggregate; + * Need enough 4k pages to cover: + * - 1 bit per block in aggregate rounded up to BPERDMAP boundary + * - 1 extra page to handle control page and intermediate level pages + * - 50 extra pages for the chkdsk service log + */ + t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP) + << L2BPERDMAP; + t32 = ((t64 + (BITSPERPAGE - 1)) / BITSPERPAGE) + 1 + 50; + newFSCKSize = t32 << sbi->l2nbperpage; + newFSCKAddress = newLogAddress - newFSCKSize; + + /* + * compute new file system space; + */ + newFSSize = newLVSize - newLogSize - newFSCKSize; + + /* file system cannot be shrinked */ + if (newFSSize < bmp->db_mapsize) { + rc = EINVAL; + goto out; + } + + /* + * If we're expanding enough that the inline log does not overlap + * the old one, we can format the new log before we quiesce the + * filesystem. + */ + if ((sbi->mntflag & JFS_INLINELOG) && (newLogAddress > oldLVSize)) { + if ((rc = lmLogFormat(log, newLogAddress, newLogSize))) + goto out; + log_formatted = 1; + } + /* + * quiesce file system + * + * (prepare to move the inline log and to prevent map update) + * + * block any new transactions and wait for completion of + * all wip transactions and flush modified pages s.t. + * on-disk file system is in consistent state and + * log is not required for recovery. + */ + txQuiesce(sb); + + if (sbi->mntflag & JFS_INLINELOG) { + /* + * deactivate old inline log + */ + lmLogShutdown(log); + + /* + * mark on-disk super block for fs in transition; + * + * update on-disk superblock for the new space configuration + * of inline log space and fsck work space descriptors: + * N.B. FS descriptor is NOT updated; + * + * crash recovery: + * logredo(): if FM_EXTENDFS, return to fsck() for cleanup; + * fsck(): if FM_EXTENDFS, reformat inline log and fsck + * workspace from superblock inline log descriptor and fsck + * workspace descriptor; + */ + + /* read in superblock */ + if ((rc = readSuper(sb, &sbp))) + goto error_out; + j_sb = (struct jfs_superblock *) (sbp->data); + + /* mark extendfs() in progress */ + j_sb->s_state |= cpu_to_le32(FM_EXTENDFS); + j_sb->s_xsize = cpu_to_le64(newFSSize); + PXDaddress(&j_sb->s_xfsckpxd, newFSCKAddress); + PXDlength(&j_sb->s_xfsckpxd, newFSCKSize); + PXDaddress(&j_sb->s_xlogpxd, newLogAddress); + PXDlength(&j_sb->s_xlogpxd, newLogSize); + + /* synchronously update superblock */ + flush_metapage(sbp); + + /* + * format new inline log synchronously; + * + * crash recovery: if log move in progress, + * reformat log and exit success; + */ + if (!log_formatted) + if ((rc = lmLogFormat(log, newLogAddress, newLogSize))) + goto error_out; + + /* + * activate new log + */ + log->base = newLogAddress; + log->size = newLogSize >> (L2LOGPSIZE - sb->s_blocksize_bits); + if ((rc = lmLogInit(log))) + goto error_out; + } + + /* + * extend block allocation map + * --------------------------- + * + * extendfs() for new extension, retry after crash recovery; + * + * note: both logredo() and fsck() rebuild map from + * the bitmap and configuration parameter from superblock + * (disregarding all other control information in the map); + * + * superblock: + * s_size: aggregate size in physical blocks; + */ + /* + * compute the new block allocation map configuration + * + * map dinode: + * di_size: map file size in byte; + * di_nblocks: number of blocks allocated for map file; + * di_mapsize: number of blocks in aggregate (covered by map); + * map control page: + * db_mapsize: number of blocks in aggregate (covered by map); + */ + newMapSize = newFSSize; + /* number of data pages of new bmap file: + * roundup new size to full dmap page boundary and + * add 1 extra dmap page for next extendfs() + */ + t64 = (newMapSize - 1) + BPERDMAP; + newNpages = BLKTODMAPN(t64) + 1; + + /* + * extend map from current map (WITHOUT growing mapfile) + * + * map new extension with unmapped part of the last partial + * dmap page, if applicable, and extra page(s) allocated + * at end of bmap by mkfs() or previous extendfs(); + */ + extendBmap: + /* compute number of blocks requested to extend */ + mapSize = bmp->db_mapsize; + XAddress = mapSize; /* eXtension Address */ + XSize = newMapSize - mapSize; /* eXtension Size */ + old_agsize = bmp->db_agsize; /* We need to know if this changes */ + + /* compute number of blocks that can be extended by current mapfile */ + t64 = dbMapFileSizeToMapSize(ipbmap); + if (mapSize > t64) { + printk(KERN_ERR + "jfs_extendfs: mapSize (0x%llx) > t64 (0x%llx)\n", + mapSize, t64); + rc = EIO; + goto error_out; + } + nblocks = min(t64 - mapSize, XSize); + + /* + * update map pages for new extension: + * + * update/init dmap and bubble up the control hierarchy + * incrementally fold up dmaps into upper levels; + * update bmap control page; + */ + if ((rc = dbExtendFS(ipbmap, XAddress, nblocks))) + goto error_out; + /* + * the map now has extended to cover additional nblocks: + * dn_mapsize = oldMapsize + nblocks; + */ + /* ipbmap->i_mapsize += nblocks; */ + XSize -= nblocks; + + /* + * grow map file to cover remaining extension + * and/or one extra dmap page for next extendfs(); + * + * allocate new map pages and its backing blocks, and + * update map file xtree + */ + /* compute number of data pages of current bmap file */ + nPages = ipbmap->i_size >> L2PSIZE; + + /* need to grow map file ? */ + if (nPages == newNpages) + goto updateImap; + + /* + * grow bmap file for the new map pages required: + * + * allocate growth at the start of newly extended region; + * bmap file only grows sequentially, i.e., both data pages + * and possibly xtree index pages may grow in append mode, + * s.t. logredo() can reconstruct pre-extension state + * by washing away bmap file of pages outside s_size boundary; + */ + /* + * journal map file growth as if a regular file growth: + * (note: bmap is created with di_mode = IFJOURNAL|IFREG); + * + * journaling of bmap file growth is not required since + * logredo() do/can not use log records of bmap file growth + * but it provides careful write semantics, pmap update, etc.; + */ + /* synchronous write of data pages: bmap data pages are + * cached in meta-data cache, and not written out + * by txCommit(); + */ + fsync_inode_data_buffers(ipbmap); + diWriteSpecial(ipbmap, 0); + + newPage = nPages; /* first new page number */ + xoff = newPage << sbi->l2nbperpage; + xlen = (newNpages - nPages) << sbi->l2nbperpage; + xlen = min(xlen, (int) nblocks) & ~(sbi->nbperpage - 1); + xaddr = XAddress; + + tid = txBegin(sb, COMMIT_FORCE); + + if ((rc = xtAppend(tid, ipbmap, 0, xoff, nblocks, &xlen, &xaddr, 0))) { + txEnd(tid); + goto error_out; + } + /* update bmap file size */ + ipbmap->i_size += xlen << sbi->l2bsize; + ipbmap->i_blocks += LBLK2PBLK(sb, xlen); + + iplist[0] = ipbmap; + rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); + + txEnd(tid); + + if (rc) + goto error_out; + + /* + * map file has been grown now to cover extension to further out; + * di_size = new map file size; + * + * if huge extension, the previous extension based on previous + * map file size may not have been sufficient to cover whole extension + * (it could have been used up for new map pages), + * but the newly grown map file now covers lot bigger new free space + * available for further extension of map; + */ + /* any more blocks to extend ? */ + if (XSize) + goto extendBmap; + + /* finalize bmap */ + dbFinalizeBmap(ipbmap); + + /* + * update inode allocation map + * --------------------------- + * + * move iag lists from old to new iag; + * agstart field is not updated for logredo() to reconstruct + * iag lists if system crash occurs. + * (computation of ag number from agstart based on agsize + * will correctly identify the new ag); + */ + updateImap: + /* if new AG size the same as old AG size, done! */ + if (bmp->db_agsize != old_agsize) { + if ((rc = diExtendFS(ipimap, ipbmap))) + goto error_out; + + /* finalize imap */ + if ((rc = diSync(ipimap))) + goto error_out; + } + + /* + * finalize + * -------- + * + * extension is committed when on-disk super block is + * updated with new descriptors: logredo will recover + * crash before it to pre-extension state; + */ + + /* sync log to skip log replay of bmap file growth transaction; */ + /* lmLogSync(log, 1); */ + + /* + * synchronous write bmap global control page; + * for crash before completion of write + * logredo() will recover to pre-extendfs state; + * for crash after completion of write, + * logredo() will recover post-extendfs state; + */ + if ((rc = dbSync(ipbmap))) + goto error_out; + + /* + * copy primary bmap inode to secondary bmap inode + */ + + ipbmap2 = diReadSpecial(sb, BMAP_I, 1); + if (ipbmap2 == NULL) { + printk(KERN_ERR "jfs_extendfs: diReadSpecial(bmap) failed\n"); + goto error_out; + } + memcpy(&JFS_IP(ipbmap2)->i_xtroot, &JFS_IP(ipbmap)->i_xtroot, 288); + ipbmap2->i_size = ipbmap->i_size; + ipbmap2->i_blocks = ipbmap->i_blocks; + + diWriteSpecial(ipbmap2, 1); + diFreeSpecial(ipbmap2); + /* + * update superblock + */ + if ((rc = readSuper(sb, &sbp))) + goto error_out; + j_sb = (struct jfs_superblock *) (sbp->data); + + /* mark extendfs() completion */ + j_sb->s_state &= cpu_to_le32(~FM_EXTENDFS); + j_sb->s_size = cpu_to_le64(bmp->db_mapsize) << + le16_to_cpu(j_sb->s_l2bfactor); + j_sb->s_agsize = cpu_to_le32(bmp->db_agsize); + + /* update inline log space descriptor */ + if (sbi->mntflag & JFS_INLINELOG) { + PXDaddress(&(j_sb->s_logpxd), newLogAddress); + PXDlength(&(j_sb->s_logpxd), newLogSize); + } + + /* record log's mount serial number */ + j_sb->s_logserial = cpu_to_le32(log->serial); + + /* update fsck work space descriptor */ + PXDaddress(&(j_sb->s_fsckpxd), newFSCKAddress); + PXDlength(&(j_sb->s_fsckpxd), newFSCKSize); + j_sb->s_fscklog = 1; + /* sb->s_fsckloglen remains the same */ + + /* Update secondary superblock */ + sb2p = read_metapage(sbi->direct_inode, + SUPER2_OFF >> sb->s_blocksize_bits, PSIZE, 1); + + if (sb2p) { + j_sb2 = (struct jfs_superblock *) (sb2p->data); + memcpy(j_sb2, j_sb, sizeof (struct jfs_superblock)); + flush_metapage(sb2p); + } + + /* write primary superblock */ + flush_metapage(sbp); + + goto resume; + + error_out: + updateSuper(sb, FM_DIRTY); + + resume: + /* + * resume file system transactions + */ + txResume(sb); + + out: + return rc; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/super.c linux.20pre2-ac1/fs/jfs/super.c --- linux.20pre2/fs/jfs/super.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/super.c 2002-08-06 18:01:27.000000000 +0100 @@ -0,0 +1,516 @@ +/* + * Copyright (c) International Business Machines Corp., 2000-2002 + * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "jfs_incore.h" +#include "jfs_filsys.h" +#include "jfs_metapage.h" +#include "jfs_superblock.h" +#include "jfs_dmap.h" +#include "jfs_imap.h" +#include "jfs_debug.h" + +MODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); +MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM"); +MODULE_LICENSE("GPL"); + +int jfs_stop_threads; +static pid_t jfsIOthread; +static pid_t jfsCommitThread; +static pid_t jfsSyncThread; +DECLARE_COMPLETION(jfsIOwait); + +#ifdef CONFIG_JFS_DEBUG +int jfsloglevel = 1; +MODULE_PARM(jfsloglevel, "i"); +MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)"); +#endif + +/* + * External declarations + */ +extern int jfs_mount(struct super_block *); +extern int jfs_mount_rw(struct super_block *, int); +extern int jfs_umount(struct super_block *); +extern int jfs_umount_rw(struct super_block *); + +extern int jfsIOWait(void *); +extern int jfs_lazycommit(void *); +extern int jfs_sync(void *); +extern void jfs_clear_inode(struct inode *inode); +extern void jfs_read_inode(struct inode *inode); +extern void jfs_dirty_inode(struct inode *inode); +extern void jfs_delete_inode(struct inode *inode); +extern void jfs_write_inode(struct inode *inode, int wait); +extern int jfs_extendfs(struct super_block *, s64, int); + +#ifdef PROC_FS_JFS /* see jfs_debug.h */ +extern void jfs_proc_init(void); +extern void jfs_proc_clean(void); +#endif + +extern wait_queue_head_t jfs_IO_thread_wait; +extern wait_queue_head_t jfs_commit_thread_wait; +extern wait_queue_head_t jfs_sync_thread_wait; + +static int jfs_statfs(struct super_block *sb, struct statfs *buf) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + s64 maxinodes; + imap_t *imap = JFS_IP(sbi->ipimap)->i_imap; + + jFYI(1, ("In jfs_statfs\n")); + buf->f_type = JFS_SUPER_MAGIC; + buf->f_bsize = sbi->bsize; + buf->f_blocks = sbi->bmap->db_mapsize; + buf->f_bfree = sbi->bmap->db_nfree; + buf->f_bavail = sbi->bmap->db_nfree; + /* + * If we really return the number of allocated & free inodes, some + * applications will fail because they won't see enough free inodes. + * We'll try to calculate some guess as to how may inodes we can + * really allocate + * + * buf->f_files = atomic_read(&imap->im_numinos); + * buf->f_ffree = atomic_read(&imap->im_numfree); + */ + maxinodes = min((s64) atomic_read(&imap->im_numinos) + + ((sbi->bmap->db_nfree >> imap->im_l2nbperiext) + << L2INOSPEREXT), (s64) 0xffffffffLL); + buf->f_files = maxinodes; + buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) - + atomic_read(&imap->im_numfree)); + + buf->f_namelen = JFS_NAME_MAX; + return 0; +} + +static void jfs_put_super(struct super_block *sb) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + int rc; + + jFYI(1, ("In jfs_put_super\n")); + rc = jfs_umount(sb); + if (rc) { + jERROR(1, ("jfs_umount failed with return code %d\n", rc)); + } + unload_nls(sbi->nls_tab); + sbi->nls_tab = NULL; + + /* + * We need to clean out the direct_inode pages since this inode + * is not in the inode hash. + */ + fsync_inode_data_buffers(sbi->direct_inode); + truncate_inode_pages(sbi->direct_mapping, 0); + iput(sbi->direct_inode); + sbi->direct_inode = NULL; + sbi->direct_mapping = NULL; + + kfree(sbi); +} + +s64 jfs_get_volume_size(struct super_block *sb) +{ + uint blocks = 0; + s64 bytes; + kdev_t dev = sb->s_dev; + int major = MAJOR(dev); + int minor = MINOR(dev); + + if (blk_size[major]) { + blocks = blk_size[major][minor]; + if (blocks) { + bytes = ((s64)blocks) << BLOCK_SIZE_BITS; + return bytes >> sb->s_blocksize_bits; + } + } + + return 0; +} + + +static int parse_options(char *options, struct super_block *sb, s64 *newLVSize) +{ + void *nls_map = NULL; + char *this_char; + char *value; + struct jfs_sb_info *sbi = JFS_SBI(sb); + + *newLVSize = 0; + + if (!options) + return 1; + while ((this_char = strsep(&options, ",")) != NULL) { + if (!*this_char) + continue; + if ((value = strchr(this_char, '=')) != NULL) + *value++ = 0; + if (!strcmp(this_char, "iocharset")) { + if (!value || !*value) + goto needs_arg; + if (nls_map) /* specified iocharset twice! */ + unload_nls(nls_map); + nls_map = load_nls(value); + if (!nls_map) { + printk(KERN_ERR "JFS: charset not found\n"); + goto cleanup; + } + } else if (!strcmp(this_char, "resize")) { + if (!value || !*value) { + *newLVSize = jfs_get_volume_size(sb); + if (*newLVSize == 0) + printk(KERN_ERR + "JFS: Cannot determine volume size\n"); + } else + *newLVSize = simple_strtoull(value, &value, 0); + + /* Silently ignore the quota options */ + } else if (!strcmp(this_char, "grpquota") + || !strcmp(this_char, "noquota") + || !strcmp(this_char, "quota") + || !strcmp(this_char, "usrquota")) + /* Don't do anything ;-) */ ; + else { + printk("jfs: Unrecognized mount option %s\n", + this_char); + goto cleanup; + } + } + if (nls_map) { + /* Discard old (if remount) */ + if (sbi->nls_tab) + unload_nls(sbi->nls_tab); + sbi->nls_tab = nls_map; + } + return 1; +needs_arg: + printk(KERN_ERR "JFS: %s needs an argument\n", this_char); +cleanup: + if (nls_map) + unload_nls(nls_map); + return 0; +} + +int jfs_remount(struct super_block *sb, int *flags, char *data) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + s64 newLVSize = 0; + int rc = 0; + + if (!parse_options(data, sb, &newLVSize)) { + return -EINVAL; + } + if (newLVSize) { + if (sb->s_flags & MS_RDONLY) { + printk(KERN_ERR + "JFS: resize requires volume to be mounted read-write\n"); + return -EROFS; + } + rc = jfs_extendfs(sb, newLVSize, 0); + if (rc) + return rc; + } + + if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { + /* + * Invalidate any previously read metadata. fsck may + * have changed the on-disk data since we mounted r/o + */ + truncate_inode_pages(sbi->direct_mapping, 0); + + return jfs_mount_rw(sb, 1); + } else if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) + return jfs_umount_rw(sb); + + return 0; +} + +static struct super_operations jfs_sops = { + read_inode: jfs_read_inode, + dirty_inode: jfs_dirty_inode, + write_inode: jfs_write_inode, + clear_inode: jfs_clear_inode, + delete_inode: jfs_delete_inode, + put_super: jfs_put_super, + statfs: jfs_statfs, + remount_fs: jfs_remount, +}; + +static struct super_block *jfs_read_super(struct super_block *sb, + void *data, int silent) +{ + struct jfs_sb_info *sbi; + struct inode *inode; + int rc; + s64 newLVSize = 0; + + jFYI(1, + ("In jfs_read_super s_dev=0x%x s_flags=0x%lx\n", sb->s_dev, + sb->s_flags)); + + sbi = kmalloc(sizeof (struct jfs_sb_info), GFP_KERNEL); + if (!sbi) + return NULL; + memset(sbi, 0, sizeof (struct jfs_sb_info)); + sb->u.generic_sbp = sbi; + + if (!parse_options((char *) data, sb, &newLVSize)) { + kfree(sbi); + return NULL; + } + + if (newLVSize) { + printk(KERN_ERR "resize option for remount only\n"); + return NULL; + } + + /* + * Initialize blocksize to 4K. + */ + sb->s_blocksize = PSIZE; + sb->s_blocksize_bits = L2PSIZE; + set_blocksize(sb->s_dev, PSIZE); + + /* + * Initialize direct-mapping inode/address-space + */ + inode = new_inode(sb); + if (inode == NULL) + goto out_kfree; + inode->i_ino = 0; + inode->i_nlink = 1; + inode->i_size = 0x0000010000000000LL; + inode->i_mapping->a_ops = &direct_aops; + inode->i_mapping->gfp_mask = GFP_NOFS; + + sbi->direct_inode = inode; + sbi->direct_mapping = inode->i_mapping; + + rc = alloc_jfs_inode(inode); + if (rc) + goto out_free_inode; + + sb->s_op = &jfs_sops; + rc = jfs_mount(sb); + if (rc) { + if (!silent) { + jERROR(1, + ("jfs_mount failed w/return code = %d\n", rc)); + } + goto out_mount_failed; + } + if (sb->s_flags & MS_RDONLY) + sbi->log = 0; + else { + rc = jfs_mount_rw(sb, 0); + if (rc) { + if (!silent) { + jERROR(1, + ("jfs_mount_rw failed w/return code = %d\n", + rc)); + } + goto out_no_rw; + } + } + + sb->s_magic = JFS_SUPER_MAGIC; + + inode = iget(sb, ROOT_I); + if (!inode || is_bad_inode(inode)) + goto out_no_root; + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) + goto out_no_root; + + if (!sbi->nls_tab) + sbi->nls_tab = load_nls_default(); + + /* logical blocks are represented by 40 bits in pxd_t, etc. */ + sb->s_maxbytes = ((u64) sb->s_blocksize) << 40; +#if BITS_PER_LONG == 32 + /* Page cache is indexed by long. */ + sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, sb->s_maxbytes); +#endif + + return sb; + +out_no_root: + jEVENT(1, ("jfs_read_super: get root inode failed\n")); + if (inode) + iput(inode); + +out_no_rw: + rc = jfs_umount(sb); + if (rc) { + jERROR(1, ("jfs_umount failed with return code %d\n", rc)); + } +out_mount_failed: + fsync_inode_data_buffers(sbi->direct_inode); + truncate_inode_pages(sbi->direct_mapping, 0); + sb->s_op = NULL; + + free_jfs_inode(inode); + +out_free_inode: + iput(sbi->direct_inode); + sbi->direct_inode = NULL; + sbi->direct_mapping = NULL; +out_kfree: + if (sbi->nls_tab) + unload_nls(sbi->nls_tab); + kfree(sbi); + return NULL; +} + +static DECLARE_FSTYPE_DEV(jfs_fs_type, "jfs", jfs_read_super); + +extern int metapage_init(void); +extern int txInit(void); +extern void txExit(void); +extern void metapage_exit(void); + +static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) +{ + struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; + + if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + INIT_LIST_HEAD(&jfs_ip->anon_inode_list); + INIT_LIST_HEAD(&jfs_ip->mp_list); + init_rwsem(&jfs_ip->rdwrlock); + init_MUTEX(&jfs_ip->commit_sem); + jfs_ip->atlhead = 0; + } +} + +static int __init init_jfs_fs(void) +{ + int rc; + + jfs_inode_cachep = + kmem_cache_create("jfs_ip", + sizeof (struct jfs_inode_info), + 0, 0, init_once, NULL); + if (jfs_inode_cachep == NULL) + return -ENOMEM; + + /* + * Metapage initialization + */ + rc = metapage_init(); + if (rc) { + jERROR(1, ("metapage_init failed w/rc = %d\n", rc)); + goto free_slab; + } + + /* + * Transaction Manager initialization + */ + rc = txInit(); + if (rc) { + jERROR(1, ("txInit failed w/rc = %d\n", rc)); + goto free_metapage; + } + + /* + * I/O completion thread (endio) + */ + jfsIOthread = kernel_thread(jfsIOWait, 0, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (jfsIOthread < 0) { + jERROR(1, + ("init_jfs_fs: fork failed w/rc = %d\n", jfsIOthread)); + goto end_txmngr; + } + wait_for_completion(&jfsIOwait); /* Wait until thread starts */ + + jfsCommitThread = kernel_thread(jfs_lazycommit, 0, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (jfsCommitThread < 0) { + jERROR(1, + ("init_jfs_fs: fork failed w/rc = %d\n", + jfsCommitThread)); + goto kill_iotask; + } + wait_for_completion(&jfsIOwait); /* Wait until thread starts */ + + jfsSyncThread = kernel_thread(jfs_sync, 0, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (jfsSyncThread < 0) { + jERROR(1, + ("init_jfs_fs: fork failed w/rc = %d\n", jfsSyncThread)); + goto kill_committask; + } + wait_for_completion(&jfsIOwait); /* Wait until thread starts */ + +#ifdef PROC_FS_JFS + jfs_proc_init(); +#endif + + return register_filesystem(&jfs_fs_type); + +kill_committask: + jfs_stop_threads = 1; + wake_up(&jfs_commit_thread_wait); + wait_for_completion(&jfsIOwait); /* Wait for thread exit */ +kill_iotask: + jfs_stop_threads = 1; + wake_up(&jfs_IO_thread_wait); + wait_for_completion(&jfsIOwait); /* Wait for thread exit */ +end_txmngr: + txExit(); +free_metapage: + metapage_exit(); +free_slab: + kmem_cache_destroy(jfs_inode_cachep); + return -rc; +} + +static void __exit exit_jfs_fs(void) +{ + jFYI(1, ("exit_jfs_fs called\n")); + + jfs_stop_threads = 1; + txExit(); + metapage_exit(); + wake_up(&jfs_IO_thread_wait); + wait_for_completion(&jfsIOwait); /* Wait for thread exit */ + wake_up(&jfs_commit_thread_wait); + wait_for_completion(&jfsIOwait); /* Wait for thread exit */ + wake_up(&jfs_sync_thread_wait); + wait_for_completion(&jfsIOwait); /* Wait for thread exit */ +#ifdef PROC_FS_JFS + jfs_proc_clean(); +#endif + unregister_filesystem(&jfs_fs_type); + kmem_cache_destroy(jfs_inode_cachep); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_jfs_fs) +module_exit(exit_jfs_fs) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/jfs/symlink.c linux.20pre2-ac1/fs/jfs/symlink.c --- linux.20pre2/fs/jfs/symlink.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/jfs/symlink.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,43 @@ +/* + * Copyright (c) Christoph Hellwig, 2001-2002 + * + * 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 "jfs_incore.h" + +static int jfs_readlink(struct dentry *, char *buffer, int buflen); +static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd); + +/* + * symlinks can't do much... + */ +struct inode_operations jfs_symlink_inode_operations = { + readlink: jfs_readlink, + follow_link: jfs_follow_link, +}; + +static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char *s = JFS_IP(dentry->d_inode)->i_inline; + return vfs_follow_link(nd, s); +} + +static int jfs_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + char *s = JFS_IP(dentry->d_inode)->i_inline; + return vfs_readlink(dentry, buffer, buflen, s); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/lockd/svclock.c linux.20pre2-ac1/fs/lockd/svclock.c --- linux.20pre2/fs/lockd/svclock.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/lockd/svclock.c 2002-08-06 15:41:51.000000000 +0100 @@ -62,8 +62,8 @@ nlmsvc_remove_block(block); bp = &nlm_blocked; if (when != NLM_NEVER) { - if ((when += jiffies) == NLM_NEVER) - when ++; + if ((when += jiffies) > NLM_NEVER) + when = NLM_NEVER; while ((b = *bp) && time_before_eq(b->b_when,when)) bp = &b->b_next; } else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/lockd/svcproc.c linux.20pre2-ac1/fs/lockd/svcproc.c --- linux.20pre2/fs/lockd/svcproc.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/lockd/svcproc.c 2002-08-06 15:41:51.000000000 +0100 @@ -345,6 +345,15 @@ return stat; } +static int +nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, + void *resp) +{ + dprintk("lockd: GRANTED_RES called\n"); + nlmsvc_grant_reply(&argp->cookie, argp->status); + return 0; +} + /* * SHARE: create a DOS share or alter existing share. */ @@ -545,14 +554,12 @@ #define nlmsvc_decode_lockres nlmsvc_decode_void #define nlmsvc_decode_unlockres nlmsvc_decode_void #define nlmsvc_decode_cancelres nlmsvc_decode_void -#define nlmsvc_decode_grantedres nlmsvc_decode_void #define nlmsvc_proc_none nlmsvc_proc_null #define nlmsvc_proc_test_res nlmsvc_proc_null #define nlmsvc_proc_lock_res nlmsvc_proc_null #define nlmsvc_proc_cancel_res nlmsvc_proc_null #define nlmsvc_proc_unlock_res nlmsvc_proc_null -#define nlmsvc_proc_granted_res nlmsvc_proc_null struct nlm_void { int dummy; }; @@ -589,7 +596,7 @@ PROC(lock_res, lockres, norep, res, void, 1), PROC(cancel_res, cancelres, norep, res, void, 1), PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, grantedres, norep, res, void, 1), + PROC(granted_res, res, norep, res, void, 1), /* statd callback */ PROC(sm_notify, reboot, void, reboot, void, 1), PROC(none, void, void, void, void, 1), diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/locks.c linux.20pre2-ac1/fs/locks.c --- linux.20pre2/fs/locks.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/locks.c 2002-08-11 21:27:46.000000000 +0100 @@ -121,6 +121,7 @@ #include #include #include +#include #include #include @@ -273,9 +274,18 @@ return -EINVAL; } - if (((start += l->l_start) < 0) || (l->l_len < 0)) + /* POSIX-1996 leaves the case l->l_len < 0 undefined; + POSIX-2001 defines it. */ + start += l->l_start; + if (l->l_len < 0) { + end = start - 1; + start += l->l_len; + } else { + end = start + l->l_len - 1; + } + + if (start < 0) return -EINVAL; - end = start + l->l_len - 1; if (l->l_len > 0 && end < 0) return -EOVERFLOW; fl->fl_start = start; /* we record the absolute position */ @@ -445,8 +455,7 @@ /* Let the blocked process remove waiter from the * block list when it gets scheduled. */ - current->policy |= SCHED_YIELD; - schedule(); + yield(); } else { /* Remove waiter from the block list, because by the * time it wakes up blocker won't exist any more. @@ -926,8 +935,11 @@ goto next_lock; /* If the next lock in the list has entirely bigger * addresses than the new one, insert the lock here. + * + * be careful if fl_end == OFFSET_MAX --okir */ - if (fl->fl_start > caller->fl_end + 1) + if (fl->fl_start > caller->fl_end + 1 + && caller->fl_end != OFFSET_MAX) break; /* If we come here, the new and old lock are of the @@ -1051,6 +1063,47 @@ return -EINVAL; } +/* We already had a lease on this file; just change its type */ +static int lease_modify(struct file_lock **before, int arg) +{ + struct file_lock *fl = *before; + int error = assign_type(fl, arg); + + if (error) + return error; + locks_wake_up_blocks(fl, 0); + if (arg == F_UNLCK) { + struct file *filp = fl->fl_file; + + filp->f_owner.pid = 0; + filp->f_owner.uid = 0; + filp->f_owner.euid = 0; + filp->f_owner.signum = 0; + locks_delete_lock(before, 0); + } + return 0; +} + +static void time_out_leases(struct inode *inode) +{ + struct file_lock **before; + struct file_lock *fl; + + before = &inode->i_flock; + while ((fl = *before) && (fl->fl_flags & FL_LEASE) + && (fl->fl_type & F_INPROGRESS)) { + if ((fl->fl_break_time == 0) + || time_before(jiffies, fl->fl_break_time)) { + before = &fl->fl_next; + continue; + } + printk(KERN_INFO "lease broken - owner pid = %d\n", fl->fl_pid); + lease_modify(before, fl->fl_type & ~F_INPROGRESS); + if (fl == *before) /* lease_modify may have freed fl */ + before = &fl->fl_next; + } +} + /** * __get_lease - revoke all outstanding leases on file * @inode: the inode of the file to return @@ -1067,34 +1120,30 @@ struct file_lock *new_fl, *flock; struct file_lock *fl; int alloc_err; + unsigned long break_time; + int i_have_this_lease = 0; - alloc_err = lease_alloc(NULL, 0, &new_fl); + alloc_err = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK, + &new_fl); lock_kernel(); + + time_out_leases(inode); + flock = inode->i_flock; - if (flock->fl_type & F_INPROGRESS) { - if ((mode & O_NONBLOCK) - || (flock->fl_owner == current->files)) { - error = -EWOULDBLOCK; - goto out; - } - if (alloc_err != 0) { - error = alloc_err; - goto out; - } - do { - error = locks_block_on(flock, new_fl); - if (error != 0) - goto out; - flock = inode->i_flock; - if (!(flock && (flock->fl_flags & FL_LEASE))) - goto out; - } while (flock->fl_type & F_INPROGRESS); - } + if ((flock == NULL) || (flock->fl_flags & FL_LEASE) == 0) + goto out; + + for (fl = flock; fl && (fl->fl_flags & FL_LEASE); fl = fl->fl_next) + if (fl->fl_owner == current->files) + i_have_this_lease = 1; if (mode & FMODE_WRITE) { /* If we want write access, we have to revoke any lease. */ future = F_UNLCK | F_INPROGRESS; + } else if (flock->fl_type & F_INPROGRESS) { + /* If the lease is already being broken, we just leave it */ + future = flock->fl_type; } else if (flock->fl_type & F_WRLCK) { /* Downgrade the exclusive lease to a read-only lease. */ future = F_RDLCK | F_INPROGRESS; @@ -1103,38 +1152,49 @@ goto out; } - if (alloc_err && (flock->fl_owner != current->files)) { + if (alloc_err && !i_have_this_lease && ((mode & O_NONBLOCK) == 0)) { error = alloc_err; goto out; } - fl = flock; - do { - fl->fl_type = future; - fl = fl->fl_next; - } while (fl != NULL && (fl->fl_flags & FL_LEASE)); + break_time = 0; + if (lease_break_time > 0) { + break_time = jiffies + lease_break_time * HZ; + if (break_time == 0) + break_time++; /* so that 0 means no break time */ + } - kill_fasync(&flock->fl_fasync, SIGIO, POLL_MSG); + for (fl = flock; fl && (fl->fl_flags & FL_LEASE); fl = fl->fl_next) { + if (fl->fl_type != future) { + fl->fl_type = future; + fl->fl_break_time = break_time; + kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); + } + } - if ((mode & O_NONBLOCK) || (flock->fl_owner == current->files)) { + if (i_have_this_lease || (mode & O_NONBLOCK)) { error = -EWOULDBLOCK; goto out; } - if (lease_break_time > 0) - error = lease_break_time * HZ; - else - error = 0; restart: - error = locks_block_on_timeout(flock, new_fl, error); - if (error == 0) { - /* We timed out. Unilaterally break the lease. */ - locks_delete_lock(&inode->i_flock, 0); - printk(KERN_WARNING "lease timed out\n"); - } else if (error > 0) { - flock = inode->i_flock; - if (flock && (flock->fl_flags & FL_LEASE)) - goto restart; + break_time = flock->fl_break_time; + if (break_time != 0) { + break_time -= jiffies; + if (break_time == 0) + break_time++; + } + error = locks_block_on_timeout(flock, new_fl, break_time); + if (error >= 0) { + if (error == 0) + time_out_leases(inode); + /* Wait for the next lease that has not been broken yet */ + for (flock = inode->i_flock; + flock && (flock->fl_flags & FL_LEASE); + flock = flock->fl_next) { + if (flock->fl_type & F_INPROGRESS) + goto restart; + } error = 0; } @@ -1166,45 +1226,41 @@ * @filp: the file * * The value returned by this function will be one of + * (if no lease break is pending): * - * %F_RDLCK to indicate a read-only (type II) lease is held. + * %F_RDLCK to indicate a shared lease is held. * * %F_WRLCK to indicate an exclusive lease is held. * - * XXX: sfr & i disagree over whether F_INPROGRESS + * %F_UNLCK to indicate no lease is held. + * + * (if a lease break is pending): + * + * %F_RDLCK to indicate an exclusive lease needs to be + * changed to a shared lease (or removed). + * + * %F_UNLCK to indicate the lease needs to be removed. + * + * XXX: sfr & willy disagree over whether F_INPROGRESS * should be returned to userspace. */ int fcntl_getlease(struct file *filp) { struct file_lock *fl; - - fl = filp->f_dentry->d_inode->i_flock; - if ((fl == NULL) || ((fl->fl_flags & FL_LEASE) == 0)) - return F_UNLCK; - return fl->fl_type & ~F_INPROGRESS; -} - -/* We already had a lease on this file; just change its type */ -static int lease_modify(struct file_lock **before, int arg, int fd, struct file *filp) -{ - struct file_lock *fl = *before; - int error = assign_type(fl, arg); - if (error < 0) - goto out; - - locks_wake_up_blocks(fl, 0); + int type = F_UNLCK; - if (arg == F_UNLCK) { - filp->f_owner.pid = 0; - filp->f_owner.uid = 0; - filp->f_owner.euid = 0; - filp->f_owner.signum = 0; - locks_delete_lock(before, 0); - fasync_helper(fd, filp, 0, &fl->fl_fasync); + lock_kernel(); + time_out_leases(filp->f_dentry->d_inode); + for (fl = filp->f_dentry->d_inode->i_flock; + fl && (fl->fl_flags & FL_LEASE); + fl = fl->fl_next) { + if (fl->fl_file == filp) { + type = fl->fl_type & ~F_INPROGRESS; + break; + } } - -out: - return error; + unlock_kernel(); + return type; } /** @@ -1232,50 +1288,59 @@ if (!S_ISREG(inode->i_mode)) return -EINVAL; + lock_kernel(); + + time_out_leases(inode); + /* * FIXME: What about F_RDLCK and files open for writing? */ + error = -EAGAIN; if ((arg == F_WRLCK) && ((atomic_read(&dentry->d_count) > 1) || (atomic_read(&inode->i_count) > 1))) - return -EAGAIN; - - before = &inode->i_flock; - - lock_kernel(); + goto out_unlock; - while ((fl = *before) != NULL) { - if (fl->fl_flags != FL_LEASE) - break; + /* + * At this point, we know that if there is an exclusive + * lease on this file, then we hold it on this filp + * (otherwise our open of this file would have blocked). + * And if we are trying to acquire an exclusive lease, + * then the file is not open by anyone (including us) + * except for this filp. + */ + for (before = &inode->i_flock; + ((fl = *before) != NULL) && (fl->fl_flags & FL_LEASE); + before = &fl->fl_next) { if (fl->fl_file == filp) my_before = before; - else if (fl->fl_type & F_WRLCK) + else if (fl->fl_type == (F_INPROGRESS | F_UNLCK)) + /* + * Someone is in the process of opening this + * file for writing so we may not take an + * exclusive lease on it. + */ wrlease_count++; else rdlease_count++; - before = &fl->fl_next; } if ((arg == F_RDLCK && (wrlease_count > 0)) || - (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) { - error = -EAGAIN; + (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) goto out_unlock; - } if (my_before != NULL) { - error = lease_modify(my_before, arg, fd, filp); + error = lease_modify(my_before, arg); goto out_unlock; } - if (arg == F_UNLCK) { - error = 0; + error = 0; + if (arg == F_UNLCK) goto out_unlock; - } - if (!leases_enable) { - error = -EINVAL; + error = -EINVAL; + if (!leases_enable) goto out_unlock; - } error = lease_alloc(filp, arg, &fl); if (error) @@ -1710,10 +1775,15 @@ before = &inode->i_flock; while ((fl = *before) != NULL) { - if ((fl->fl_flags & (FL_FLOCK|FL_LEASE)) - && (fl->fl_file == filp)) { - locks_delete_lock(before, 0); - continue; + if (fl->fl_file == filp) { + if (fl->fl_flags & FL_FLOCK) { + locks_delete_lock(before, 0); + continue; + } + if (fl->fl_flags & FL_LEASE) { + lease_modify(before, F_UNLCK); + continue; + } } before = &fl->fl_next; } @@ -1769,7 +1839,13 @@ #endif out += sprintf(out, "FLOCK ADVISORY "); } else if (fl->fl_flags & FL_LEASE) { - out += sprintf(out, "LEASE MANDATORY "); + out += sprintf(out, "LEASE "); + if (fl->fl_type & F_INPROGRESS) + out += sprintf(out, "BREAKING "); + else if (fl->fl_file) + out += sprintf(out, "ACTIVE "); + else + out += sprintf(out, "BREAKER "); } else { out += sprintf(out, "UNKNOWN UNKNOWN "); } @@ -1782,7 +1858,9 @@ } else #endif out += sprintf(out, "%s ", - (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); + (fl->fl_type & F_INPROGRESS) + ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " + : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); out += sprintf(out, "%d %s:%ld ", fl->fl_pid, inode ? kdevname(inode->i_dev) : "", @@ -1940,7 +2018,7 @@ static int __init filelock_init(void) { - filelock_cache = kmem_cache_create("file lock cache", + filelock_cache = kmem_cache_create("file_lock_cache", sizeof(struct file_lock), 0, 0, init_once, NULL); if (!filelock_cache) panic("cannot create file lock slab cache"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/Makefile linux.20pre2-ac1/fs/Makefile --- linux.20pre2/fs/Makefile 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/Makefile 2002-08-06 15:41:51.000000000 +0100 @@ -7,20 +7,19 @@ O_TARGET := fs.o -export-objs := filesystems.o open.o dcache.o buffer.o +export-objs := filesystems.o open.o dcache.o buffer.o dquot.o mod-subdirs := nls obj-y := open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \ fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \ dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \ - filesystems.o namespace.o seq_file.o + filesystems.o namespace.o seq_file.o quota.o -ifeq ($(CONFIG_QUOTA),y) -obj-y += dquot.o -else -obj-y += noquot.o -endif + +obj-$(CONFIG_QUOTA) += dquot.o +obj-$(CONFIG_QFMT_V1) += quota_v1.o +obj-$(CONFIG_QFMT_V2) += quota_v2.o subdir-$(CONFIG_PROC_FS) += proc subdir-y += partitions @@ -66,9 +65,12 @@ subdir-$(CONFIG_REISERFS_FS) += reiserfs subdir-$(CONFIG_DEVPTS_FS) += devpts subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs +subdir-$(CONFIG_BEFS_FS) += befs +subdir-$(CONFIG_JFS_FS) += jfs obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o +obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/namei.c linux.20pre2-ac1/fs/namei.c --- linux.20pre2/fs/namei.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/namei.c 2002-08-06 15:41:51.000000000 +0100 @@ -739,6 +739,16 @@ } /* SMP-safe */ +int path_lookup(const char *path, unsigned flags, struct nameidata *nd) +{ + int error = 0; + if (path_init(path, flags, nd)) + error = path_walk(path, nd); + return error; +} + + +/* SMP-safe */ int path_init(const char *name, unsigned int flags, struct nameidata *nd) { nd->last_type = LAST_ROOT; /* if there are only slashes... */ @@ -844,8 +854,7 @@ err = PTR_ERR(tmp); if (!IS_ERR(tmp)) { err = 0; - if (path_init(tmp, flags, nd)) - err = path_walk(tmp, nd); + err = path_lookup(tmp, flags, nd); putname(tmp); } return err; @@ -1001,8 +1010,7 @@ * The simplest case - just a plain lookup. */ if (!(flag & O_CREAT)) { - if (path_init(pathname, lookup_flags(flag), nd)) - error = path_walk(pathname, nd); + error = path_lookup(pathname, lookup_flags(flag), nd); if (error) return error; dentry = nd->dentry; @@ -1012,8 +1020,7 @@ /* * Create - we need to know the parent. */ - if (path_init(pathname, LOOKUP_PARENT, nd)) - error = path_walk(pathname, nd); + error = path_lookup(pathname, LOOKUP_PARENT, nd); if (error) return error; @@ -1265,8 +1272,7 @@ if (IS_ERR(tmp)) return PTR_ERR(tmp); - if (path_init(tmp, LOOKUP_PARENT, &nd)) - error = path_walk(tmp, &nd); + error = path_lookup(tmp, LOOKUP_PARENT, &nd); if (error) goto out; dentry = lookup_create(&nd, 0); @@ -1334,8 +1340,7 @@ struct dentry *dentry; struct nameidata nd; - if (path_init(tmp, LOOKUP_PARENT, &nd)) - error = path_walk(tmp, &nd); + error = path_lookup(tmp, LOOKUP_PARENT, &nd); if (error) goto out; dentry = lookup_create(&nd, 1); @@ -1431,8 +1436,7 @@ if(IS_ERR(name)) return PTR_ERR(name); - if (path_init(name, LOOKUP_PARENT, &nd)) - error = path_walk(name, &nd); + error = path_lookup(name, LOOKUP_PARENT, &nd); if (error) goto exit; @@ -1500,8 +1504,7 @@ if(IS_ERR(name)) return PTR_ERR(name); - if (path_init(name, LOOKUP_PARENT, &nd)) - error = path_walk(name, &nd); + error = path_lookup(name, LOOKUP_PARENT, &nd); if (error) goto exit; error = -EISDIR; @@ -1572,8 +1575,7 @@ struct dentry *dentry; struct nameidata nd; - if (path_init(to, LOOKUP_PARENT, &nd)) - error = path_walk(to, &nd); + error = path_lookup(to, LOOKUP_PARENT, &nd); if (error) goto out; dentry = lookup_create(&nd, 0); @@ -1643,25 +1645,18 @@ asmlinkage long sys_link(const char * oldname, const char * newname) { int error; - char * from; char * to; - from = getname(oldname); - if(IS_ERR(from)) - return PTR_ERR(from); to = getname(newname); error = PTR_ERR(to); if (!IS_ERR(to)) { struct dentry *new_dentry; struct nameidata nd, old_nd; - error = 0; - if (path_init(from, LOOKUP_POSITIVE, &old_nd)) - error = path_walk(from, &old_nd); + error = __user_walk(oldname, LOOKUP_POSITIVE, &old_nd); if (error) goto exit; - if (path_init(to, LOOKUP_PARENT, &nd)) - error = path_walk(to, &nd); + error = path_lookup(to, LOOKUP_PARENT, &nd); if (error) goto out; error = -EXDEV; @@ -1681,8 +1676,6 @@ exit: putname(to); } - putname(from); - return error; } @@ -1859,14 +1852,11 @@ struct dentry * old_dentry, *new_dentry; struct nameidata oldnd, newnd; - if (path_init(oldname, LOOKUP_PARENT, &oldnd)) - error = path_walk(oldname, &oldnd); - + error = path_lookup(oldname, LOOKUP_PARENT, &oldnd); if (error) goto exit; - if (path_init(newname, LOOKUP_PARENT, &newnd)) - error = path_walk(newname, &newnd); + error = path_lookup(newname, LOOKUP_PARENT, &newnd); if (error) goto exit1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/namespace.c linux.20pre2-ac1/fs/namespace.c --- linux.20pre2/fs/namespace.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/namespace.c 2002-08-06 15:41:51.000000000 +0100 @@ -29,8 +29,6 @@ static int hash_mask, hash_bits; static kmem_cache_t *mnt_cache; -extern void init_rootfs(void); - static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES); @@ -361,17 +359,9 @@ asmlinkage long sys_umount(char * name, int flags) { struct nameidata nd; - char *kname; int retval; - kname = getname(name); - retval = PTR_ERR(kname); - if (IS_ERR(kname)) - goto out; - retval = 0; - if (path_init(kname, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd)) - retval = path_walk(kname, &nd); - putname(kname); + retval = __user_walk(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd); if (retval) goto out; retval = -EINVAL; @@ -498,8 +488,7 @@ return err; if (!old_name || !*old_name) return -EINVAL; - if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd)) - err = path_walk(old_name, &old_nd); + err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd); if (err) return err; @@ -565,8 +554,7 @@ return -EPERM; if (!old_name || !*old_name) return -EINVAL; - if (path_init(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd)) - err = path_walk(old_name, &old_nd); + err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd); if (err) return err; @@ -732,8 +720,7 @@ flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV); /* ... and get the mountpoint */ - if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) - retval = path_walk(dir_name, &nd); + retval = path_lookup(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd); if (retval) return retval; @@ -912,7 +899,6 @@ { struct vfsmount *tmp; struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd; - char *name; int error; if (!capable(CAP_SYS_ADMIN)) @@ -920,28 +906,14 @@ lock_kernel(); - name = getname(new_root); - error = PTR_ERR(name); - if (IS_ERR(name)) - goto out0; - error = 0; - if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd)) - error = path_walk(name, &new_nd); - putname(name); + error = __user_walk(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd); if (error) goto out0; error = -EINVAL; if (!check_mnt(new_nd.mnt)) goto out1; - name = getname(put_old); - error = PTR_ERR(name); - if (IS_ERR(name)) - goto out1; - error = 0; - if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd)) - error = path_walk(name, &old_nd); - putname(name); + error = __user_walk(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd); if (error) goto out1; @@ -1037,6 +1009,7 @@ set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); } +extern int init_rootfs(void) __init; void __init mnt_init(unsigned long mempages) { struct list_head *d; @@ -1049,15 +1022,10 @@ if (!mnt_cache) panic("Cannot create vfsmount cache"); - mempages >>= (16 - PAGE_SHIFT); - mempages *= sizeof(struct list_head); - for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++) - ; - - do { - mount_hashtable = (struct list_head *) - __get_free_pages(GFP_ATOMIC, order); - } while (mount_hashtable == NULL && --order >= 0); + /* using single pointer list heads would save half of the hash table. */ + order = 0; + mount_hashtable = (struct list_head *) + __get_free_pages(GFP_ATOMIC, order); if (!mount_hashtable) panic("Failed to allocate mount hash table\n"); @@ -1081,8 +1049,9 @@ nr_hash = 1UL << hash_bits; hash_mask = nr_hash-1; - printk("Mount-cache hash table entries: %d (order: %ld, %ld bytes)\n", - nr_hash, order, (PAGE_SIZE << order)); + printk(KERN_INFO "Mount cache hash table entries: %d" + " (order: %ld, %ld bytes)\n", + nr_hash, order, (PAGE_SIZE << order)); /* And initialize the newly allocated array */ d = mount_hashtable; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nfs/dir.c linux.20pre2-ac1/fs/nfs/dir.c --- linux.20pre2/fs/nfs/dir.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/nfs/dir.c 2002-08-13 17:26:46.000000000 +0100 @@ -45,12 +45,14 @@ static int nfs_mknod(struct inode *, struct dentry *, int, int); static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +static int nfs_fsync_dir(struct file *, struct dentry *, int); struct file_operations nfs_dir_operations = { read: generic_read_dir, readdir: nfs_readdir, open: nfs_open, release: nfs_release, + fsync: nfs_fsync_dir }; struct inode_operations nfs_dir_inode_operations = { @@ -402,6 +404,15 @@ } /* + * All directory operations under NFS are synchronous, so fsync() + * is a dummy operation. + */ +int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) +{ + return 0; +} + +/* * A check for whether or not the parent directory has changed. * In the case it has, we assume that the dentries are untrustworthy * and may need to be looked up again. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nfs/pagelist.c linux.20pre2-ac1/fs/nfs/pagelist.c --- linux.20pre2/fs/nfs/pagelist.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/nfs/pagelist.c 2002-08-06 15:41:51.000000000 +0100 @@ -96,8 +96,7 @@ continue; if (signalled() && (server->flags & NFS_MOUNT_INTR)) return ERR_PTR(-ERESTARTSYS); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } /* Initialize the request struct. Initially, we assume a diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nfsd/lockd.c linux.20pre2-ac1/fs/nfsd/lockd.c --- linux.20pre2/fs/nfsd/lockd.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/nfsd/lockd.c 2002-08-06 15:41:51.000000000 +0100 @@ -62,7 +62,7 @@ struct nlmsvc_binding nfsd_nlm_ops = { exp_readlock, /* lock export table for reading */ - exp_unlock, /* unlock export table */ + exp_readunlock, /* unlock export table */ exp_getclient, /* look up NFS client */ nlm_fopen, /* open file for locking */ nlm_fclose, /* close file */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nfsd/nfscache.c linux.20pre2-ac1/fs/nfsd/nfscache.c --- linux.20pre2/fs/nfsd/nfscache.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/nfsd/nfscache.c 2002-08-06 15:41:51.000000000 +0100 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,13 @@ static int nfsd_cache_append(struct svc_rqst *rqstp, struct svc_buf *data); +/* + * locking for the reply cache: + * A cache entry is "single use" if c_state == RC_INPROG + * Otherwise, it when accessing _prev or _next, the lock must be held. + */ +static spinlock_t cache_lock = SPIN_LOCK_UNLOCKED; + void nfsd_cache_init(void) { @@ -171,6 +179,7 @@ vers = rqstp->rq_vers, proc = rqstp->rq_proc; unsigned long age; + int rtn; rqstp->rq_cacherep = NULL; if (cache_disabled || type == RC_NOCACHE) { @@ -178,6 +187,9 @@ return RC_DOIT; } + spin_lock(&cache_lock); + rtn = RC_DOIT; + rp = rh = (struct svc_cacherep *) &hash_list[REQHASH(xid)]; while ((rp = rp->c_hash_next) != rh) { if (rp->c_state != RC_UNUSED && @@ -200,7 +212,7 @@ if (safe++ > CACHESIZE) { printk("nfsd: loop in repcache LRU list\n"); cache_disabled = 1; - return RC_DOIT; + goto out; } } } @@ -214,7 +226,7 @@ printk(KERN_WARNING "nfsd: disabling repcache.\n"); cache_disabled = 1; } - return RC_DOIT; + goto out; } rqstp->rq_cacherep = rp; @@ -234,8 +246,9 @@ rp->c_replbuf.buf = NULL; } rp->c_type = RC_NOCACHE; - - return RC_DOIT; + out: + spin_unlock(&cache_lock); + return rtn; found_entry: /* We found a matching entry which is either in progress or done. */ @@ -243,33 +256,36 @@ rp->c_timestamp = jiffies; lru_put_front(rp); + rtn = RC_DROPIT; /* Request being processed or excessive rexmits */ if (rp->c_state == RC_INPROG || age < RC_DELAY) - return RC_DROPIT; + goto out; /* From the hall of fame of impractical attacks: * Is this a user who tries to snoop on the cache? */ + rtn = RC_DOIT; if (!rqstp->rq_secure && rp->c_secure) - return RC_DOIT; + goto out; /* Compose RPC reply header */ switch (rp->c_type) { case RC_NOCACHE: - return RC_DOIT; + break; case RC_REPLSTAT: svc_putlong(&rqstp->rq_resbuf, rp->c_replstat); + rtn = RC_REPLY; break; case RC_REPLBUFF: if (!nfsd_cache_append(rqstp, &rp->c_replbuf)) - return RC_DOIT; /* should not happen */ + goto out; /* should not happen */ + rtn = RC_REPLY; break; default: printk(KERN_WARNING "nfsd: bad repcache type %d\n", rp->c_type); rp->c_state = RC_UNUSED; - return RC_DOIT; } - return RC_REPLY; + goto out; } /* @@ -316,20 +332,22 @@ cachp = &rp->c_replbuf; cachp->buf = (u32 *) kmalloc(len << 2, GFP_KERNEL); if (!cachp->buf) { + spin_lock(&cache_lock); rp->c_state = RC_UNUSED; + spin_unlock(&cache_lock); return; } cachp->len = len; memcpy(cachp->buf, statp, len << 2); break; } - + spin_lock(&cache_lock); lru_put_front(rp); rp->c_secure = rqstp->rq_secure; rp->c_type = cachetype; rp->c_state = RC_DONE; rp->c_timestamp = jiffies; - + spin_unlock(&cache_lock); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nfsd/nfsctl.c linux.20pre2-ac1/fs/nfsd/nfsctl.c --- linux.20pre2/fs/nfsd/nfsctl.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/nfsd/nfsctl.c 2002-08-13 17:27:22.000000000 +0100 @@ -123,7 +123,7 @@ err = -EPERM; else err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen); - exp_unlock(); + exp_readunlock(); return err; } @@ -146,7 +146,7 @@ err = -EPERM; else err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE); - exp_unlock(); + exp_readunlock(); if (err == 0) { if (fh.fh_size > NFS_FHSIZE) @@ -179,7 +179,7 @@ err = -EPERM; else err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, &fh, NFS_FHSIZE); - exp_unlock(); + exp_readunlock(); if (err == 0) { if (fh.fh_size > NFS_FHSIZE) @@ -222,7 +222,6 @@ int err; int argsize, respsize; - lock_kernel (); err = -EPERM; if (!capable(CAP_SYS_ADMIN)) { @@ -295,7 +294,6 @@ if (res) kfree(res); - unlock_kernel (); return err; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nfsd/nfsfh.c linux.20pre2-ac1/fs/nfsd/nfsfh.c --- linux.20pre2/fs/nfsd/nfsfh.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/nfsd/nfsfh.c 2002-08-06 15:41:51.000000000 +0100 @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -428,6 +429,7 @@ */ dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,datap[0]); + lock_kernel(); if (!S_ISDIR(result->d_inode->i_mode)) { nfsdstats.fh_nocache_nondir++; /* need to iget dirino and make sure this inode is in that directory */ @@ -496,6 +498,7 @@ dput(dentry); dput(result); /* this will discard the whole free path, so we can up the semaphore */ up(&sb->s_nfsd_free_path_sem); + unlock_kernel(); goto retry; } dput(dentry); @@ -503,6 +506,7 @@ } dput(dentry); up(&sb->s_nfsd_free_path_sem); + unlock_kernel(); return result; err_dentry: @@ -510,6 +514,7 @@ err_result: dput(result); up(&sb->s_nfsd_free_path_sem); + unlock_kernel(); err_out: if (err == -ESTALE) nfsdstats.fh_stale++; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nfsd/nfssvc.c linux.20pre2-ac1/fs/nfsd/nfssvc.c --- linux.20pre2/fs/nfsd/nfssvc.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/nfsd/nfssvc.c 2002-08-06 15:41:51.000000000 +0100 @@ -54,8 +54,9 @@ static void nfsd(struct svc_rqst *rqstp); struct timeval nfssvc_boot; static struct svc_serv *nfsd_serv; -static int nfsd_busy; +static atomic_t nfsd_busy; static unsigned long nfsd_last_call; +static spinlock_t nfsd_call_lock = SPIN_LOCK_UNLOCKED; struct nfsd_list { struct list_head list; @@ -74,7 +75,8 @@ int error; int none_left; struct list_head *victim; - + + lock_kernel(); dprintk("nfsd: creating service\n"); error = -EINVAL; if (nrservs <= 0) @@ -87,7 +89,7 @@ if (error<0) goto out; if (!nfsd_serv) { - error = -ENOMEM; + atomic_set(&nfsd_busy, 0); nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE); if (nfsd_serv == NULL) goto out; @@ -95,7 +97,7 @@ if (error < 0) goto failure; -#if 0 /* Don't even pretend that TCP works. It doesn't. */ +#if CONFIG_NFSD_TCP error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); if (error < 0) goto failure; @@ -126,6 +128,7 @@ nfsd_racache_shutdown(); } out: + unlock_kernel(); return error; } @@ -136,6 +139,7 @@ unsigned long diff; int decile; + spin_lock(&nfsd_call_lock); prev_call = nfsd_last_call; nfsd_last_call = jiffies; decile = busy_threads*10/nfsdstats.th_cnt; @@ -146,6 +150,7 @@ if (decile == 10) nfsdstats.th_fullcnt++; } + spin_unlock(&nfsd_call_lock); } /* @@ -174,6 +179,7 @@ me.task = current; list_add(&me.list, &nfsd_list); + unlock_kernel(); /* * The main request loop */ @@ -193,8 +199,8 @@ ; if (err < 0) break; - update_thread_usage(nfsd_busy); - nfsd_busy++; + update_thread_usage(atomic_read(&nfsd_busy)); + atomic_inc(&nfsd_busy); /* Lock the export hash tables for reading. */ exp_readlock(); @@ -212,9 +218,9 @@ svc_process(serv, rqstp); /* Unlock export hash tables */ - exp_unlock(); - update_thread_usage(nfsd_busy); - nfsd_busy--; + exp_readunlock(); + update_thread_usage(atomic_read(&nfsd_busy)); + atomic_dec(&nfsd_busy); } if (err != -EINTR) { @@ -229,6 +235,8 @@ err = signo; } + lock_kernel(); + /* Release lockd */ lockd_down(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nfsd/vfs.c linux.20pre2-ac1/fs/nfsd/vfs.c --- linux.20pre2/fs/nfsd/vfs.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/nfsd/vfs.c 2002-08-06 15:41:51.000000000 +0100 @@ -548,12 +548,15 @@ * Obtain the readahead parameters for the file * specified by (dev, ino). */ +static spinlock_t ra_lock = SPIN_LOCK_UNLOCKED; + static inline struct raparms * nfsd_get_raparms(dev_t dev, ino_t ino) { struct raparms *ra, **rap, **frap = NULL; int depth = 0; - + + spin_lock(&ra_lock); for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) { if (ra->p_ino == ino && ra->p_dev == dev) goto found; @@ -562,8 +565,10 @@ frap = rap; } depth = nfsdstats.ra_size*11/10; - if (!frap) + if (!frap) { + spin_unlock(&ra_lock); return NULL; + } rap = frap; ra = *frap; ra->p_dev = dev; @@ -581,6 +586,7 @@ } ra->p_count++; nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; + spin_unlock(&ra_lock); return ra; } @@ -1284,6 +1290,7 @@ goto out_dput_old; + lock_kernel(); #ifdef MSNFS if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && ((atomic_read(&odentry->d_count) > 1) @@ -1292,6 +1299,7 @@ } else #endif err = vfs_rename(fdir, odentry, tdir, ndentry); + unlock_kernel(); if (!err && EX_ISSYNC(tfhp->fh_export)) { nfsd_sync_dir(tdentry); nfsd_sync_dir(fdentry); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nls/Makefile linux.20pre2-ac1/fs/nls/Makefile --- linux.20pre2/fs/nls/Makefile 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/nls/Makefile 2002-08-06 15:41:51.000000000 +0100 @@ -29,12 +29,6 @@ obj-$(CONFIG_NLS_CODEPAGE_950) += nls_cp950.o nls_big5.o obj-$(CONFIG_NLS_CODEPAGE_1250) += nls_cp1250.o obj-$(CONFIG_NLS_CODEPAGE_1251) += nls_cp1251.o -obj-$(CONFIG_NLS_CODEPAGE_1252) += nls_cp1252.o -obj-$(CONFIG_NLS_CODEPAGE_1253) += nls_cp1253.o -obj-$(CONFIG_NLS_CODEPAGE_1254) += nls_cp1254.o -obj-$(CONFIG_NLS_CODEPAGE_1256) += nls_cp1256.o -obj-$(CONFIG_NLS_CODEPAGE_1257) += nls_cp1257.o -obj-$(CONFIG_NLS_CODEPAGE_1258) += nls_cp1258.o obj-$(CONFIG_NLS_ISO8859_1) += nls_iso8859-1.o obj-$(CONFIG_NLS_ISO8859_2) += nls_iso8859-2.o obj-$(CONFIG_NLS_ISO8859_3) += nls_iso8859-3.o @@ -44,13 +38,11 @@ obj-$(CONFIG_NLS_ISO8859_7) += nls_iso8859-7.o obj-$(CONFIG_NLS_ISO8859_8) += nls_cp1255.o nls_iso8859-8.o obj-$(CONFIG_NLS_ISO8859_9) += nls_iso8859-9.o -obj-$(CONFIG_NLS_ISO8859_10) += nls_iso8859-10.o obj-$(CONFIG_NLS_ISO8859_13) += nls_iso8859-13.o obj-$(CONFIG_NLS_ISO8859_14) += nls_iso8859-14.o obj-$(CONFIG_NLS_ISO8859_15) += nls_iso8859-15.o obj-$(CONFIG_NLS_KOI8_R) += nls_koi8-r.o obj-$(CONFIG_NLS_KOI8_U) += nls_koi8-u.o nls_koi8-ru.o -obj-$(CONFIG_NLS_ABC) += nls_abc.o obj-$(CONFIG_NLS_UTF8) += nls_utf8.o export-objs = $(obj-y) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/nls/nls_cp1250.c linux.20pre2-ac1/fs/nls/nls_cp1250.c --- linux.20pre2/fs/nls/nls_cp1250.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/nls/nls_cp1250.c 2002-08-06 15:41:51.000000000 +0100 @@ -344,7 +344,7 @@ module_init(init_nls_cp1250) module_exit(exit_nls_cp1250) -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/noquot.c linux.20pre2-ac1/fs/noquot.c --- linux.20pre2/fs/noquot.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/noquot.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,15 +0,0 @@ -/* noquot.c: Quota stubs necessary for when quotas are not - * compiled into the kernel. - */ - -#include -#include -#include - -int nr_dquots, nr_free_dquots; -int max_dquots; - -asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) -{ - return(-ENOSYS); -} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/open.c linux.20pre2-ac1/fs/open.c --- linux.20pre2/fs/open.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/open.c 2002-08-06 15:41:51.000000000 +0100 @@ -385,17 +385,8 @@ { int error; struct nameidata nd; - char *name; - name = getname(filename); - error = PTR_ERR(name); - if (IS_ERR(name)) - goto out; - - error = 0; - if (path_init(name,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd)) - error = path_walk(name, &nd); - putname(name); + error = __user_walk(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd); if (error) goto out; @@ -445,17 +436,9 @@ { int error; struct nameidata nd; - char *name; - - name = getname(filename); - error = PTR_ERR(name); - if (IS_ERR(name)) - goto out; - path_init(name, LOOKUP_POSITIVE | LOOKUP_FOLLOW | + error = __user_walk(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd); - error = path_walk(name, &nd); - putname(name); if (error) goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/partitions/ldm.c linux.20pre2-ac1/fs/partitions/ldm.c --- linux.20pre2/fs/partitions/ldm.c 2002-08-13 13:58:15.000000000 +0100 +++ linux.20pre2-ac1/fs/partitions/ldm.c 2002-08-11 21:08:42.000000000 +0100 @@ -1,1074 +1,1543 @@ -/* - * ldm - Part of the Linux-NTFS project. +/** + * ldm - Support for Windows Logical Disk Manager (Dynamic Disks) * - * Copyright (C) 2001 Richard Russon - * Copyright (C) 2001 Anton Altaparmakov (AIA) + * Copyright (C) 2001,2002 Richard Russon + * Copyright (C) 2001 Anton Altaparmakov + * Copyright (C) 2001,2002 Jakob Kemi * * Documentation is available at http://linux-ntfs.sf.net/ldm * - * 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 (in the main directory of the Linux-NTFS source - * in the file COPYING); if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * 28/10/2001 - Added sorting of ldm partitions. (AIA) - */ -#include -#include -#include -#include -#include + * 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 (in the main directory of the source in the file COPYING); if + * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + #include +#include #include -#include "check.h" #include "ldm.h" +#include "check.h" #include "msdos.h" -#if 0 /* Fool kernel-doc since it doesn't do macros yet. */ +typedef enum { + FALSE = 0, + TRUE = 1 +} BOOL; + /** - * ldm_debug - output an error message if debugging was enabled at compile time - * @f: a printf format string containing the message - * @...: the variables to substitute into @f + * ldm_debug/info/error/crit - Output an error message + * @f: A printf format string containing the message + * @...: Variables to substitute into @f * * ldm_debug() writes a DEBUG level message to the syslog but only if the * driver was compiled with debug enabled. Otherwise, the call turns into a NOP. */ -static void ldm_debug(const char *f, ...); +#ifndef CONFIG_LDM_DEBUG +#define ldm_debug(...) do {} while (0) +#else +#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __FUNCTION__, f, ##a) #endif -#ifdef CONFIG_LDM_DEBUG -#define ldm_debug(f, a...) \ - { \ - printk(LDM_DEBUG " DEBUG (%s, %d): %s: ", \ - __FILE__, __LINE__, __FUNCTION__); \ - printk(f, ##a); \ - } -#else /* !CONFIG_LDM_DEBUG */ -#define ldm_debug(f, a...) do {} while (0) -#endif /* !CONFIG_LDM_DEBUG */ -/* Necessary forward declarations. */ -static int create_partition(struct gendisk *, int, int, int); -static int parse_privhead(const u8 *, struct privhead *); -static u64 get_vnum(const u8 *, int *); -static int get_vstr(const u8 *, u8 *, const int); +#define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __FUNCTION__, f, ##a) +#define ldm_error(f, a...) _ldm_printk (KERN_ERR, __FUNCTION__, f, ##a) +#define ldm_info(f, a...) _ldm_printk (KERN_INFO, __FUNCTION__, f, ##a) + +__attribute__ ((format (printf, 3, 4))) +static void _ldm_printk (const char *level, const char *function, + const char *fmt, ...) +{ + static char buf[128]; + va_list args; + + va_start (args, fmt); + vsnprintf (buf, sizeof (buf), fmt, args); + va_end (args); + + printk ("%s%s(): %s\n", level, function, buf); +} + /** - * parse_vblk_part - parse a LDM database vblk partition record - * @buffer: vblk partition record loaded from the LDM database - * @buf_size: size of @buffer in bytes - * @vb: in memory vblk structure to return parsed information in + * ldm_parse_hexbyte - Convert a ASCII hex number to a byte + * @src: Pointer to at least 2 characters to convert. * - * This parses the LDM database vblk record of type VBLK_PART, i.e. a partition - * record, supplied in @buffer and sets up the in memory vblk structure @vb - * with the obtained information. + * Convert a two character ASCII hex string to a number. * - * Return 1 on success and -1 on error, in which case @vb is undefined. + * Return: 0-255 Success, the byte was parsed correctly + * -1 Error, an invalid character was supplied */ -static int parse_vblk_part(const u8 *buffer, const int buf_size, - struct vblk *vb) +static int ldm_parse_hexbyte (const u8 *src) { - int err, rel_objid, rel_name, rel_size, rel_parent; + unsigned int x; /* For correct wrapping */ + int h; - if (0x34 >= buf_size) - return -1; - /* Calculate relative offsets. */ - rel_objid = 1 + buffer[0x18]; - if (0x18 + rel_objid >= buf_size) - return -1; - rel_name = 1 + buffer[0x18 + rel_objid] + rel_objid; - if (0x34 + rel_name >= buf_size) - return -1; - rel_size = 1 + buffer[0x34 + rel_name] + rel_name; - if (0x34 + rel_size >= buf_size) - return -1; - rel_parent = 1 + buffer[0x34 + rel_size] + rel_size; - if (0x34 + rel_parent >= buf_size) - return -1; - /* Setup @vb. */ - vb->vblk_type = VBLK_PART; - vb->obj_id = get_vnum(buffer + 0x18, &err); - if (err || 0x34 + rel_parent + buffer[0x34 + rel_parent] >= buf_size) - return -1; - vb->disk_id = get_vnum(buffer + 0x34 + rel_parent, &err); - if (err || 0x24 + rel_name + 8 > buf_size) - return -1; - vb->start_sector = BE64(buffer + 0x24 + rel_name); - if (0x34 + rel_name + buffer[0x34 + rel_name] >= buf_size) - return -1; - vb->num_sectors = get_vnum(buffer + 0x34 + rel_name, &err); - if (err || 0x18 + rel_objid + buffer[0x18 + rel_objid] >= buf_size) - return -1; - err = get_vstr(buffer + 0x18 + rel_objid, vb->name, sizeof(vb->name)); - if (err == -1) - return err; - ldm_debug("Parsed Partition VBLK successfully.\n"); - return 1; + /* high part */ + if ((x = src[0] - '0') <= '9'-'0') h = x; + else if ((x = src[0] - 'a') <= 'f'-'a') h = x+10; + else if ((x = src[0] - 'A') <= 'F'-'A') h = x+10; + else return -1; + h <<= 4; + + /* low part */ + if ((x = src[1] - '0') <= '9'-'0') return h | x; + if ((x = src[1] - 'a') <= 'f'-'a') return h | (x+10); + if ((x = src[1] - 'A') <= 'F'-'A') return h | (x+10); + return -1; } /** - * parse_vblk - parse a LDM database vblk record - * @buffer: vblk record loaded from the LDM database - * @buf_size: size of @buffer in bytes - * @vb: in memory vblk structure to return parsed information in + * ldm_parse_guid - Convert GUID from ASCII to binary + * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba + * @dest: Memory block to hold binary GUID (16 bytes) + * + * N.B. The GUID need not be NULL terminated. * - * This parses the LDM database vblk record supplied in @buffer and sets up - * the in memory vblk structure @vb with the obtained information. + * Return: TRUE @dest contains binary GUID + * FALSE @dest contents are undefined + */ +static BOOL ldm_parse_guid (const u8 *src, u8 *dest) +{ + static const int size[] = { 4, 2, 2, 2, 6 }; + int i, j, v; + + if (src[8] != '-' || src[13] != '-' || + src[18] != '-' || src[23] != '-') + return FALSE; + + for (j = 0; j < 5; j++, src++) + for (i = 0; i < size[j]; i++, src+=2, *dest++ = v) + if ((v = ldm_parse_hexbyte (src)) < 0) + return FALSE; + + return TRUE; +} + + +/** + * ldm_parse_privhead - Read the LDM Database PRIVHEAD structure + * @data: Raw database PRIVHEAD structure loaded from the device + * @ph: In-memory privhead structure in which to return parsed information * - * Return 1 on success, 0 if successful but record not in use, and -1 on error. - * If the return value is 0 or -1, @vb is undefined. + * This parses the LDM database PRIVHEAD structure supplied in @data and + * sets up the in-memory privhead structure @ph with the obtained information. * - * NOTE: Currently the only record type we handle is VBLK_PART, i.e. records - * describing a partition. For all others, we just set @vb->vblk_type to 0 and - * return success. This of course means that if @vb->vblk_type is zero, all - * other fields in @vb are undefined. + * Return: TRUE @ph contains the PRIVHEAD data + * FALSE @ph contents are undefined */ -static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb) +static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph) { - int err = 1; + BUG_ON (!data); + BUG_ON (!ph); - if (buf_size < 0x14) - return -1; - if (MAGIC_VBLK != BE32(buffer)) { - printk(LDM_CRIT "Cannot find VBLK, database may be corrupt.\n"); - return -1; + if (MAGIC_PRIVHEAD != BE64 (data)) { + ldm_error ("Cannot find PRIVHEAD structure. LDM database is" + " corrupt. Aborting."); + return FALSE; } - if ((BE16(buffer + 0x0E) == 0) || /* Record is not in use. */ - (BE16(buffer + 0x0C) != 0)) /* Part 2 of an ext. record */ - return 0; - /* FIXME: What about extended VBLKs? */ - switch (buffer[0x13]) { - case VBLK_PART: - err = parse_vblk_part(buffer, buf_size, vb); - break; - default: - vb->vblk_type = 0; + + ph->ver_major = BE16 (data + 0x000C); + ph->ver_minor = BE16 (data + 0x000E); + ph->logical_disk_start = BE64 (data + 0x011B); + ph->logical_disk_size = BE64 (data + 0x0123); + ph->config_start = BE64 (data + 0x012B); + ph->config_size = BE64 (data + 0x0133); + + if ((ph->ver_major != 2) || (ph->ver_minor != 11)) { + ldm_error ("Expected PRIVHEAD version %d.%d, got %d.%d." + " Aborting.", 2, 11, ph->ver_major, ph->ver_minor); + return FALSE; + } + if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */ + /* Warn the user and continue, carefully */ + ldm_info ("Database is normally %u bytes, it claims to " + "be %llu bytes.", LDM_DB_SIZE, + (unsigned long long)ph->config_size ); + } + if ((ph->logical_disk_size == 0) || + (ph->logical_disk_start + ph->logical_disk_size > ph->config_start)) { + ldm_error ("PRIVHEAD disk size doesn't match real disk size"); + return FALSE; + } + + if (!ldm_parse_guid (data + 0x0030, ph->disk_id)) { + ldm_error ("PRIVHEAD contains an invalid GUID."); + return FALSE; } - if (err != -1) - ldm_debug("Parsed VBLK successfully.\n"); - return err; + + ldm_debug ("Parsed PRIVHEAD successfully."); + return TRUE; } /** - * add_partition_to_list - insert partition into a partition list - * @pl: sorted list of partitions - * @hd: gendisk structure to which the data partition belongs - * @disk_minor: minor number of the disk device - * @start: first sector within the disk device - * @size: number of sectors on the partition device + * ldm_parse_tocblock - Read the LDM Database TOCBLOCK structure + * @data: Raw database TOCBLOCK structure loaded from the device + * @toc: In-memory toc structure in which to return parsed information * - * This sanity checks the partition specified by @start and @size against the - * device specified by @hd and inserts the partition into the sorted partition - * list @pl if the checks pass. + * This parses the LDM Database TOCBLOCK (table of contents) structure supplied + * in @data and sets up the in-memory tocblock structure @toc with the obtained + * information. * - * On success return 1, otherwise return -1. + * N.B. The *_start and *_size values returned in @toc are not range-checked. * - * TODO: Add sanity check for overlapping partitions. (AIA) - */ -static int add_partition_to_list(struct list_head *pl, const struct gendisk *hd, - const int disk_minor, const unsigned long start, - const unsigned long size) + * Return: TRUE @toc contains the TOCBLOCK data + * FALSE @toc contents are undefined + */ +static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc) { - struct ldm_part *lp, *lptmp; - struct list_head *tmp; + BUG_ON (!data); + BUG_ON (!toc); - if (!hd->part) - return -1; - if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) { - printk(LDM_CRIT "LDM partition exceeds physical disk. " - "Skipping.\n"); - return -1; + if (MAGIC_TOCBLOCK != BE64 (data)) { + ldm_crit ("Cannot find TOCBLOCK, database may be corrupt."); + return FALSE; + } + strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name)); + toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0; + toc->bitmap1_start = BE64 (data + 0x2E); + toc->bitmap1_size = BE64 (data + 0x36); + + if (strncmp (toc->bitmap1_name, TOC_BITMAP1, + sizeof (toc->bitmap1_name)) != 0) { + ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.", + TOC_BITMAP1, toc->bitmap1_name); + return FALSE; + } + strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name)); + toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0; + toc->bitmap2_start = BE64 (data + 0x50); + toc->bitmap2_size = BE64 (data + 0x58); + if (strncmp (toc->bitmap2_name, TOC_BITMAP2, + sizeof (toc->bitmap2_name)) != 0) { + ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.", + TOC_BITMAP2, toc->bitmap2_name); + return FALSE; } - lp = (struct ldm_part*)kmalloc(sizeof(struct ldm_part), GFP_KERNEL); - if (!lp) { - printk(LDM_CRIT "Not enough memory! Aborting LDM partition " - "parsing.\n"); - return -2; - } - INIT_LIST_HEAD(&lp->part_list); - lp->start = start; - lp->size = size; - list_for_each(tmp, pl) { - lptmp = list_entry(tmp, struct ldm_part, part_list); - if (start > lptmp->start) - continue; - if (start < lptmp->start) - break; - printk(LDM_CRIT "Duplicate LDM partition entry! Skipping.\n"); - kfree(lp); - return -1; - } - list_add_tail(&lp->part_list, tmp); - ldm_debug("Added LDM partition successfully.\n"); - return 1; + ldm_debug ("Parsed TOCBLOCK successfully."); + return TRUE; } /** - * create_data_partitions - create the data partition devices - * @hd: gendisk structure in which to create the data partitions - * @first_sector: first sector within the disk device - * @first_part_minor: first minor number of data partition devices - * @dev: partition device holding the LDM database - * @vm: in memory vmdb structure of @dev - * @ph: in memory privhead structure of the disk device - * @dk: in memory ldmdisk structure of the disk device + * ldm_parse_vmdb - Read the LDM Database VMDB structure + * @data: Raw database VMDB structure loaded from the device + * @vm: In-memory vmdb structure in which to return parsed information * - * The database contains ALL the partitions for ALL the disks, so we need to - * filter out this specific disk. Using the disk's object id, we can find all - * the partitions in the database that belong to this disk. + * This parses the LDM Database VMDB structure supplied in @data and sets up + * the in-memory vmdb structure @vm with the obtained information. + * + * N.B. The *_start, *_size and *_seq values will be range-checked later. * - * For each found partition, we create a corresponding partition device starting - * with minor number @first_part_minor. But we do this in such a way that we - * actually sort the partitions in order of on-disk position. Any invalid - * partitions are completely ignored/skipped (an error is output but that's - * all). - * - * Return 1 on success and -1 on error. - */ -static int create_data_partitions(struct gendisk *hd, - const unsigned long first_sector, int first_part_minor, - struct block_device *bdev, const struct vmdb *vm, - const struct privhead *ph, const struct ldmdisk *dk, - unsigned long base) + * Return: TRUE @vm contains VMDB info + * FALSE @vm contents are undefined + */ +static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm) { - Sector sect; - unsigned char *data; - struct vblk *vb; - LIST_HEAD(pl); /* Sorted list of partitions. */ - struct ldm_part *lp; - struct list_head *tmp; - int vblk; - int vsize; /* VBLK size. */ - int perbuf; /* VBLKs per buffer. */ - int buffer, lastbuf, lastofs, err, disk_minor; - - vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL); - if (!vb) - goto no_mem; - vsize = vm->vblk_size; - if (vsize < 1 || vsize > 512) - goto err_out; - perbuf = 512 / vsize; - if (perbuf < 1 || 512 % vsize) - goto err_out; - /* 512 == VMDB size */ - lastbuf = vm->last_vblk_seq / perbuf - 1; - lastofs = vm->last_vblk_seq % perbuf; - if (lastofs) - lastbuf++; - if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > - ph->config_size * 512) - goto err_out; - /* - * Get the minor number of the parent device so we can check we don't - * go beyond the end of the device. - */ - disk_minor = (first_part_minor >> hd->minor_shift) << hd->minor_shift; - for (buffer = 0; buffer < lastbuf; buffer++) { - data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); - if (!data) - goto read_err; - for (vblk = 0; vblk < perbuf; vblk++) { - u8 *block; - - if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs) - break; - block = data + vsize * vblk; - if (block + vsize > data + 512) - goto brelse_out; - if (parse_vblk(block, vsize, vb) != 1) - continue; - if (vb->vblk_type != VBLK_PART) - continue; - if (dk->obj_id != vb->disk_id) - continue; - /* Ignore invalid partition errors. */ - if (add_partition_to_list(&pl, hd, disk_minor, - first_sector + vb->start_sector + - ph->logical_disk_start, - vb->num_sectors) < -1) - goto brelse_out; - } - put_dev_sector(sect); + BUG_ON (!data); + BUG_ON (!vm); + + if (MAGIC_VMDB != BE32 (data)) { + ldm_crit ("Cannot find the VMDB, database may be corrupt."); + return FALSE; } - err = 1; -out: - /* Finally create the nicely sorted data partitions. */ - printk(" <"); - list_for_each(tmp, &pl) { - lp = list_entry(tmp, struct ldm_part, part_list); - add_gd_partition(hd, first_part_minor++, lp->start, lp->size); - } - printk(" >\n"); - if (!list_empty(&pl)) { - struct list_head *tmp2; - - /* Cleanup the partition list which is now superfluous. */ - list_for_each_safe(tmp, tmp2, &pl) { - lp = list_entry(tmp, struct ldm_part, part_list); - list_del(tmp); - kfree(lp); - } + + vm->ver_major = BE16 (data + 0x12); + vm->ver_minor = BE16 (data + 0x14); + if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { + ldm_error ("Expected VMDB version %d.%d, got %d.%d. " + "Aborting.", 4, 10, vm->ver_major, vm->ver_minor); + return FALSE; } - kfree(vb); - return err; -brelse_out: - put_dev_sector(sect); - goto err_out; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); - goto err_out; -read_err: - printk(LDM_CRIT "Disk read failed in create_partitions.\n"); -err_out: - err = -1; - goto out; + + vm->vblk_size = BE32 (data + 0x08); + vm->vblk_offset = BE32 (data + 0x0C); + vm->last_vblk_seq = BE32 (data + 0x04); + + ldm_debug ("Parsed VMDB successfully."); + return TRUE; } /** - * get_vnum - convert a variable-width, big endian number, to cpu u64 one - * @block: pointer to the variable-width number to convert - * @err: address of an integer into which to return the error code. - * - * This converts a variable-width, big endian number into a 64-bit, CPU format - * number and returns the result with err set to 0. If an error occurs return 0 - * with err set to -1. + * ldm_compare_privheads - Compare two privhead objects + * @ph1: First privhead + * @ph2: Second privhead * - * The first byte of a variable-width number is the size of the number in bytes. + * This compares the two privhead structures @ph1 and @ph2. + * + * Return: TRUE Identical + * FALSE Different */ -static u64 get_vnum(const u8 *block, int *err) +static BOOL ldm_compare_privheads (const struct privhead *ph1, + const struct privhead *ph2) { - u64 tmp = 0ULL; - u8 length = *block++; + BUG_ON (!ph1); + BUG_ON (!ph2); - if (length && length <= 8) { - while (length--) - tmp = (tmp << 8) | *block++; - *err = 0; - } else { - printk(LDM_ERR "Illegal length in get_vnum(): %d.\n", length); - *err = 1; - } - return tmp; + return ((ph1->ver_major == ph2->ver_major) && + (ph1->ver_minor == ph2->ver_minor) && + (ph1->logical_disk_start == ph2->logical_disk_start) && + (ph1->logical_disk_size == ph2->logical_disk_size) && + (ph1->config_start == ph2->config_start) && + (ph1->config_size == ph2->config_size) && + !memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE)); } /** - * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one - * @block: string to convert - * @buffer: output buffer - * @buflen: size of output buffer + * ldm_compare_tocblocks - Compare two tocblock objects + * @toc1: First toc + * @toc2: Second toc * - * This converts @block, a counted, non-null-terminated ASCII string, into a - * C-style, null-terminated, ASCII string and returns this in @buffer. The - * maximum number of characters converted is given by @buflen. + * This compares the two tocblock structures @toc1 and @toc2. * - * The first bytes of a counted string stores the length of the string in bytes. + * Return: TRUE Identical + * FALSE Different + */ +static BOOL ldm_compare_tocblocks (const struct tocblock *toc1, + const struct tocblock *toc2) +{ + BUG_ON (!toc1); + BUG_ON (!toc2); + + return ((toc1->bitmap1_start == toc2->bitmap1_start) && + (toc1->bitmap1_size == toc2->bitmap1_size) && + (toc1->bitmap2_start == toc2->bitmap2_start) && + (toc1->bitmap2_size == toc2->bitmap2_size) && + !strncmp (toc1->bitmap1_name, toc2->bitmap1_name, + sizeof (toc1->bitmap1_name)) && + !strncmp (toc1->bitmap2_name, toc2->bitmap2_name, + sizeof (toc1->bitmap2_name))); +} + +/** + * ldm_validate_privheads - Compare the primary privhead with its backups + * @bdev: Device holding the LDM Database + * @ph1: Memory struct to fill with ph contents + * + * Read and compare all three privheads from disk. * - * Return the number of characters written to @buffer, not including the - * terminating null character, on success, and -1 on error, in which case - * @buffer is not defined. + * The privheads on disk show the size and location of the main disk area and + * the configuration area (the database). + * + * Return: TRUE Success + * FALSE Error */ -static int get_vstr(const u8 *block, u8 *buffer, const int buflen) +static BOOL ldm_validate_privheads (struct block_device *bdev, + unsigned long first_sector, struct privhead *ph1, struct gendisk *hd, + unsigned long first_minor) { - int length = block[0]; + static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 }; + struct privhead *ph[3] = { ph1 }; + Sector sect; + u8 *data; + BOOL result = FALSE; + long num_sects; + int i; + + BUG_ON (!bdev); + BUG_ON (!ph1); + + ph[1] = kmalloc (sizeof (*ph[1]), GFP_KERNEL); + ph[2] = kmalloc (sizeof (*ph[2]), GFP_KERNEL); + if (!ph[1] || !ph[2]) { + ldm_crit ("Out of memory."); + goto out; + } - if (length < 1) - return -1; - if (length >= buflen) { - printk(LDM_ERR "String too long for buffer in get_vstr(): " - "(%d/%d). Truncating.\n", length, buflen); - length = buflen - 1; + /* off[1 & 2] are relative to ph[0]->config_start */ + ph[0]->config_start = 0; + + /* Read and parse privheads */ + for (i = 0; i < 3; i++) { + data = read_dev_sector (bdev, + first_sector + ph[0]->config_start + off[i], §); + if (!data) { + ldm_crit ("Disk read failed."); + goto out; + } + result = ldm_parse_privhead (data, ph[i]); + put_dev_sector (sect); + if (!result) { + ldm_error ("Cannot find PRIVHEAD %d.", i+1); /* Log again */ + if (i < 2) + goto out; /* Already logged */ + else + break; /* FIXME ignore for now, 3rd PH can fail on odd-sized disks */ + } } - memcpy(buffer, block + 1, length); - buffer[length] = (u8)'\0'; - return length; + + num_sects = hd->part[(first_minor >> hd->minor_shift) + << hd->minor_shift].nr_sects; + + if ((ph[0]->config_start > num_sects) || + ((ph[0]->config_start + ph[0]->config_size) > num_sects)) { + ldm_crit ("Database extends beyond the end of the disk."); + goto out; + } + + if ((ph[0]->logical_disk_start > ph[0]->config_start) || + ((ph[0]->logical_disk_start + ph[0]->logical_disk_size) + > ph[0]->config_start)) { + ldm_crit ("Disk and database overlap."); + goto out; + } + + if (!ldm_compare_privheads (ph[0], ph[1])) { + ldm_crit ("Primary and backup PRIVHEADs don't match."); + goto out; + } + /* FIXME ignore this for now + if (!ldm_compare_privheads (ph[0], ph[2])) { + ldm_crit ("Primary and backup PRIVHEADs don't match."); + goto out; + }*/ + ldm_debug ("Validated PRIVHEADs successfully."); + result = TRUE; +out: + kfree (ph[1]); + kfree (ph[2]); + return result; } /** - * get_disk_objid - obtain the object id for the device we are working on - * @dev: partition device holding the LDM database - * @vm: in memory vmdb structure of the LDM database - * @ph: in memory privhead structure of the device we are working on - * @dk: in memory ldmdisk structure to return information into - * - * This obtains the object id for the device we are working on as defined by - * the private header @ph. The obtained object id, together with the disk's - * GUID from @ph are returned in the ldmdisk structure pointed to by @dk. - * - * A Disk has two Ids. The main one is a GUID in string format. The second, - * used internally for cross-referencing, is a small, sequentially allocated, - * number. The PRIVHEAD, just after the partition table, tells us the disk's - * GUID. To find the disk's object id, we have to look through the database. - * - * Return 1 on success and -1 on error, in which case @dk is undefined. - */ -static int get_disk_objid(struct block_device *bdev, const struct vmdb *vm, - const struct privhead *ph, struct ldmdisk *dk, - unsigned long base) + * ldm_validate_tocblocks - Validate the table of contents and its backups + * @bdev: Device holding the LDM Database + * @base: Offset, into @bdev, of the database + * @ldb: Cache of the database structures + * + * Find and compare the four tables of contents of the LDM Database stored on + * @bdev and return the parsed information into @toc1. + * + * The offsets and sizes of the configs are range-checked against a privhead. + * + * Return: TRUE @toc1 contains validated TOCBLOCK info + * FALSE @toc1 contents are undefined + */ +static BOOL ldm_validate_tocblocks (struct block_device *bdev, + unsigned long base, struct ldmdb *ldb) { + static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4}; + struct tocblock *tb[4]; + struct privhead *ph; Sector sect; - unsigned char *data; - u8 *disk_id; - int vblk; - int vsize; /* VBLK size. */ - int perbuf; /* VBLKs per buffer. */ - int buffer, lastbuf, lastofs, err; - - disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL); - if (!disk_id) - goto no_mem; - vsize = vm->vblk_size; - if (vsize < 1 || vsize > 512) - goto err_out; - perbuf = 512 / vsize; - if (perbuf < 1 || 512 % vsize) - goto err_out; - /* 512 == VMDB size */ - lastbuf = vm->last_vblk_seq / perbuf - 1; - lastofs = vm->last_vblk_seq % perbuf; - if (lastofs) - lastbuf++; - if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > - ph->config_size * 512) - goto err_out; - for (buffer = 0; buffer < lastbuf; buffer++) { - data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); - if (!data) - goto read_err; - for (vblk = 0; vblk < perbuf; vblk++) { - int rel_objid, rel_name, delta; - u8 *block; - - if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs) - break; - block = data + vblk * vsize; - delta = vblk * vsize + 0x18; - if (delta >= 512) - goto brelse_out; - if (block[0x0D] != 0) /* Extended VBLK, ignore */ - continue; - if ((block[0x13] != VBLK_DSK1) && - (block[0x13] != VBLK_DSK2)) - continue; - /* Calculate relative offsets. */ - rel_objid = 1 + block[0x18]; - if (delta + rel_objid >= 512) - goto brelse_out; - rel_name = 1 + block[0x18 + rel_objid] + rel_objid; - if (delta + rel_name >= 512 || - delta + rel_name + block[0x18 + rel_name] >= 512) - goto brelse_out; - err = get_vstr(block + 0x18 + rel_name, disk_id, - DISK_ID_SIZE); - if (err == -1) - goto brelse_out; - if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) { - dk->obj_id = get_vnum(block + 0x18, &err); - put_dev_sector(sect); - if (err) - goto out; - strncpy(dk->disk_id, ph->disk_id, - sizeof(dk->disk_id)); - dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0'; - err = 1; - goto out; - } + u8 *data; + BOOL result = FALSE; + int i; + + BUG_ON (!bdev); + BUG_ON (!ldb); + + ph = &ldb->ph; + tb[0] = &ldb->toc; + tb[1] = kmalloc (sizeof (*tb[1]), GFP_KERNEL); + tb[2] = kmalloc (sizeof (*tb[2]), GFP_KERNEL); + tb[3] = kmalloc (sizeof (*tb[3]), GFP_KERNEL); + if (!tb[1] || !tb[2] || !tb[3]) { + ldm_crit ("Out of memory."); + goto out; + } + + for (i = 0; i < 4; i++) /* Read and parse all four toc's. */ + { + data = read_dev_sector (bdev, base + off[i], §); + if (!data) { + ldm_crit ("Disk read failed."); + goto out; } - put_dev_sector(sect); + result = ldm_parse_tocblock (data, tb[i]); + put_dev_sector (sect); + if (!result) + goto out; /* Already logged */ + } + + /* Range check the toc against a privhead. */ + if (((tb[0]->bitmap1_start + tb[0]->bitmap1_size) > ph->config_size) || + ((tb[0]->bitmap2_start + tb[0]->bitmap2_size) > ph->config_size)) { + ldm_crit ("The bitmaps are out of range. Giving up."); + goto out; + } + + if (!ldm_compare_tocblocks (tb[0], tb[1]) || /* Compare all tocs. */ + !ldm_compare_tocblocks (tb[0], tb[2]) || + !ldm_compare_tocblocks (tb[0], tb[3])) { + ldm_crit ("The TOCBLOCKs don't match."); + goto out; } - err = -1; + + ldm_debug ("Validated TOCBLOCKs successfully."); + result = TRUE; out: - kfree(disk_id); - return err; -brelse_out: - put_dev_sector(sect); - goto err_out; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); - goto err_out; -read_err: - printk(LDM_CRIT "Disk read failed in get_disk_objid.\n"); -err_out: - err = -1; - goto out; + kfree (tb[1]); + kfree (tb[2]); + kfree (tb[3]); + return result; } /** - * parse_vmdb - parse the LDM database vmdb structure - * @buffer: LDM database vmdb structure loaded from the device - * @vm: in memory vmdb structure to return parsed information in - * - * This parses the LDM database vmdb structure supplied in @buffer and sets up - * the in memory vmdb structure @vm with the obtained information. - * - * Return 1 on success and -1 on error, in which case @vm is undefined. + * ldm_validate_vmdb - Read the VMDB and validate it + * @bdev: Device holding the LDM Database + * @base: Offset, into @bdev, of the database + * @ldb: Cache of the database structures + * + * Find the vmdb of the LDM Database stored on @bdev and return the parsed + * information in @ldb. * - * NOTE: The *_start, *_size and *_seq values returned in @vm have not been - * checked for validity, so make sure to check them when using them. + * Return: TRUE @ldb contains validated VBDB info + * FALSE @ldb contents are undefined */ -static int parse_vmdb(const u8 *buffer, struct vmdb *vm) +static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base, + struct ldmdb *ldb) { - if (MAGIC_VMDB != BE32(buffer)) { - printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n"); - return -1; + Sector sect; + u8 *data; + BOOL result = FALSE; + struct vmdb *vm; + struct tocblock *toc; + + BUG_ON (!bdev); + BUG_ON (!ldb); + + vm = &ldb->vm; + toc = &ldb->toc; + + data = read_dev_sector (bdev, base + OFF_VMDB, §); + if (!data) { + ldm_crit ("Disk read failed."); + return FALSE; } - vm->ver_major = BE16(buffer + 0x12); - vm->ver_minor = BE16(buffer + 0x14); - if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { - printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. " - "Aborting.\n", 4, 10, vm->ver_major, - vm->ver_minor); - return -1; + + if (!ldm_parse_vmdb (data, vm)) + goto out; /* Already logged */ + + /* Are there uncommitted transactions? */ + if (BE16(data + 0x10) != 0x01) { + ldm_crit ("Database is not in a consistant state. Aborting."); + goto out; } - vm->vblk_size = BE32(buffer + 0x08); - vm->vblk_offset = BE32(buffer + 0x0C); - vm->last_vblk_seq = BE32(buffer + 0x04); - ldm_debug("Parsed VMDB successfully.\n"); - return 1; + if (vm->vblk_offset != 512) + ldm_info ("VBLKs start at offset 0x%04x.", vm->vblk_offset); + + /* FIXME: How should we handle this situation? */ + if ((vm->vblk_size * vm->last_vblk_seq) != (toc->bitmap1_size << 9)) + ldm_info ("VMDB and TOCBLOCK don't agree on the database size."); + + result = TRUE; +out: + put_dev_sector (sect); + return result; } + /** - * validate_vmdb - validate the vmdb - * @dev: partition device holding the LDM database - * @vm: in memory vmdb in which to return information + * ldm_validate_partition_table - Determine whether bdev might be a dynamic disk + * @bdev: Device holding the LDM Database * - * Find the vmdb of the LDM database stored on @dev and return the parsed - * information into @vm. + * This function provides a weak test to decide whether the device is a dynamic + * disk or not. It looks for an MS-DOS-style partition table containing at + * least one partition of type 0x42 (formerly SFS, now used by Windows for + * dynamic disks). + * + * N.B. The only possible error can come from the read_dev_sector and that is + * only likely to happen if the underlying device is strange. If that IS + * the case we should return zero to let someone else try. * - * Return 1 on success and -1 on error, in which case @vm is undefined. + * Return: TRUE @bdev is a dynamic disk + * FALSE @bdev is not a dynamic disk, or an error occurred */ -static int validate_vmdb(struct block_device *bdev, struct vmdb *vm, unsigned long base) +static BOOL ldm_validate_partition_table (struct block_device *bdev) { Sector sect; - unsigned char *data; - int ret; + u8 *data; + struct partition *p; + int i; + BOOL result = FALSE; - data = read_dev_sector(bdev, base + OFF_VMDB * 2 + 1, §); + BUG_ON (!bdev); + + data = read_dev_sector (bdev, 0, §); if (!data) { - printk(LDM_CRIT "Disk read failed in validate_vmdb.\n"); - return -1; + ldm_crit ("Disk read failed."); + return FALSE; + } + + if (*(u16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC)) { + ldm_debug ("No MS-DOS partition table found."); + goto out; } - ret = parse_vmdb(data, vm); - put_dev_sector(sect); - return ret; + + p = (struct partition*)(data + 0x01BE); + for (i = 0; i < 4; i++, p++) + if (SYS_IND (p) == WIN2K_DYNAMIC_PARTITION) { + result = TRUE; + break; + } + + if (result) + ldm_debug ("Parsed partition table successfully."); + else + ldm_debug ("Found an MS-DOS partition table, not a dynamic disk."); +out: + put_dev_sector (sect); + return result; } /** - * compare_tocblocks - compare two tables of contents - * @toc1: first toc - * @toc2: second toc + * ldm_get_disk_objid - Search a linked list of vblk's for a given Disk Id + * @ldb: Cache of the database structures * - * This compares the two tables of contents @toc1 and @toc2. + * The LDM Database contains a list of all partitions on all dynamic disks. The + * primary PRIVHEAD, at the beginning of the physical disk, tells us the GUID of + * this disk. This function searches for the GUID in a linked list of vblk's. * - * Return 1 if @toc1 and @toc2 are equal and -1 otherwise. + * Return: Pointer, A matching vblk was found + * NULL, No match, or an error */ -static int compare_tocblocks(const struct tocblock *toc1, - const struct tocblock *toc2) +static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb) { - if ((toc1->bitmap1_start == toc2->bitmap1_start) && - (toc1->bitmap1_size == toc2->bitmap1_size) && - (toc1->bitmap2_start == toc2->bitmap2_start) && - (toc1->bitmap2_size == toc2->bitmap2_size) && - !strncmp(toc1->bitmap1_name, toc2->bitmap1_name, - sizeof(toc1->bitmap1_name)) && - !strncmp(toc1->bitmap2_name, toc2->bitmap2_name, - sizeof(toc1->bitmap2_name))) - return 1; - return -1; + struct list_head *item; + + BUG_ON (!ldb); + + list_for_each (item, &ldb->v_disk) { + struct vblk *v = list_entry (item, struct vblk, list); + if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE)) + return v; + } + + return NULL; } /** - * parse_tocblock - parse the LDM database table of contents structure - * @buffer: LDM database toc structure loaded from the device - * @toc: in memory toc structure to return parsed information in + * ldm_create_partition - Create a kernel partition device + * @hd: gendisk structure in which to create partition + * @minor: Create a this minor number on the device + * @start: Offset (in sectors) into the device of the partition + * @size: Size (in sectors) of the partition * - * This parses the LDM database table of contents structure supplied in @buffer - * and sets up the in memory table of contents structure @toc with the obtained - * information. + * This validates the range, then puts an entry into the kernel's partition + * table. + * + * Return: TRUE Created the partition + * FALSE Error + */ +static BOOL ldm_create_partition (struct gendisk *hd, int minor, int start, + int size) +{ + int disk_minor; + + BUG_ON (!hd);; + BUG_ON (!hd->part); + + /* Get the minor number of the parent device + * so we can check we don't go beyond the end of the device. */ + disk_minor = (minor >> hd->minor_shift) << hd->minor_shift; + if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) { + ldm_crit ("Partition exceeds physical disk. Aborting."); + return FALSE; + } + add_gd_partition (hd, minor, start, size); + ldm_debug ("Created partition successfully."); + return TRUE; +} + +/** + * ldm_create_data_partitions - Create data partitions for this device + * @pp: List of the partitions parsed so far + * @ldb: Cache of the database structures * - * Return 1 on success and -1 on error, in which case @toc is undefined. + * The database contains ALL the partitions for ALL disk groups, so we need to + * filter out this specific disk. Using the disk's object id, we can find all + * the partitions in the database that belong to this disk. + * + * Add each partition in our database, to the parsed_partitions structure. + * + * N.B. This function creates the partitions in the order it finds partition + * objects in the linked list. * - * FIXME: The *_start and *_size values returned in @toc are not been checked - * for validity but as we don't use the actual values for anything other than - * comparing between the toc and its backups, the values are not important. + * Return: TRUE Partition created + * FALSE Error, probably a range checking problem */ -static int parse_tocblock(const u8 *buffer, struct tocblock *toc) +static BOOL ldm_create_data_partitions (struct gendisk *hd, + unsigned long first_sector, int first_minor, const struct ldmdb *ldb) { - if (MAGIC_TOCBLOCK != BE64(buffer)) { - printk(LDM_CRIT "Cannot find TOCBLOCK, database may be " - "corrupt.\n"); - return -1; + struct list_head *item; + struct vblk_part *part; + struct vblk *disk; + int disk_minor; + int minor; + + BUG_ON (!hd); + BUG_ON (!ldb); + + disk = ldm_get_disk_objid (ldb); + if (!disk) { + ldm_crit ("Can't find the ID of this disk in the database."); + return FALSE; } - strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name)); - toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0'; - toc->bitmap1_start = BE64(buffer + 0x2E); - toc->bitmap1_size = BE64(buffer + 0x36); - /*toc->bitmap1_flags = BE64(buffer + 0x3E);*/ - if (strncmp(toc->bitmap1_name, TOC_BITMAP1, - sizeof(toc->bitmap1_name)) != 0) { - printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is " - "%s.\n", TOC_BITMAP1, toc->bitmap1_name); - return -1; + + /* We use the range-check the partitions against the parent device. */ + disk_minor = (first_minor >> hd->minor_shift) << hd->minor_shift; + minor = first_minor; + + printk (" [LDM]"); + + /* Create the data partitions */ + list_for_each (item, &ldb->v_part) { + struct vblk *vb; + vb = list_entry (item, struct vblk, list); + part = &vb->vblk.part; + + if (part->disk_id != disk->obj_id) + continue; + + if (!ldm_create_partition (hd, minor, + part->start + ldb->ph.logical_disk_start, part->size)) + continue; /* Already logged */ + minor++; } - strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name)); - toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0'; - toc->bitmap2_start = BE64(buffer + 0x50); - toc->bitmap2_size = BE64(buffer + 0x58); - /*toc->bitmap2_flags = BE64(buffer + 0x60);*/ - if (strncmp(toc->bitmap2_name, TOC_BITMAP2, - sizeof(toc->bitmap2_name)) != 0) { - printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is " - "%s.\n", TOC_BITMAP2, toc->bitmap2_name); + + printk ("\n"); + return TRUE; +} + + +/** + * ldm_relative - Calculate the next relative offset + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @base: Size of the previous fixed width fields + * @offset: Cumulative size of the previous variable-width fields + * + * Because many of the VBLK fields are variable-width, it's necessary + * to calculate each offset based on the previous one and the length + * of the field it pointed to. + * + * Return: -1 Error, the calculated offset exceeded the size of the buffer + * n OK, a range-checked offset into buffer + */ +static int ldm_relative (const u8 *buffer, int buflen, int base, int offset) +{ + + base += offset; + if ((!buffer) || (offset < 0) || (base > buflen)) return -1; - } - ldm_debug("Parsed TOCBLOCK successfully.\n"); - return 1; + if ((base + buffer[base]) >= buflen) + return -1; + + return buffer[base] + offset + 1; } /** - * validate_tocblocks - validate the table of contents and its backups - * @dev: partition device holding the LDM database - * @toc1: in memory table of contents in which to return information + * ldm_get_vnum - Convert a variable-width, big endian number, into cpu order + * @block: Pointer to the variable-width number to convert + * + * Large numbers in the LDM Database are often stored in a packed format. Each + * number is prefixed by a one byte width marker. All numbers in the database + * are stored in big-endian byte order. This function reads one of these + * numbers and returns the result * - * Find and compare the four tables of contents of the LDM database stored on - * @dev and return the parsed information into @toc1. + * N.B. This function DOES NOT perform any range checking, though the most + * it will read is eight bytes. * - * Return 1 on success and -1 on error, in which case @toc1 is undefined. + * Return: n A number + * 0 Zero, or an error occurred */ -static int validate_tocblocks(struct block_device *bdev, - struct tocblock *toc1, - unsigned long base) +static u64 ldm_get_vnum (const u8 *block) { - Sector sect; - unsigned char *data; - struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL; - int err; - - toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL); - if (!toc2) - goto no_mem; - toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL); - if (!toc3) - goto no_mem; - toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL); - if (!toc4) - goto no_mem; - /* Read and parse first toc. */ - data = read_dev_sector(bdev, base + OFF_TOCBLOCK1 * 2 + 1, §); - if (!data) { - printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n"); - goto err_out; - } - err = parse_tocblock(data, toc1); - put_dev_sector(sect); - if (err != 1) - goto out; - /* Read and parse second toc. */ - data = read_dev_sector(bdev, base + OFF_TOCBLOCK2 * 2, §); - if (!data) { - printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n"); - goto err_out; - } - err = parse_tocblock(data, toc2); - put_dev_sector(sect); - if (err != 1) - goto out; - /* Read and parse third toc. */ - data = read_dev_sector(bdev, base + OFF_TOCBLOCK3 * 2 + 1, §); - if (!data) { - printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n"); - goto err_out; - } - err = parse_tocblock(data, toc3); - put_dev_sector(sect); - if (err != 1) - goto out; - /* Read and parse fourth toc. */ - data = read_dev_sector(bdev, base + OFF_TOCBLOCK4 * 2, §); - if (!data) { - printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n"); - goto err_out; - } - err = parse_tocblock(data, toc4); - put_dev_sector(sect); - if (err != 1) - goto out; - /* Compare all tocs. */ - err = compare_tocblocks(toc1, toc2); - if (err != 1) { - printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n"); - goto out; - } - err = compare_tocblocks(toc3, toc4); - if (err != 1) { - printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n"); - goto out; - } - err = compare_tocblocks(toc1, toc3); - if (err != 1) - printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n"); + u64 tmp = 0; + u8 length; + + BUG_ON (!block); + + length = *block++; + + if (length && length <= 8) + while (length--) + tmp = (tmp << 8) | *block++; else - ldm_debug("Validated TOCBLOCKs successfully.\n"); -out: - kfree(toc2); - kfree(toc3); - kfree(toc4); - return err; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); -err_out: - err = -1; - goto out; + ldm_error ("Illegal length %d.", length); + + return tmp; } /** - * compare_privheads - compare two privheads - * @ph1: first privhead - * @ph2: second privhead - * - * This compares the two privheads @ph1 and @ph2. - * - * Return 1 if @ph1 and @ph2 are equal and -1 otherwise. - */ -static int compare_privheads(const struct privhead *ph1, - const struct privhead *ph2) -{ - if ((ph1->ver_major == ph2->ver_major) && - (ph1->ver_minor == ph2->ver_minor) && - (ph1->logical_disk_start == ph2->logical_disk_start) && - (ph1->logical_disk_size == ph2->logical_disk_size) && - (ph1->config_start == ph2->config_start) && - (ph1->config_size == ph2->config_size) && - !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id))) - return 1; - return -1; + * ldm_get_vstr - Read a length-prefixed string into a buffer + * @block: Pointer to the length marker + * @buffer: Location to copy string to + * @buflen: Size of the output buffer + * + * Many of the strings in the LDM Database are not NULL terminated. Instead + * they are prefixed by a one byte length marker. This function copies one of + * these strings into a buffer. + * + * N.B. This function DOES NOT perform any range checking on the input. + * If the buffer is too small, the output will be truncated. + * + * Return: 0, Error and @buffer contents are undefined + * n, String length in characters (excluding NULL) + * buflen-1, String was truncated. + */ +static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen) +{ + int length; + + BUG_ON (!block); + BUG_ON (!buffer); + + length = block[0]; + if (length >= buflen) { + ldm_error ("Truncating string %d -> %d.", length, buflen); + length = buflen - 1; + } + memcpy (buffer, block + 1, length); + buffer[length] = 0; + return length; +} + + +/** + * ldm_parse_cmp3 - Read a raw VBLK Component object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Component object (version 3) into a vblk structure. + * + * Return: TRUE @vb contains a Component VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len; + struct vblk_comp *comp; + + BUG_ON (!buffer); + BUG_ON (!vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_vstate = ldm_relative (buffer, buflen, 0x18, r_name); + r_child = ldm_relative (buffer, buflen, 0x1D, r_vstate); + r_parent = ldm_relative (buffer, buflen, 0x2D, r_child); + + if (buffer[0x12] & VBLK_FLAG_COMP_STRIPE) { + r_stripe = ldm_relative (buffer, buflen, 0x2E, r_parent); + r_cols = ldm_relative (buffer, buflen, 0x2E, r_stripe); + len = r_cols; + } else { + r_stripe = 0; + r_cols = 0; + len = r_parent; + } + if (len < 0) + return FALSE; + + len += VBLK_SIZE_CMP3; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + comp = &vb->vblk.comp; + ldm_get_vstr (buffer + 0x18 + r_name, comp->state, + sizeof (comp->state)); + comp->type = buffer[0x18 + r_vstate]; + comp->children = ldm_get_vnum (buffer + 0x1D + r_vstate); + comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child); + comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0; + + return TRUE; +} + +/** + * ldm_parse_dgr3 - Read a raw VBLK Disk Group object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Disk Group object (version 3) into a vblk structure. + * + * Return: TRUE @vb contains a Disk Group VBLK + * FALSE @vb contents are not defined + */ +static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_diskid, r_id1, r_id2, len; + struct vblk_dgrp *dgrp; + + BUG_ON (!buffer); + BUG_ON (!vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_diskid = ldm_relative (buffer, buflen, 0x18, r_name); + + if (buffer[0x12] & VBLK_FLAG_DGR3_IDS) { + r_id1 = ldm_relative (buffer, buflen, 0x24, r_diskid); + r_id2 = ldm_relative (buffer, buflen, 0x24, r_id1); + len = r_id2; + } else { + r_id1 = 0; + r_id2 = 0; + len = r_diskid; + } + if (len < 0) + return FALSE; + + len += VBLK_SIZE_DGR3; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + dgrp = &vb->vblk.dgrp; + ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id, + sizeof (dgrp->disk_id)); + return TRUE; } /** - * validate_privheads - compare the privhead backups to the first one - * @dev: partition device holding the LDM database - * @ph1: first privhead which we have already validated before - * - * We already have one privhead from the beginning of the disk. - * Now we compare the two other copies for safety. - * - * Return 1 on succes and -1 on error. - */ -static int validate_privheads(struct block_device *bdev, - const struct privhead *ph1, - unsigned long base) + * ldm_parse_dgr4 - Read a raw VBLK Disk Group object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Disk Group object (version 4) into a vblk structure. + * + * Return: TRUE @vb contains a Disk Group VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb) { - Sector sect; - unsigned char *data; - struct privhead *ph2 = NULL, *ph3 = NULL; - int err; - - ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL); - if (!ph2) - goto no_mem; - ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL); - if (!ph3) - goto no_mem; - data = read_dev_sector(bdev, base + OFF_PRIVHEAD2 * 2, §); - if (!data) { - printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n"); - goto err_out; + char buf[64]; + int r_objid, r_name, r_id1, r_id2, len; + struct vblk_dgrp *dgrp; + + BUG_ON (!buffer); + BUG_ON (!vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + + if (buffer[0x12] & VBLK_FLAG_DGR4_IDS) { + r_id1 = ldm_relative (buffer, buflen, 0x44, r_name); + r_id2 = ldm_relative (buffer, buflen, 0x44, r_id1); + len = r_id2; + } else { + r_id1 = 0; + r_id2 = 0; + len = r_name; } - err = parse_privhead(data, ph2); - put_dev_sector(sect); - if (err != 1) - goto out; - data = read_dev_sector(bdev, base + OFF_PRIVHEAD3 * 2 + 1, §); - if (!data) { - printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n"); - goto err_out; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_DGR4; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + dgrp = &vb->vblk.dgrp; + + ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf)); + return TRUE; +} + +/** + * ldm_parse_dsk3 - Read a raw VBLK Disk object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Disk object (version 3) into a vblk structure. + * + * Return: TRUE @vb contains a Disk VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_diskid, r_altname, len; + struct vblk_disk *disk; + + BUG_ON (!buffer); + BUG_ON (!vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_diskid = ldm_relative (buffer, buflen, 0x18, r_name); + r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid); + len = r_altname; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_DSK3; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + disk = &vb->vblk.disk; + ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name, + sizeof (disk->alt_name)); + if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id)) + return FALSE; + + return TRUE; +} + +/** + * ldm_parse_dsk4 - Read a raw VBLK Disk object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Disk object (version 4) into a vblk structure. + * + * Return: TRUE @vb contains a Disk VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, len; + struct vblk_disk *disk; + + BUG_ON (!buffer); + BUG_ON (!vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + len = r_name; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_DSK4; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + disk = &vb->vblk.disk; + memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE); + return TRUE; +} + +/** + * ldm_parse_prt3 - Read a raw VBLK Partition object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Partition object (version 3) into a vblk structure. + * + * Return: TRUE @vb contains a Partition VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len; + struct vblk_part *part; + + BUG_ON (!buffer); + BUG_ON (!vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_size = ldm_relative (buffer, buflen, 0x34, r_name); + r_parent = ldm_relative (buffer, buflen, 0x34, r_size); + r_diskid = ldm_relative (buffer, buflen, 0x34, r_parent); + + if (buffer[0x12] & VBLK_FLAG_PART_INDEX) { + r_index = ldm_relative (buffer, buflen, 0x34, r_diskid); + len = r_index; + } else { + r_index = 0; + len = r_diskid; } - err = parse_privhead(data, ph3); - put_dev_sector(sect); - if (err != 1) - goto out; - err = compare_privheads(ph1, ph2); - if (err != 1) { - printk(LDM_CRIT "First and second PRIVHEADs don't match.\n"); - goto out; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_PRT3; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + part = &vb->vblk.part; + part->start = BE64 (buffer + 0x24 + r_name); + part->volume_offset = BE64 (buffer + 0x2C + r_name); + part->size = ldm_get_vnum (buffer + 0x34 + r_name); + part->parent_id = ldm_get_vnum (buffer + 0x34 + r_size); + part->disk_id = ldm_get_vnum (buffer + 0x34 + r_parent); + if (vb->flags & VBLK_FLAG_PART_INDEX) + part->partnum = buffer[0x35 + r_diskid]; + else + part->partnum = 0; + + return TRUE; +} + +/** + * ldm_parse_vol5 - Read a raw VBLK Volume object into a vblk structure + * @buffer: Block of data being worked on + * @buflen: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK Volume object (version 5) into a vblk structure. + * + * Return: TRUE @vb contains a Volume VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb) +{ + int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2; + int r_drive, len; + struct vblk_volu *volu; + + BUG_ON (!buffer); + BUG_ON (!vb); + + r_objid = ldm_relative (buffer, buflen, 0x18, 0); + r_name = ldm_relative (buffer, buflen, 0x18, r_objid); + r_vtype = ldm_relative (buffer, buflen, 0x18, r_name); + r_child = ldm_relative (buffer, buflen, 0x2E, r_vtype); + r_size = ldm_relative (buffer, buflen, 0x3E, r_child); + + if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) + r_id1 = ldm_relative (buffer, buflen, 0x53, r_size); + else + r_id1 = r_size; + + if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) + r_id2 = ldm_relative (buffer, buflen, 0x53, r_id1); + else + r_id2 = r_id1; + + if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) + r_size2 = ldm_relative (buffer, buflen, 0x53, r_id2); + else + r_size2 = r_id2; + + if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) + r_drive = ldm_relative (buffer, buflen, 0x53, r_size2); + else + r_drive = r_size2; + + len = r_drive; + if (len < 0) + return FALSE; + + len += VBLK_SIZE_VOL5; + if (len != BE32 (buffer + 0x14)) + return FALSE; + + volu = &vb->vblk.volu; + + ldm_get_vstr (buffer + 0x18 + r_name, volu->volume_type, + sizeof (volu->volume_type)); + memcpy (volu->volume_state, buffer + 0x19 + r_vtype, + sizeof (volu->volume_state)); + volu->size = ldm_get_vnum (buffer + 0x3E + r_child); + volu->partition_type = buffer[0x42 + r_size]; + memcpy (volu->guid, buffer + 0x43 + r_size, sizeof (volu->guid)); + if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) { + ldm_get_vstr (buffer + 0x53 + r_size, volu->drive_hint, + sizeof (volu->drive_hint)); } - err = compare_privheads(ph1, ph3); - if (err != 1) - printk(LDM_CRIT "First and third PRIVHEADs don't match.\n"); + return TRUE; +} + +/** + * ldm_parse_vblk - Read a raw VBLK object into a vblk structure + * @buf: Block of data being worked on + * @len: Size of the block of data + * @vb: In-memory vblk in which to return information + * + * Read a raw VBLK object into a vblk structure. This function just reads the + * information common to all VBLK types, then delegates the rest of the work to + * helper functions: ldm_parse_*. + * + * Return: TRUE @vb contains a VBLK + * FALSE @vb contents are not defined + */ +static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb) +{ + BOOL result = FALSE; + int r_objid; + + BUG_ON (!buf); + BUG_ON (!vb); + + r_objid = ldm_relative (buf, len, 0x18, 0); + if (r_objid < 0) { + ldm_error ("VBLK header is corrupt."); + return FALSE; + } + + vb->flags = buf[0x12]; + vb->type = buf[0x13]; + vb->obj_id = ldm_get_vnum (buf + 0x18); + ldm_get_vstr (buf+0x18+r_objid, vb->name, sizeof (vb->name)); + + switch (vb->type) { + case VBLK_CMP3: result = ldm_parse_cmp3 (buf, len, vb); break; + case VBLK_DSK3: result = ldm_parse_dsk3 (buf, len, vb); break; + case VBLK_DSK4: result = ldm_parse_dsk4 (buf, len, vb); break; + case VBLK_DGR3: result = ldm_parse_dgr3 (buf, len, vb); break; + case VBLK_DGR4: result = ldm_parse_dgr4 (buf, len, vb); break; + case VBLK_PRT3: result = ldm_parse_prt3 (buf, len, vb); break; + case VBLK_VOL5: result = ldm_parse_vol5 (buf, len, vb); break; + } + + if (result) + ldm_debug ("Parsed VBLK 0x%llx (type: 0x%02x) ok.", + (unsigned long long) vb->obj_id, vb->type); else - /* We _could_ have checked more. */ - ldm_debug("Validated PRIVHEADs successfully.\n"); -out: - kfree(ph2); - kfree(ph3); - return err; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); -err_out: - err = -1; - goto out; + ldm_error ("Failed to parse VBLK 0x%llx (type: 0x%02x).", + (unsigned long long) vb->obj_id, vb->type); + + return result; } + /** - * create_partition - validate input and create a kernel partition device - * @hd: gendisk structure in which to create partition - * @minor: minor number for device to create - * @start: starting offset of the partition into the parent device - * @size: size of the partition + * ldm_ldmdb_add - Adds a raw VBLK entry to the ldmdb database + * @data: Raw VBLK to add to the database + * @len: Size of the raw VBLK + * @ldb: Cache of the database structures * - * This validates the range, then puts an entry into the kernel's partition - * table. + * The VBLKs are sorted into categories. Partitions are also sorted by offset. * - * @start and @size are numbers of sectors. + * N.B. This function does not check the validity of the VBLKs. * - * Return 1 on succes and -1 on error. + * Return: TRUE The VBLK was added + * FALSE An error occurred */ -static int create_partition(struct gendisk *hd, const int minor, - const int start, const int size) +static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb) { - int disk_minor; + struct vblk *vb; + struct list_head *item; - if (!hd->part) - return -1; - /* - * Get the minor number of the parent device so we can check we don't - * go beyond the end of the device. - */ - disk_minor = (minor >> hd->minor_shift) << hd->minor_shift; - if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) { - printk(LDM_CRIT "LDM Partition exceeds physical disk. " - "Aborting.\n"); - return -1; + BUG_ON (!data); + BUG_ON (!ldb); + + vb = kmalloc (sizeof (*vb), GFP_KERNEL); + if (!vb) { + ldm_crit ("Out of memory."); + return FALSE; + } + + if (!ldm_parse_vblk (data, len, vb)) + return FALSE; /* Already logged */ + + /* Put vblk into the correct list. */ + switch (vb->type) { + case VBLK_DGR3: + case VBLK_DGR4: + list_add (&vb->list, &ldb->v_dgrp); + break; + case VBLK_DSK3: + case VBLK_DSK4: + list_add (&vb->list, &ldb->v_disk); + break; + case VBLK_VOL5: + list_add (&vb->list, &ldb->v_volu); + break; + case VBLK_CMP3: + list_add (&vb->list, &ldb->v_comp); + break; + case VBLK_PRT3: + /* Sort by the partition's start sector. */ + list_for_each (item, &ldb->v_part) { + struct vblk *v = list_entry (item, struct vblk, list); + if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) && + (v->vblk.part.start > vb->vblk.part.start)) { + list_add_tail (&vb->list, &v->list); + return TRUE; + } + } + list_add_tail (&vb->list, &ldb->v_part); + break; } - add_gd_partition(hd, minor, start, size); - ldm_debug("Created partition successfully.\n"); - return 1; + return TRUE; } /** - * parse_privhead - parse the LDM database PRIVHEAD structure - * @buffer: LDM database privhead structure loaded from the device - * @ph: in memory privhead structure to return parsed information in + * ldm_frag_add - Add a VBLK fragment to a list + * @data: Raw fragment to be added to the list + * @size: Size of the raw fragment + * @frags: Linked list of VBLK fragments * - * This parses the LDM database PRIVHEAD structure supplied in @buffer and - * sets up the in memory privhead structure @ph with the obtained information. + * Fragmented VBLKs may not be consecutive in the database, so they are placed + * in a list so they can be pieced together later. * - * Return 1 on succes and -1 on error, in which case @ph is undefined. + * Return: TRUE Success, the VBLK was added to the list + * FALSE Error, a problem occurred */ -static int parse_privhead(const u8 *buffer, struct privhead *ph) +static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags) { - if (MAGIC_PRIVHEAD != BE64(buffer)) { - printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database " - "is corrupt. Aborting.\n"); - return -1; + struct frag *f; + struct list_head *item; + int rec, num, group; + + BUG_ON (!data); + BUG_ON (!frags); + + group = BE32 (data + 0x08); + rec = BE16 (data + 0x0C); + num = BE16 (data + 0x0E); + if ((num < 1) || (num > 4)) { + ldm_error ("A VBLK claims to have %d parts.", num); + return FALSE; } - ph->ver_major = BE16(buffer + 0x000C); - ph->ver_minor = BE16(buffer + 0x000E); - if ((ph->ver_major != 2) || (ph->ver_minor != 11)) { - printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. " - "Aborting.\n", 2, 11, ph->ver_major, - ph->ver_minor); - return -1; + + list_for_each (item, frags) { + f = list_entry (item, struct frag, list); + if (f->group == group) + goto found; } - ph->config_start = BE64(buffer + 0x012B); - ph->config_size = BE64(buffer + 0x0133); - if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */ - printk(LDM_ERR "Database should be %u bytes, claims to be %Lu " - "bytes. Aborting.\n", LDM_DB_SIZE, - ph->config_size); - return -1; + + f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL); + if (!f) { + ldm_crit ("Out of memory."); + return FALSE; } - ph->logical_disk_start = BE64(buffer + 0x011B); - ph->logical_disk_size = BE64(buffer + 0x0123); - if (!ph->logical_disk_size || - ph->logical_disk_start + ph->logical_disk_size > ph->config_start) - return -1; - memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id)); + f->group = group; + f->num = num; + f->rec = rec; + f->map = 0xFF << num; + + list_add_tail (&f->list, frags); +found: + if (f->map & (1 << rec)) { + ldm_error ("Duplicate VBLK, part %d.", rec); + f->map &= 0x7F; /* Mark the group as broken */ + return FALSE; + } - ldm_debug("Parsed PRIVHEAD successfully.\n"); - return 1; + f->map |= (1 << rec); + + if (num > 0) { + data += VBLK_SIZE_HEAD; + size -= VBLK_SIZE_HEAD; + } + memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size); + + return TRUE; } /** - * create_db_partition - create a dedicated partition for our database - * @hd: gendisk structure in which to create partition - * @dev: device of which to create partition - * @ph: @dev's LDM database private header + * ldm_frag_free - Free a linked list of VBLK fragments + * @list: Linked list of fragments * - * Find the primary private header, locate the LDM database, then create a - * partition to wrap it. + * Free a linked list of VBLK fragments * - * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error. + * Return: none */ -static int create_db_partition(struct gendisk *hd, struct block_device *bdev, - const unsigned long first_sector, const int first_part_minor, - struct privhead *ph) +static void ldm_frag_free (struct list_head *list) { - Sector sect; - unsigned char *data; - int err; + struct list_head *item, *tmp; - data = read_dev_sector(bdev, OFF_PRIVHEAD1*2, §); - if (!data) { - printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n"); - return -1; - } - if (BE64(data) != MAGIC_PRIVHEAD) { - ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk " - "or corrupt LDM database.\n"); - return 0; + BUG_ON (!list); + + list_for_each_safe (item, tmp, list) + kfree (list_entry (item, struct frag, list)); +} + +/** + * ldm_frag_commit - Validate fragmented VBLKs and add them to the database + * @frags: Linked list of VBLK fragments + * @ldb: Cache of the database structures + * + * Now that all the fragmented VBLKs have been collected, they must be added to + * the database for later use. + * + * Return: TRUE All the fragments we added successfully + * FALSE One or more of the fragments we invalid + */ +static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb) +{ + struct frag *f; + struct list_head *item; + + BUG_ON (!frags); + BUG_ON (!ldb); + + list_for_each (item, frags) { + f = list_entry (item, struct frag, list); + + if (f->map != 0xFF) { + ldm_error ("VBLK group %d is incomplete (0x%02x).", + f->group, f->map); + return FALSE; + } + + if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb)) + return FALSE; /* Already logged */ } - err = parse_privhead(data, ph); - if (err == 1) - err = create_partition(hd, first_part_minor, first_sector + - ph->config_start, ph->config_size); - put_dev_sector(sect); - return err; + return TRUE; } /** - * validate_patition_table - check whether @dev is a dynamic disk - * @dev: device to test + * ldm_get_vblks - Read the on-disk database of VBLKs into memory + * @bdev: Device holding the LDM Database + * @base: Offset, into @bdev, of the database + * @ldb: Cache of the database structures * - * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition - * table with one or more entries of type 0x42 (the former Secure File System - * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it. - * If this succeeds we assume we have a dynamic disk, and not otherwise. + * To use the information from the VBLKs, they need to be read from the disk, + * unpacked and validated. We cache them in @ldb according to their type. * - * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error. + * Return: TRUE All the VBLKs were read successfully + * FALSE An error occurred */ -static int validate_partition_table(struct block_device *bdev) +static BOOL ldm_get_vblks (struct block_device *bdev, unsigned long base, + struct ldmdb *ldb) { + int size, perbuf, skip, finish, s, v, recs; + u8 *data = NULL; Sector sect; - unsigned char *data; - struct partition *p; - int i, nr_sfs; + BOOL result = FALSE; + LIST_HEAD (frags); - data = read_dev_sector(bdev, 0, §); - if (!data) - return -1; + BUG_ON (!bdev); + BUG_ON (!ldb); - if (*(u16*)(data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { - ldm_debug("No MS-DOS partition found.\n"); - goto no_msdos_partition; - } - nr_sfs = 0; - p = (struct partition*)(data + 0x01BE); - for (i = 0; i < 4; i++) { - if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION) - continue; - if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) { - nr_sfs++; - continue; + size = ldb->vm.vblk_size; + perbuf = 512 / size; + skip = ldb->vm.vblk_offset >> 9; /* Bytes to sectors */ + finish = (size * ldb->vm.last_vblk_seq) >> 9; + + for (s = skip; s < finish; s++) { /* For each sector */ + data = read_dev_sector (bdev, base + OFF_VMDB + s, §); + if (!data) { + ldm_crit ("Disk read failed."); + goto out; } - goto not_dynamic_disk; + + for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */ + if (MAGIC_VBLK != BE32 (data)) { + ldm_error ("Expected to find a VBLK."); + goto out; + } + + recs = BE16 (data + 0x0E); /* Number of records */ + if (recs == 1) { + if (!ldm_ldmdb_add (data, size, ldb)) + goto out; /* Already logged */ + } else if (recs > 1) { + if (!ldm_frag_add (data, size, &frags)) + goto out; /* Already logged */ + } + /* else Record is not in use, ignore it. */ + } + put_dev_sector (sect); + data = NULL; } - if (!nr_sfs) - goto not_dynamic_disk; - ldm_debug("Parsed partition table successfully.\n"); - put_dev_sector(sect); - return 1; -not_dynamic_disk: -// ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n"); -no_msdos_partition: - put_dev_sector(sect); - return 0; + + result = ldm_frag_commit (&frags, ldb); /* Failures, already logged */ +out: + if (data) + put_dev_sector (sect); + ldm_frag_free (&frags); + + return result; } /** - * ldm_partition - find out whether a device is a dynamic disk and handle it - * @hd: gendisk structure in which to return the handled disk - * @dev: device we need to look at - * @first_sector: first sector within the device - * @first_part_minor: first minor number of partitions for the device + * ldm_free_vblks - Free a linked list of vblk's + * @lh: Head of a linked list of struct vblk * - * Description: + * Free a list of vblk's and free the memory used to maintain the list. + * + * Return: none + */ +static void ldm_free_vblks (struct list_head *lh) +{ + struct list_head *item, *tmp; + + BUG_ON (!lh); + + list_for_each_safe (item, tmp, lh) + kfree (list_entry (item, struct vblk, list)); +} + + +/** + * ldm_partition - Find out whether a device is a dynamic disk and handle it + * @hd: gendisk structure in which to return the handled disk + * @bdev: Device we need to look at + * @first_sector: First sector within the device + * @first_minor: First minor number of partitions for the device * - * This determines whether the device @dev is a dynamic disk and if so creates + * This determines whether the device @bdev is a dynamic disk and if so creates * the partitions necessary in the gendisk structure pointed to by @hd. * - * We create a dummy device 1, which contains the LDM database, we skip - * devices 2-4 and then create each partition described by the LDM database - * in sequence as devices 5 and following. For example, if the device is hda, - * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the - * actual data containing partitions. - * - * Return values: - * - * 1 if @dev is a dynamic disk and we handled it, - * 0 if @dev is not a dynamic disk, - * -1 if an error occured. - */ -int ldm_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor) -{ - struct privhead *ph = NULL; - struct tocblock *toc = NULL; - struct vmdb *vm = NULL; - struct ldmdisk *dk = NULL; - unsigned long db_first; - int err; + * We create a dummy device 1, which contains the LDM database, and then create + * each partition described by the LDM database in sequence as devices 2+. For + * example, if the device is hda, we would have: hda1: LDM database, hda2, hda3, + * and so on: the actual data containing partitions. + * + * Return: 1 Success, @bdev is a dynamic disk and we handled it + * 0 Success, @bdev is not a dynamic disk + * -1 An error occurred before enough information had been read + * Or @bdev is a dynamic disk, but it may be corrupted + */ +int ldm_partition (struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_minor) +{ + struct ldmdb *ldb; + unsigned long base; + int result = -1; + + BUG_ON (!hd); + BUG_ON (!bdev); - if (!hd) + /* Look for signs of a Dynamic Disk */ + if (!ldm_validate_partition_table (bdev)) return 0; - /* Check the partition table. */ - err = validate_partition_table(bdev); - if (err != 1) - return err; - if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL))) - goto no_mem; - /* Create the LDM database device. */ - err = create_db_partition(hd, bdev, first_sector, first_part_minor, ph); - if (err != 1) - goto out; - db_first = hd->part[first_part_minor].start_sect; - /* Check the backup privheads. */ - err = validate_privheads(bdev, ph, db_first); - if (err != 1) - goto out; - /* Check the table of contents and its backups. */ - if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL))) - goto no_mem; - err = validate_tocblocks(bdev, toc, db_first); - if (err != 1) - goto out; - /* Check the vmdb. */ - if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL))) - goto no_mem; - err = validate_vmdb(bdev, vm, db_first); - if (err != 1) - goto out; - /* Find the object id for @dev in the LDM database. */ - if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL))) - goto no_mem; - err = get_disk_objid(bdev, vm, ph, dk, db_first); - if (err != 1) + + ldb = kmalloc (sizeof (*ldb), GFP_KERNEL); + if (!ldb) { + ldm_crit ("Out of memory."); goto out; + } + + /* Parse and check privheads. */ + if (!ldm_validate_privheads (bdev, first_sector, &ldb->ph, hd, first_minor)) + goto out; /* Already logged */ + + /* All further references are relative to base (database start). */ + base = first_sector + ldb->ph.config_start; + + /* Parse and check tocs and vmdb. */ + if (!ldm_validate_tocblocks (bdev, base, ldb) || + !ldm_validate_vmdb (bdev, base, ldb)) + goto out; /* Already logged */ + + /* Initialize vblk lists in ldmdb struct */ + INIT_LIST_HEAD (&ldb->v_dgrp); + INIT_LIST_HEAD (&ldb->v_disk); + INIT_LIST_HEAD (&ldb->v_volu); + INIT_LIST_HEAD (&ldb->v_comp); + INIT_LIST_HEAD (&ldb->v_part); + + if (!ldm_get_vblks (bdev, base, ldb)) { + ldm_crit ("Failed to read the VBLKs from the database."); + goto cleanup; + } + /* Finally, create the data partition devices. */ - err = create_data_partitions(hd, first_sector, first_part_minor + - LDM_FIRST_PART_OFFSET, bdev, vm, ph, dk, db_first); - if (err == 1) - ldm_debug("Parsed LDM database successfully.\n"); + if (ldm_create_data_partitions (hd, first_sector, first_minor, ldb)) { + ldm_debug ("Parsed LDM database successfully."); + result = 1; + } + /* else Already logged */ + +cleanup: + ldm_free_vblks (&ldb->v_dgrp); + ldm_free_vblks (&ldb->v_disk); + ldm_free_vblks (&ldb->v_volu); + ldm_free_vblks (&ldb->v_comp); + ldm_free_vblks (&ldb->v_part); out: - kfree(ph); - kfree(toc); - kfree(vm); - kfree(dk); - return err; -no_mem: - printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); - err = -1; - goto out; + kfree (ldb); + return result; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/partitions/ldm.h linux.20pre2-ac1/fs/partitions/ldm.h --- linux.20pre2/fs/partitions/ldm.h 2002-08-13 13:58:15.000000000 +0100 +++ linux.20pre2-ac1/fs/partitions/ldm.h 2002-08-14 14:41:30.000000000 +0100 @@ -1,10 +1,9 @@ -#ifndef _FS_PT_LDM_H_ -#define _FS_PT_LDM_H_ -/* +/** * ldm - Part of the Linux-NTFS project. * - * Copyright (C) 2001 Richard Russon - * Copyright (C) 2001 Anton Altaparmakov + * Copyright (C) 2001,2002 Richard Russon + * Copyright (C) 2001 Anton Altaparmakov + * Copyright (C) 2001,2002 Jakob Kemi * * Documentation is available at http://linux-ntfs.sf.net/ldm * @@ -23,16 +22,18 @@ * in the file COPYING); if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _FS_PT_LDM_H_ +#define _FS_PT_LDM_H_ + #include +#include +#include +#include #include #include -#include -/* Borrowed from kernel.h. */ -#define LDM_PREFIX "LDM: " /* Prefix our error messages with this. */ -#define LDM_CRIT KERN_CRIT LDM_PREFIX /* critical conditions */ -#define LDM_ERR KERN_ERR LDM_PREFIX /* error conditions */ -#define LDM_DEBUG KERN_DEBUG LDM_PREFIX /* debug-level messages */ +struct parsed_partitions; /* Magic numbers in CPU format. */ #define MAGIC_VMDB 0x564D4442 /* VMDB */ @@ -41,41 +42,58 @@ #define MAGIC_TOCBLOCK 0x544F43424C4F434B /* TOCBLOCK */ /* The defined vblk types. */ -#define VBLK_COMP 0x32 /* Component */ -#define VBLK_PART 0x33 /* Partition */ -#define VBLK_DSK1 0x34 /* Disk */ -#define VBLK_DSK2 0x44 /* Disk */ -#define VBLK_DGR1 0x35 /* Disk Group */ -#define VBLK_DGR2 0x45 /* Disk Group */ -#define VBLK_VOLU 0x51 /* Volume */ +#define VBLK_VOL5 0x51 /* Volume, version 5 */ +#define VBLK_CMP3 0x32 /* Component, version 3 */ +#define VBLK_PRT3 0x33 /* Partition, version 3 */ +#define VBLK_DSK3 0x34 /* Disk, version 3 */ +#define VBLK_DSK4 0x44 /* Disk, version 4 */ +#define VBLK_DGR3 0x35 /* Disk Group, version 3 */ +#define VBLK_DGR4 0x45 /* Disk Group, version 4 */ + +/* vblk flags indicating extra information will be present */ +#define VBLK_FLAG_COMP_STRIPE 0x10 +#define VBLK_FLAG_PART_INDEX 0x08 +#define VBLK_FLAG_DGR3_IDS 0x08 +#define VBLK_FLAG_DGR4_IDS 0x08 +#define VBLK_FLAG_VOLU_ID1 0x08 +#define VBLK_FLAG_VOLU_ID2 0x20 +#define VBLK_FLAG_VOLU_SIZE 0x80 +#define VBLK_FLAG_VOLU_DRIVE 0x02 + +/* size of a vblk's static parts */ +#define VBLK_SIZE_HEAD 16 +#define VBLK_SIZE_CMP3 22 /* Name and version */ +#define VBLK_SIZE_DGR3 12 +#define VBLK_SIZE_DGR4 44 +#define VBLK_SIZE_DSK3 12 +#define VBLK_SIZE_DSK4 45 +#define VBLK_SIZE_PRT3 28 +#define VBLK_SIZE_VOL5 59 + +/* component types */ +#define COMP_STRIPE 0x01 /* Stripe-set */ +#define COMP_BASIC 0x02 /* Basic disk */ +#define COMP_RAID 0x03 /* Raid-set */ /* Other constants. */ -#define LDM_BLOCKSIZE 1024 /* Size of block in bytes. */ #define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */ -#define LDM_FIRST_PART_OFFSET 4 /* Add this to first_part_minor - to get to the first data - partition device minor. */ -#define OFF_PRIVHEAD1 3 /* Offset of the first privhead +#define OFF_PRIV1 6 /* Offset of the first privhead relative to the start of the - device in units of - LDM_BLOCKSIZE. */ + device in sectors */ -/* Offsets to structures within the LDM Database in units of LDM_BLOCKSIZE. */ -#define OFF_PRIVHEAD2 928 /* Backup private headers. */ -#define OFF_PRIVHEAD3 1023 - -#define OFF_TOCBLOCK1 0 /* Tables of contents. */ -#define OFF_TOCBLOCK2 1 -#define OFF_TOCBLOCK3 1022 -#define OFF_TOCBLOCK4 1023 - -#define OFF_VMDB 8 /* List of partitions. */ -#define OFF_VBLK 9 - -#define WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */ -#define WIN2K_EXTENDED_PARTITION 0x05 /* A standard extended - partition. */ +/* Offsets to structures within the LDM Database in sectors. */ +#define OFF_PRIV2 1856 /* Backup private headers. */ +#define OFF_PRIV3 2047 + +#define OFF_TOCB1 1 /* Tables of contents. */ +#define OFF_TOCB2 2 +#define OFF_TOCB3 2045 +#define OFF_TOCB4 2046 + +#define OFF_VMDB 17 /* List of partitions. */ + +#define WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */ #define TOC_BITMAP1 "config" /* Names of the two defined */ #define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */ @@ -85,49 +103,42 @@ #define BE32(x) ((u32)be32_to_cpu(get_unaligned((u32*)(x)))) #define BE64(x) ((u64)be64_to_cpu(get_unaligned((u64*)(x)))) -/* Borrowed from msdos.c. */ +/* Borrowed from msdos.c */ #define SYS_IND(p) (get_unaligned(&(p)->sys_ind)) -#define NR_SECTS(p) ({ __typeof__((p)->nr_sects) __a = \ - get_unaligned(&(p)->nr_sects); \ - le32_to_cpu(__a); \ - }) - -#define START_SECT(p) ({ __typeof__((p)->start_sect) __a = \ - get_unaligned(&(p)->start_sect);\ - le32_to_cpu(__a); \ - }) -/* In memory LDM database structures. */ +struct frag { /* VBLK Fragment handling */ + struct list_head list; + u32 group; + u8 num; /* Total number of records */ + u8 rec; /* This is record number n */ + u8 map; /* Which portions are in use */ + u8 data[0]; +}; -#define DISK_ID_SIZE 64 /* Size in bytes. */ +/* In memory LDM database structures. */ -struct ldmdisk { - u64 obj_id; - u8 disk_id[DISK_ID_SIZE]; -}; +#define GUID_SIZE 16 -struct privhead { /* Offsets and sizes are in sectors. */ +struct privhead { /* Offsets and sizes are in sectors. */ u16 ver_major; u16 ver_minor; u64 logical_disk_start; u64 logical_disk_size; u64 config_start; u64 config_size; - u8 disk_id[DISK_ID_SIZE]; + u8 disk_id[GUID_SIZE]; }; struct tocblock { /* We have exactly two bitmaps. */ u8 bitmap1_name[16]; u64 bitmap1_start; u64 bitmap1_size; - /*u64 bitmap1_flags;*/ u8 bitmap2_name[16]; u64 bitmap2_start; u64 bitmap2_size; - /*u64 bitmap2_flags;*/ }; -struct vmdb { +struct vmdb { /* VMDB: The database header */ u16 ver_major; u16 ver_minor; u32 vblk_size; @@ -135,23 +146,76 @@ u32 last_vblk_seq; }; -struct vblk { - u8 name[64]; - u8 vblk_type; - u64 obj_id; +struct vblk_comp { /* VBLK Component */ + u8 state[16]; + u64 parent_id; + u8 type; + u8 children; + u16 chunksize; +}; + +struct vblk_dgrp { /* VBLK Disk Group */ + u8 disk_id[64]; +}; + +struct vblk_disk { /* VBLK Disk */ + u8 disk_id[GUID_SIZE]; + u8 alt_name[128]; +}; + +struct vblk_part { /* VBLK Partition */ + u64 start; + u64 size; /* start, size and vol_off in sectors */ + u64 volume_offset; + u64 parent_id; u64 disk_id; - u64 start_sector; - u64 num_sectors; + u8 partnum; +}; + +struct vblk_volu { /* VBLK Volume */ + u8 volume_type[16]; + u8 volume_state[16]; + u8 guid[16]; + u8 drive_hint[4]; + u64 size; + u8 partition_type; }; -struct ldm_part { - struct list_head part_list; - unsigned long start; - unsigned long size; +struct vblk_head { /* VBLK standard header */ + u32 group; + u16 rec; + u16 nrec; +}; + +struct vblk { /* Generalised VBLK */ + u8 name[64]; + u64 obj_id; + u32 sequence; + u8 flags; + u8 type; + union { + struct vblk_comp comp; + struct vblk_dgrp dgrp; + struct vblk_disk disk; + struct vblk_part part; + struct vblk_volu volu; + } vblk; + struct list_head list; +}; + +struct ldmdb { /* Cache of the database */ + struct privhead ph; + struct tocblock toc; + struct vmdb vm; + struct list_head v_dgrp; + struct list_head v_disk; + struct list_head v_volu; + struct list_head v_comp; + struct list_head v_part; }; -int ldm_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); +int ldm_partition (struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_minor); #endif /* _FS_PT_LDM_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/proc/array.c linux.20pre2-ac1/fs/proc/array.c --- linux.20pre2/fs/proc/array.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/proc/array.c 2002-08-06 15:41:51.000000000 +0100 @@ -338,9 +338,8 @@ /* scale priority and nice values from timeslices to -20..20 */ /* to make it look like a "normal" Unix priority/nice value */ - priority = task->counter; - priority = 20 - (priority * 10 + DEF_COUNTER / 2) / DEF_COUNTER; - nice = task->nice; + priority = task_prio(task); + nice = task_nice(task); read_lock(&tasklist_lock); ppid = task->pid ? task->p_opptr->pid : 0; @@ -390,7 +389,7 @@ task->nswap, task->cnswap, task->exit_signal, - task->processor); + task->cpu); if(mm) mmput(mm); return res; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/proc/proc_misc.c linux.20pre2-ac1/fs/proc/proc_misc.c --- linux.20pre2/fs/proc/proc_misc.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/proc/proc_misc.c 2002-08-13 14:43:44.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -106,11 +107,11 @@ a = avenrun[0] + (FIXED_1/200); b = avenrun[1] + (FIXED_1/200); c = avenrun[2] + (FIXED_1/200); - len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n", + len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running, nr_threads, last_pid); + nr_running(), nr_threads, last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } @@ -122,7 +123,7 @@ int len; uptime = jiffies; - idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime; + idle = init_task.times.tms_utime + init_task.times.tms_stime; /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but that would overflow about every five days at HZ == 100. @@ -155,7 +156,11 @@ struct sysinfo i; int len; int pg_size ; + int committed; + /* FIXME: needs to be in headers */ + extern atomic_t vm_committed_space; + /* * display in kilobytes. */ @@ -164,6 +169,7 @@ si_meminfo(&i); si_swapinfo(&i); pg_size = atomic_read(&page_cache_size) - i.bufferram ; + committed = atomic_read(&vm_committed_space); len = sprintf(page, " total: used: free: shared: buffers: cached:\n" "Mem: %8Lu %8Lu %8Lu %8Lu %8Lu %8Lu\n" @@ -185,13 +191,16 @@ "Cached: %8lu kB\n" "SwapCached: %8lu kB\n" "Active: %8u kB\n" - "Inactive: %8u kB\n" + "Inact_dirty: %8u kB\n" + "Inact_clean: %8u kB\n" + "Inact_target: %8u kB\n" "HighTotal: %8lu kB\n" "HighFree: %8lu kB\n" "LowTotal: %8lu kB\n" "LowFree: %8lu kB\n" "SwapTotal: %8lu kB\n" - "SwapFree: %8lu kB\n", + "SwapFree: %8lu kB\n" + "Committed_AS: %8u kB\n", K(i.totalram), K(i.freeram), K(i.sharedram), @@ -199,13 +208,16 @@ K(pg_size - swapper_space.nrpages), K(swapper_space.nrpages), K(nr_active_pages), - K(nr_inactive_pages), + K(nr_inactive_dirty_pages), + K(nr_inactive_clean_pages), + K(inactive_target()), K(i.totalhigh), K(i.freehigh), K(i.totalram-i.totalhigh), K(i.freeram-i.freehigh), K(i.totalswap), - K(i.freeswap)); + K(i.freeswap), + K(committed)); return proc_calc_metrics(page, start, off, count, eof, len); #undef B @@ -370,11 +382,11 @@ } } - proc_sprintf(page, &off, &len, - "\nctxt %u\n" + len += sprintf(page + len, + "\nctxt %lu\n" "btime %lu\n" "processes %lu\n", - kstat.context_swtch, + nr_context_switches(), xtime.tv_sec - jif / HZ, total_forks); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/proc/root.c linux.20pre2-ac1/fs/proc/root.c --- linux.20pre2/fs/proc/root.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/proc/root.c 2002-08-06 15:41:51.000000000 +0100 @@ -55,6 +55,9 @@ proc_mkdir("openprom", 0); #endif proc_tty_init(); +#ifdef CONFIG_SPEAKUP /* console speech output */ + proc_speakup_init(); /* This has to be early.. */ +#endif /* speakup */ #ifdef CONFIG_PROC_DEVICETREE proc_device_tree_init(); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/quota.c linux.20pre2-ac1/fs/quota.c --- linux.20pre2/fs/quota.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/quota.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,656 @@ +/* + * Quota code necessary even when VFS quota support is not compiled + * into the kernel. The interesting stuff is over in dquot.c, here + * we have symbols for initial quotactl(2) handling, the sysctl(2) + * variables, etc - things needed even when quota support disabled. + */ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_QIFACE_COMPAT +#include +#endif + + +int nr_dquots, nr_free_dquots; + +/* Check validity of quotactl */ +static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +{ + if (type >= MAXQUOTAS) + return -EINVAL; + /* Is operation supported? */ + if (!sb->s_qcop) + return -ENOSYS; + + switch (cmd) { + case Q_GETFMT: + break; + case Q_QUOTAON: + if (!sb->s_qcop->quota_on) + return -ENOSYS; + break; + case Q_QUOTAOFF: + if (!sb->s_qcop->quota_off) + return -ENOSYS; + break; + case Q_SETINFO: + if (!sb->s_qcop->set_info) + return -ENOSYS; + break; + case Q_GETINFO: + if (!sb->s_qcop->get_info) + return -ENOSYS; + break; + case Q_SETQUOTA: + if (!sb->s_qcop->set_dqblk) + return -ENOSYS; + break; + case Q_GETQUOTA: + if (!sb->s_qcop->get_dqblk) + return -ENOSYS; + break; + case Q_SYNC: + if (!sb->s_qcop->quota_sync) + return -ENOSYS; + break; + case Q_XQUOTAON: + case Q_XQUOTAOFF: + case Q_XQUOTARM: + if (!sb->s_qcop->set_xstate) + return -ENOSYS; + break; + case Q_XGETQSTAT: + if (!sb->s_qcop->get_xstate) + return -ENOSYS; + break; + case Q_XSETQLIM: + if (!sb->s_qcop->set_xquota) + return -ENOSYS; + break; + case Q_XGETQUOTA: + if (!sb->s_qcop->get_xquota) + return -ENOSYS; + break; + default: + return -EINVAL; + } + + /* Is quota turned on for commands which need it? */ + switch (cmd) { + case Q_GETFMT: + case Q_GETINFO: + case Q_QUOTAOFF: + case Q_SETINFO: + case Q_SETQUOTA: + case Q_GETQUOTA: + if (!sb_has_quota_enabled(sb, type)) + return -ESRCH; + } + /* Check privileges */ + if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) { + if (((type == USRQUOTA && current->euid != id) || + (type == GRPQUOTA && !in_egroup_p(id))) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + } + else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT) + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + +/* Resolve device pathname to superblock */ +static struct super_block *resolve_dev(const char *path) +{ + int ret; + mode_t mode; + struct nameidata nd; + kdev_t dev; + struct super_block *sb; + + ret = user_path_walk(path, &nd); + if (ret) + goto out; + + dev = nd.dentry->d_inode->i_rdev; + mode = nd.dentry->d_inode->i_mode; + path_release(&nd); + + ret = -ENOTBLK; + if (!S_ISBLK(mode)) + goto out; + ret = -ENODEV; + sb = get_super(dev); + if (!sb) + goto out; + return sb; +out: + return ERR_PTR(ret); +} + +/* Copy parameters and call proper function */ +static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr) +{ + int ret; + + switch (cmd) { + case Q_QUOTAON: { + char *pathname; + + if (IS_ERR(pathname = getname(addr))) + return PTR_ERR(pathname); + ret = sb->s_qcop->quota_on(sb, type, id, pathname); + putname(pathname); + return ret; + } + case Q_QUOTAOFF: + return sb->s_qcop->quota_off(sb, type); + + case Q_GETFMT: { + __u32 fmt; + + fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; + if (copy_to_user(addr, &fmt, sizeof(fmt))) + return -EFAULT; + return 0; + } + case Q_GETINFO: { + struct if_dqinfo info; + + if ((ret = sb->s_qcop->get_info(sb, type, &info))) + return ret; + if (copy_to_user(addr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case Q_SETINFO: { + struct if_dqinfo info; + + if (copy_from_user(&info, addr, sizeof(info))) + return -EFAULT; + return sb->s_qcop->set_info(sb, type, &info); + } + case Q_GETQUOTA: { + struct if_dqblk idq; + + if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq))) + return ret; + if (copy_to_user(addr, &idq, sizeof(idq))) + return -EFAULT; + return 0; + } + case Q_SETQUOTA: { + struct if_dqblk idq; + + if (copy_from_user(&idq, addr, sizeof(idq))) + return -EFAULT; + return sb->s_qcop->set_dqblk(sb, type, id, &idq); + } + case Q_SYNC: + return sb->s_qcop->quota_sync(sb, type); + + case Q_XQUOTAON: + case Q_XQUOTAOFF: + case Q_XQUOTARM: { + __u32 flags; + + if (copy_from_user(&flags, addr, sizeof(flags))) + return -EFAULT; + return sb->s_qcop->set_xstate(sb, flags, cmd); + } + case Q_XGETQSTAT: { + struct fs_quota_stat fqs; + + if ((ret = sb->s_qcop->get_xstate(sb, &fqs))) + return ret; + if (copy_to_user(addr, &fqs, sizeof(fqs))) + return -EFAULT; + return 0; + } + case Q_XSETQLIM: { + struct fs_disk_quota fdq; + + if (copy_from_user(&fdq, addr, sizeof(fdq))) + return -EFAULT; + return sb->s_qcop->set_xquota(sb, type, id, &fdq); + } + case Q_XGETQUOTA: { + struct fs_disk_quota fdq; + + if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq))) + return ret; + if (copy_to_user(addr, &fdq, sizeof(fdq))) + return -EFAULT; + return 0; + } + /* We never reach here unless validity check is broken */ + default: + BUG(); + } + return 0; +} + +#ifdef CONFIG_QIFACE_COMPAT +static int check_compat_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +{ + if (type >= MAXQUOTAS) + return -EINVAL; + /* Is operation supported? */ + /* sb==NULL for GETSTATS calls */ + if (sb && !sb->s_qcop) + return -ENOSYS; + + switch (cmd) { + case Q_COMP_QUOTAON: + if (!sb->s_qcop->quota_on) + return -ENOSYS; + break; + case Q_COMP_QUOTAOFF: + if (!sb->s_qcop->quota_off) + return -ENOSYS; + break; + case Q_COMP_SYNC: + if (!sb->s_qcop->quota_sync) + return -ENOSYS; + break; +#ifdef CONFIG_QIFACE_V2 + case Q_V2_SETFLAGS: + case Q_V2_SETGRACE: + case Q_V2_SETINFO: + if (!sb->s_qcop->set_info) + return -ENOSYS; + break; + case Q_V2_GETINFO: + if (!sb->s_qcop->get_info) + return -ENOSYS; + break; + case Q_V2_SETQLIM: + case Q_V2_SETUSE: + case Q_V2_SETQUOTA: + if (!sb->s_qcop->set_dqblk) + return -ENOSYS; + break; + case Q_V2_GETQUOTA: + if (!sb->s_qcop->get_dqblk) + return -ENOSYS; + break; + case Q_V2_GETSTATS: + return 0; /* GETSTATS need no other checks */ +#endif +#ifdef CONFIG_QIFACE_V1 + case Q_V1_SETQLIM: + case Q_V1_SETUSE: + case Q_V1_SETQUOTA: + if (!sb->s_qcop->set_dqblk) + return -ENOSYS; + break; + case Q_V1_GETQUOTA: + if (!sb->s_qcop->get_dqblk) + return -ENOSYS; + break; + case Q_V1_RSQUASH: + if (!sb->s_qcop->set_info) + return -ENOSYS; + break; + case Q_V1_GETSTATS: + return 0; /* GETSTATS need no other checks */ +#endif + default: + return -EINVAL; + } + + /* Is quota turned on for commands which need it? */ + switch (cmd) { + case Q_V2_SETFLAGS: + case Q_V2_SETGRACE: + case Q_V2_SETINFO: + case Q_V2_GETINFO: + case Q_COMP_QUOTAOFF: + case Q_V1_RSQUASH: + case Q_V1_SETQUOTA: + case Q_V1_SETQLIM: + case Q_V1_SETUSE: + case Q_V2_SETQUOTA: + /* Q_V2_SETQLIM: collision with Q_V1_SETQLIM */ + case Q_V2_SETUSE: + case Q_V1_GETQUOTA: + case Q_V2_GETQUOTA: + if (!sb_has_quota_enabled(sb, type)) + return -ESRCH; + } +#ifdef CONFIG_QIFACE_V1 + if (cmd != Q_COMP_QUOTAON && cmd != Q_COMP_QUOTAOFF && cmd != Q_COMP_SYNC && sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_OLD) +#else + if (cmd != Q_COMP_QUOTAON && cmd != Q_COMP_QUOTAOFF && cmd != Q_COMP_SYNC && sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_V0) +#endif + return -ESRCH; + + /* Check privileges */ + if (cmd == Q_V1_GETQUOTA || cmd == Q_V2_GETQUOTA) { + if (((type == USRQUOTA && current->euid != id) || + (type == GRPQUOTA && !in_egroup_p(id))) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + } + else if (cmd != Q_V1_GETSTATS && cmd != Q_V2_GETSTATS && cmd != Q_V2_GETINFO && cmd != Q_COMP_SYNC) + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + +#ifdef CONFIG_QIFACE_V1 +static int v1_set_rsquash(struct super_block *sb, int type, int flag) +{ + struct if_dqinfo info; + + info.dqi_valid = IIF_FLAGS; + info.dqi_flags = flag ? V1_DQF_RSQUASH : 0; + return sb->s_qcop->set_info(sb, type, &info); +} + +static int v1_get_dqblk(struct super_block *sb, int type, qid_t id, struct v1c_mem_dqblk *mdq) +{ + struct if_dqblk idq; + int ret; + + if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0) + return ret; + mdq->dqb_ihardlimit = idq.dqb_ihardlimit; + mdq->dqb_isoftlimit = idq.dqb_isoftlimit; + mdq->dqb_curinodes = idq.dqb_curinodes; + mdq->dqb_bhardlimit = idq.dqb_bhardlimit; + mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit; + mdq->dqb_curblocks = toqb(idq.dqb_curspace); + mdq->dqb_itime = idq.dqb_itime; + mdq->dqb_btime = idq.dqb_btime; + if (id == 0) { /* Times for id 0 are in fact grace times */ + struct if_dqinfo info; + + if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0) + return ret; + mdq->dqb_btime = info.dqi_bgrace; + mdq->dqb_itime = info.dqi_igrace; + } + return 0; +} + +static int v1_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v1c_mem_dqblk *mdq) +{ + struct if_dqblk idq; + int ret; + + idq.dqb_valid = 0; + if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETQLIM) { + idq.dqb_ihardlimit = mdq->dqb_ihardlimit; + idq.dqb_isoftlimit = mdq->dqb_isoftlimit; + idq.dqb_bhardlimit = mdq->dqb_bhardlimit; + idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit; + idq.dqb_valid |= QIF_LIMITS; + } + if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETUSE) { + idq.dqb_curinodes = mdq->dqb_curinodes; + idq.dqb_curspace = ((qsize_t)mdq->dqb_curblocks) << QUOTABLOCK_BITS; + idq.dqb_valid |= QIF_USAGE; + } + ret = sb->s_qcop->set_dqblk(sb, type, id, &idq); + if (!ret && id == 0 && cmd == Q_V1_SETQUOTA) { /* Times for id 0 are in fact grace times */ + struct if_dqinfo info; + + info.dqi_bgrace = mdq->dqb_btime; + info.dqi_igrace = mdq->dqb_itime; + info.dqi_valid = IIF_BGRACE | IIF_IGRACE; + ret = sb->s_qcop->set_info(sb, type, &info); + } + return ret; +} + +static void v1_get_stats(struct v1c_dqstats *dst) +{ + memcpy(dst, &dqstats, sizeof(dqstats)); +} +#endif + +#ifdef CONFIG_QIFACE_V2 +static int v2_get_info(struct super_block *sb, int type, struct v2c_mem_dqinfo *oinfo) +{ + struct if_dqinfo info; + int ret; + + if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0) + return ret; + oinfo->dqi_bgrace = info.dqi_bgrace; + oinfo->dqi_igrace = info.dqi_igrace; + oinfo->dqi_flags = info.dqi_flags; + oinfo->dqi_blocks = sb_dqopt(sb)->info[type].u.v2_i.dqi_blocks; + oinfo->dqi_free_blk = sb_dqopt(sb)->info[type].u.v2_i.dqi_free_blk; + oinfo->dqi_free_entry = sb_dqopt(sb)->info[type].u.v2_i.dqi_free_entry; + return 0; +} + +static int v2_set_info(struct super_block *sb, int type, int cmd, struct v2c_mem_dqinfo *oinfo) +{ + struct if_dqinfo info; + + info.dqi_valid = 0; + if (cmd == Q_V2_SETGRACE || cmd == Q_V2_SETINFO) { + info.dqi_bgrace = oinfo->dqi_bgrace; + info.dqi_igrace = oinfo->dqi_igrace; + info.dqi_valid |= IIF_BGRACE | IIF_IGRACE; + } + if (cmd == Q_V2_SETFLAGS || cmd == Q_V2_SETINFO) { + info.dqi_flags = oinfo->dqi_flags; + info.dqi_valid |= IIF_FLAGS; + } + /* We don't simulate deadly effects of setting other parameters ;-) */ + return sb->s_qcop->set_info(sb, type, &info); +} + +static int v2_get_dqblk(struct super_block *sb, int type, qid_t id, struct v2c_mem_dqblk *mdq) +{ + struct if_dqblk idq; + int ret; + + if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0) + return ret; + mdq->dqb_ihardlimit = idq.dqb_ihardlimit; + mdq->dqb_isoftlimit = idq.dqb_isoftlimit; + mdq->dqb_curinodes = idq.dqb_curinodes; + mdq->dqb_bhardlimit = idq.dqb_bhardlimit; + mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit; + mdq->dqb_curspace = idq.dqb_curspace; + mdq->dqb_itime = idq.dqb_itime; + mdq->dqb_btime = idq.dqb_btime; + return 0; +} + +static int v2_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v2c_mem_dqblk *mdq) +{ + struct if_dqblk idq; + + idq.dqb_valid = 0; + if (cmd == Q_V2_SETQUOTA || cmd == Q_V2_SETQLIM) { + idq.dqb_ihardlimit = mdq->dqb_ihardlimit; + idq.dqb_isoftlimit = mdq->dqb_isoftlimit; + idq.dqb_bhardlimit = mdq->dqb_bhardlimit; + idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit; + idq.dqb_valid |= QIF_LIMITS; + } + if (cmd == Q_V2_SETQUOTA || cmd == Q_V2_SETUSE) { + idq.dqb_curinodes = mdq->dqb_curinodes; + idq.dqb_curspace = mdq->dqb_curspace; + idq.dqb_valid |= QIF_USAGE; + } + return sb->s_qcop->set_dqblk(sb, type, id, &idq); +} + +static void v2_get_stats(struct v2c_dqstats *dst) +{ + memcpy(dst, &dqstats, sizeof(dqstats)); + dst->version = __DQUOT_NUM_VERSION__; +} +#endif + +/* Handle requests to old interface */ +static int do_compat_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr) +{ + int ret; + + switch (cmd) { + case Q_COMP_QUOTAON: { + char *pathname; + + if (IS_ERR(pathname = getname(addr))) + return PTR_ERR(pathname); +#ifdef CONFIG_QIFACE_V1 + ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_OLD, pathname); +#else + ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_V0, pathname); +#endif + putname(pathname); + return ret; + } + case Q_COMP_QUOTAOFF: + return sb->s_qcop->quota_off(sb, type); + case Q_COMP_SYNC: + return sb->s_qcop->quota_sync(sb, type); +#ifdef CONFIG_QIFACE_V1 + case Q_V1_RSQUASH: { + int flag; + + if (copy_from_user(&flag, addr, sizeof(flag))) + return -EFAULT; + return v1_set_rsquash(sb, type, flag); + } + case Q_V1_GETQUOTA: { + struct v1c_mem_dqblk mdq; + + if ((ret = v1_get_dqblk(sb, type, id, &mdq))) + return ret; + if (copy_to_user(addr, &mdq, sizeof(mdq))) + return -EFAULT; + return 0; + } + case Q_V1_SETQLIM: + case Q_V1_SETUSE: + case Q_V1_SETQUOTA: { + struct v1c_mem_dqblk mdq; + + if (copy_from_user(&mdq, addr, sizeof(mdq))) + return -EFAULT; + return v1_set_dqblk(sb, type, cmd, id, &mdq); + } + case Q_V1_GETSTATS: { + struct v1c_dqstats dst; + + v1_get_stats(&dst); + if (copy_to_user(addr, &dst, sizeof(dst))) + return -EFAULT; + return 0; + } +#endif +#ifdef CONFIG_QIFACE_V2 + case Q_V2_GETINFO: { + struct v2c_mem_dqinfo info; + + if ((ret = v2_get_info(sb, type, &info))) + return ret; + if (copy_to_user(addr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case Q_V2_SETFLAGS: + case Q_V2_SETGRACE: + case Q_V2_SETINFO: { + struct v2c_mem_dqinfo info; + + if (copy_from_user(&info, addr, sizeof(info))) + return -EFAULT; + + return v2_set_info(sb, type, cmd, &info); + } + case Q_V2_GETQUOTA: { + struct v2c_mem_dqblk mdq; + + if ((ret = v2_get_dqblk(sb, type, id, &mdq))) + return ret; + if (copy_to_user(addr, &mdq, sizeof(mdq))) + return -EFAULT; + return 0; + } + case Q_V2_SETUSE: + case Q_V2_SETQLIM: + case Q_V2_SETQUOTA: { + struct v2c_mem_dqblk mdq; + + if (copy_from_user(&mdq, addr, sizeof(mdq))) + return -EFAULT; + return v2_set_dqblk(sb, type, cmd, id, &mdq); + } + case Q_V2_GETSTATS: { + struct v2c_dqstats dst; + + v2_get_stats(&dst); + if (copy_to_user(addr, &dst, sizeof(dst))) + return -EFAULT; + return 0; + } +#endif + } + BUG(); + return 0; +} +#endif + +/* Macros for short-circuiting the compatibility tests */ +#define NEW_COMMAND(c) ((c) & (0x80 << 16)) +#define XQM_COMMAND(c) (((c) & ('X' << 8)) == ('X' << 8)) + +/* + * This is the system call interface. This communicates with + * the user-level programs. Currently this only supports diskquota + * calls. Maybe we need to add the process quotas etc. in the future, + * but we probably should use rlimits for that. + */ +asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr) +{ + uint cmds, type; + struct super_block *sb = NULL; + int ret = -EINVAL; + + lock_kernel(); + cmds = cmd >> SUBCMDSHIFT; + type = cmd & SUBCMDMASK; + +#ifdef CONFIG_QIFACE_COMPAT + if (cmds != Q_V1_GETSTATS && cmds != Q_V2_GETSTATS && IS_ERR(sb = resolve_dev(special))) { + ret = PTR_ERR(sb); + sb = NULL; + goto out; + } + if (!NEW_COMMAND(cmds) && !XQM_COMMAND(cmds)) { + if ((ret = check_compat_quotactl_valid(sb, type, cmds, id)) < 0) + goto out; + ret = do_compat_quotactl(sb, type, cmds, id, addr); + goto out; + } +#else + if (IS_ERR(sb = resolve_dev(special))) { + ret = PTR_ERR(sb); + sb = NULL; + goto out; + } +#endif + if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0) + goto out; + ret = do_quotactl(sb, type, cmds, id, addr); +out: + if (sb) + drop_super(sb); + unlock_kernel(); + return ret; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/quota_v1.c linux.20pre2-ac1/fs/quota_v1.c --- linux.20pre2/fs/quota_v1.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/quota_v1.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void v1_disk2mem_dqblk(struct mem_dqblk *m, struct v1_disk_dqblk *d) +{ + m->dqb_ihardlimit = d->dqb_ihardlimit; + m->dqb_isoftlimit = d->dqb_isoftlimit; + m->dqb_curinodes = d->dqb_curinodes; + m->dqb_bhardlimit = d->dqb_bhardlimit; + m->dqb_bsoftlimit = d->dqb_bsoftlimit; + m->dqb_curspace = d->dqb_curblocks << QUOTABLOCK_BITS; + m->dqb_itime = d->dqb_itime; + m->dqb_btime = d->dqb_btime; +} + +static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m) +{ + d->dqb_ihardlimit = m->dqb_ihardlimit; + d->dqb_isoftlimit = m->dqb_isoftlimit; + d->dqb_curinodes = m->dqb_curinodes; + d->dqb_bhardlimit = m->dqb_bhardlimit; + d->dqb_bsoftlimit = m->dqb_bsoftlimit; + d->dqb_curblocks = toqb(m->dqb_curspace); + d->dqb_itime = m->dqb_itime; + d->dqb_btime = m->dqb_btime; +} + +static int v1_read_dqblk(struct dquot *dquot) +{ + int type = dquot->dq_type; + struct file *filp; + mm_segment_t fs; + loff_t offset; + struct v1_disk_dqblk dqblk; + + filp = sb_dqopt(dquot->dq_sb)->files[type]; + if (filp == (struct file *)NULL) + return -EINVAL; + + /* Now we are sure filp is valid */ + offset = v1_dqoff(dquot->dq_id); + fs = get_fs(); + set_fs(KERNEL_DS); + filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset); + set_fs(fs); + + v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk); + if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 && + dquot->dq_dqb.dqb_ihardlimit == 0 && dquot->dq_dqb.dqb_isoftlimit == 0) + dquot->dq_flags |= DQ_FAKE; + dqstats.reads++; + return 0; +} + +static int v1_commit_dqblk(struct dquot *dquot) +{ + short type = dquot->dq_type; + struct file *filp; + mm_segment_t fs; + loff_t offset; + ssize_t ret; + struct v1_disk_dqblk dqblk; + + filp = sb_dqopt(dquot->dq_sb)->files[type]; + offset = v1_dqoff(dquot->dq_id); + fs = get_fs(); + set_fs(KERNEL_DS); + + /* + * Note: clear the DQ_MOD flag unconditionally, + * so we don't loop forever on failure. + */ + v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb); + dquot->dq_flags &= ~DQ_MOD; + if (dquot->dq_id == 0) { + dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace; + dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace; + } + ret = 0; + if (filp) + ret = filp->f_op->write(filp, (char *)&dqblk, + sizeof(struct v1_disk_dqblk), &offset); + if (ret != sizeof(struct v1_disk_dqblk)) { + printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", + kdevname(dquot->dq_dev)); + if (ret >= 0) + ret = -EIO; + goto out; + } + ret = 0; + +out: + set_fs(fs); + dqstats.writes++; + return ret; +} + +/* Magics of new quota format */ +#define V2_INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} + +/* Header of new quota format */ +struct v2_disk_dqheader { + __u32 dqh_magic; /* Magic number identifying file */ + __u32 dqh_version; /* File version */ +}; + +static int v1_check_quota_file(struct super_block *sb, int type) +{ + struct file *f = sb_dqopt(sb)->files[type]; + struct inode *inode = f->f_dentry->d_inode; + ulong blocks; + size_t off; + struct v2_disk_dqheader dqhead; + mm_segment_t fs; + ssize_t size; + loff_t offset = 0; + static const uint quota_magics[] = V2_INITQMAGICS; + + if (!inode->i_size) + return 0; + blocks = inode->i_size >> BLOCK_SIZE_BITS; + off = inode->i_size & (BLOCK_SIZE - 1); + if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % sizeof(struct v1_disk_dqblk)) + return 0; + /* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */ + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset); + set_fs(fs); + if (size != sizeof(struct v2_disk_dqheader)) + return 1; /* Probably not new format */ + if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type]) + return 1; /* Definitely not new format */ + printk(KERN_INFO "VFS: %s: Refusing to turn on old quota format on given file. It probably contains newer quota format.\n", kdevname(sb->s_dev)); + return 0; /* Seems like a new format file -> refuse it */ +} + +static int v1_read_file_info(struct super_block *sb, int type) +{ + struct quota_info *dqopt = sb_dqopt(sb); + mm_segment_t fs; + loff_t offset; + struct file *filp = dqopt->files[type]; + struct v1_disk_dqblk dqblk; + int ret; + + down(&dqopt->dqio_sem); + offset = v1_dqoff(0); + fs = get_fs(); + set_fs(KERNEL_DS); + if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) { + if (ret >= 0) + ret = -EIO; + goto out; + } + ret = 0; + dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME; + dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME; +out: + up(&dqopt->dqio_sem); + set_fs(fs); + return ret; +} + +static int v1_write_file_info(struct super_block *sb, int type) +{ + struct quota_info *dqopt = sb_dqopt(sb); + mm_segment_t fs; + struct file *filp = dqopt->files[type]; + struct v1_disk_dqblk dqblk; + loff_t offset; + int ret; + + down(&dqopt->dqio_sem); + dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY; + offset = v1_dqoff(0); + fs = get_fs(); + set_fs(KERNEL_DS); + if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) { + if (ret >= 0) + ret = -EIO; + goto out; + } + dqblk.dqb_itime = dqopt->info[type].dqi_igrace; + dqblk.dqb_btime = dqopt->info[type].dqi_bgrace; + offset = v1_dqoff(0); + ret = filp->f_op->write(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset); + if (ret == sizeof(struct v1_disk_dqblk)) + ret = 0; + else if (ret > 0) + ret = -EIO; +out: + up(&dqopt->dqio_sem); + set_fs(fs); + return ret; +} + +static struct quota_format_ops v1_format_ops = { + check_quota_file: v1_check_quota_file, + read_file_info: v1_read_file_info, + write_file_info: v1_write_file_info, + free_file_info: NULL, + read_dqblk: v1_read_dqblk, + commit_dqblk: v1_commit_dqblk, +}; + +static struct quota_format_type v1_quota_format = { + qf_fmt_id: QFMT_VFS_OLD, + qf_ops: &v1_format_ops, + qf_owner: THIS_MODULE +}; + +static int __init init_v1_quota_format(void) +{ + return register_quota_format(&v1_quota_format); +} + +static void __exit exit_v1_quota_format(void) +{ + unregister_quota_format(&v1_quota_format); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_v1_quota_format); +module_exit(exit_v1_quota_format); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/quota_v2.c linux.20pre2-ac1/fs/quota_v2.c --- linux.20pre2/fs/quota_v2.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/fs/quota_v2.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,690 @@ +/* + * vfsv0 quota IO operations on file + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define __QUOTA_V2_PARANOIA + +typedef char *dqbuf_t; + +#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) +#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader))) + +/* Check whether given file is really vfsv0 quotafile */ +static int v2_check_quota_file(struct super_block *sb, int type) +{ + struct v2_disk_dqheader dqhead; + struct file *f = sb_dqopt(sb)->files[type]; + mm_segment_t fs; + ssize_t size; + loff_t offset = 0; + static const uint quota_magics[] = V2_INITQMAGICS; + static const uint quota_versions[] = V2_INITQVERSIONS; + + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset); + set_fs(fs); + if (size != sizeof(struct v2_disk_dqheader)) + return 0; + if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] || + le32_to_cpu(dqhead.dqh_version) != quota_versions[type]) + return 0; + return 1; +} + +/* Read information header from quota file */ +static int v2_read_file_info(struct super_block *sb, int type) +{ + mm_segment_t fs; + struct v2_disk_dqinfo dinfo; + struct mem_dqinfo *info = sb_dqopt(sb)->info+type; + struct file *f = sb_dqopt(sb)->files[type]; + ssize_t size; + loff_t offset = V2_DQINFOOFF; + + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->read(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset); + set_fs(fs); + if (size != sizeof(struct v2_disk_dqinfo)) { + printk(KERN_WARNING "Can't read info structure on device %s.\n", + kdevname(f->f_dentry->d_sb->s_dev)); + return -1; + } + info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); + info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); + info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); + info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); + info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); + info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); + return 0; +} + +/* Write information header to quota file */ +static int v2_write_file_info(struct super_block *sb, int type) +{ + mm_segment_t fs; + struct v2_disk_dqinfo dinfo; + struct mem_dqinfo *info = sb_dqopt(sb)->info+type; + struct file *f = sb_dqopt(sb)->files[type]; + ssize_t size; + loff_t offset = V2_DQINFOOFF; + + info->dqi_flags &= ~DQF_INFO_DIRTY; + dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace); + dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); + dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); + dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks); + dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk); + dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry); + fs = get_fs(); + set_fs(KERNEL_DS); + size = f->f_op->write(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset); + set_fs(fs); + if (size != sizeof(struct v2_disk_dqinfo)) { + printk(KERN_WARNING "Can't write info structure on device %s.\n", + kdevname(f->f_dentry->d_sb->s_dev)); + return -1; + } + return 0; +} + +static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d) +{ + m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); + m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit); + m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes); + m->dqb_itime = le64_to_cpu(d->dqb_itime); + m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit); + m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit); + m->dqb_curspace = le64_to_cpu(d->dqb_curspace); + m->dqb_btime = le64_to_cpu(d->dqb_btime); +} + +static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) +{ + d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit); + d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); + d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); + d->dqb_itime = cpu_to_le64(m->dqb_itime); + d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit); + d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit); + d->dqb_curspace = cpu_to_le64(m->dqb_curspace); + d->dqb_btime = cpu_to_le64(m->dqb_btime); + d->dqb_id = cpu_to_le32(id); +} + +static dqbuf_t getdqbuf(void) +{ + dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_KERNEL); + if (!buf) + printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n"); + return buf; +} + +static inline void freedqbuf(dqbuf_t buf) +{ + kfree(buf); +} + +static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf) +{ + mm_segment_t fs; + ssize_t ret; + loff_t offset = blk<f_op->read(filp, (char *)buf, V2_DQBLKSIZE, &offset); + set_fs(fs); + return ret; +} + +static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf) +{ + mm_segment_t fs; + ssize_t ret; + loff_t offset = blk<f_op->write(filp, (char *)buf, V2_DQBLKSIZE, &offset); + set_fs(fs); + return ret; + +} + +/* Remove empty block from list and return it */ +static int get_free_dqblk(struct file *filp, struct mem_dqinfo *info) +{ + dqbuf_t buf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + int ret, blk; + + if (!buf) + return -ENOMEM; + if (info->u.v2_i.dqi_free_blk) { + blk = info->u.v2_i.dqi_free_blk; + if ((ret = read_blk(filp, blk, buf)) < 0) + goto out_buf; + info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); + } + else { + memset(buf, 0, V2_DQBLKSIZE); + if ((ret = write_blk(filp, info->u.v2_i.dqi_blocks, buf)) < 0) /* Assure block allocation... */ + goto out_buf; + blk = info->u.v2_i.dqi_blocks++; + } + mark_info_dirty(info); + ret = blk; +out_buf: + freedqbuf(buf); + return ret; +} + +/* Insert empty block to the list */ +static int put_free_dqblk(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + int err; + + dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk); + dh->dqdh_prev_free = cpu_to_le32(0); + dh->dqdh_entries = cpu_to_le16(0); + info->u.v2_i.dqi_free_blk = blk; + mark_info_dirty(info); + if ((err = write_blk(filp, blk, buf)) < 0) /* Some strange block. We had better leave it... */ + return err; + return 0; +} + +/* Remove given block from the list of blocks with free entries */ +static int remove_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free); + int err; + + if (!tmpbuf) + return -ENOMEM; + if (nextblk) { + if ((err = read_blk(filp, nextblk, tmpbuf)) < 0) + goto out_buf; + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free; + if ((err = write_blk(filp, nextblk, tmpbuf)) < 0) + goto out_buf; + } + if (prevblk) { + if ((err = read_blk(filp, prevblk, tmpbuf)) < 0) + goto out_buf; + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free; + if ((err = write_blk(filp, prevblk, tmpbuf)) < 0) + goto out_buf; + } + else { + info->u.v2_i.dqi_free_entry = nextblk; + mark_info_dirty(info); + } + freedqbuf(tmpbuf); + dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); + if (write_blk(filp, blk, buf) < 0) /* No matter whether write succeeds block is out of list */ + printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk); + return 0; +out_buf: + freedqbuf(tmpbuf); + return err; +} + +/* Insert given block to the beginning of list with free entries */ +static int insert_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; + int err; + + if (!tmpbuf) + return -ENOMEM; + dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry); + dh->dqdh_prev_free = cpu_to_le32(0); + if ((err = write_blk(filp, blk, buf)) < 0) + goto out_buf; + if (info->u.v2_i.dqi_free_entry) { + if ((err = read_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0) + goto out_buf; + ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk); + if ((err = write_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0) + goto out_buf; + } + freedqbuf(tmpbuf); + info->u.v2_i.dqi_free_entry = blk; + mark_info_dirty(info); + return 0; +out_buf: + freedqbuf(tmpbuf); + return err; +} + +/* Find space for dquot */ +static uint find_free_dqentry(struct dquot *dquot, int *err) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info+dquot->dq_type; + uint blk, i; + struct v2_disk_dqdbheader *dh; + struct v2_disk_dqblk *ddquot; + struct v2_disk_dqblk fakedquot; + dqbuf_t buf; + + *err = 0; + if (!(buf = getdqbuf())) { + *err = -ENOMEM; + return 0; + } + dh = (struct v2_disk_dqdbheader *)buf; + ddquot = GETENTRIES(buf); + if (info->u.v2_i.dqi_free_entry) { + blk = info->u.v2_i.dqi_free_entry; + if ((*err = read_blk(filp, blk, buf)) < 0) + goto out_buf; + } + else { + blk = get_free_dqblk(filp, info); + if ((int)blk < 0) { + *err = blk; + return 0; + } + memset(buf, 0, V2_DQBLKSIZE); + info->u.v2_i.dqi_free_entry = blk; /* This is enough as block is already zeroed and entry list is empty... */ + mark_info_dirty(info); + } + if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */ + if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk); + goto out_buf; + } + dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1); + memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); + /* Find free structure in block */ + for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++); +#ifdef __QUOTA_V2_PARANOIA + if (i == V2_DQSTRINBLK) { + printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n"); + *err = -EIO; + goto out_buf; + } +#endif + if ((*err = write_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk); + goto out_buf; + } + dquot->dq_off = (blk<dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + dqbuf_t buf; + int ret = 0, newson = 0, newact = 0; + u32 *ref; + uint newblk; + + if (!(buf = getdqbuf())) + return -ENOMEM; + if (!*treeblk) { + ret = get_free_dqblk(filp, info); + if (ret < 0) + goto out_buf; + *treeblk = ret; + memset(buf, 0, V2_DQBLKSIZE); + newact = 1; + } + else { + if ((ret = read_blk(filp, *treeblk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk); + goto out_buf; + } + } + ref = (u32 *)buf; + newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (!newblk) + newson = 1; + if (depth == V2_DQTREEDEPTH-1) { +#ifdef __QUOTA_V2_PARANOIA + if (newblk) { + printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]); + ret = -EIO; + goto out_buf; + } +#endif + newblk = find_free_dqentry(dquot, &ret); + } + else + ret = do_insert_tree(dquot, &newblk, depth+1); + if (newson && ret >= 0) { + ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk); + ret = write_blk(filp, *treeblk, buf); + } + else if (newact && ret < 0) + put_free_dqblk(filp, info, buf, *treeblk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Wrapper for inserting quota structure into tree */ +static inline int dq_insert_tree(struct dquot *dquot) +{ + int tmp = V2_DQTREEOFF; + return do_insert_tree(dquot, &tmp, 0); +} + +/* + * We don't have to be afraid of deadlocks as we never have quotas on quota files... + */ +static int v2_write_dquot(struct dquot *dquot) +{ + int type = dquot->dq_type; + struct file *filp; + mm_segment_t fs; + loff_t offset; + ssize_t ret; + struct v2_disk_dqblk ddquot; + + if (!dquot->dq_off) + if ((ret = dq_insert_tree(dquot)) < 0) { + printk(KERN_ERR "VFS: Error %d occured while creating quota.\n", ret); + return ret; + } + filp = sb_dqopt(dquot->dq_sb)->files[type]; + offset = dquot->dq_off; + mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); + fs = get_fs(); + set_fs(KERNEL_DS); + ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset); + set_fs(fs); + if (ret != sizeof(struct v2_disk_dqblk)) { + printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", kdevname(dquot->dq_dev)); + if (ret >= 0) + ret = -ENOSPC; + } + else + ret = 0; + dqstats.writes++; + return ret; +} + +/* Free dquot entry in data block */ +static int free_dqentry(struct dquot *dquot, uint blk) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + struct v2_disk_dqdbheader *dh; + dqbuf_t buf = getdqbuf(); + int ret = 0; + + if (!buf) + return -ENOMEM; + if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) { + printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS)); + goto out_buf; + } + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); + goto out_buf; + } + dh = (struct v2_disk_dqdbheader *)buf; + dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1); + if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ + if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 || + (ret = put_free_dqblk(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk); + goto out_buf; + } + } + else { + memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk)); + if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) { + /* Insert will write block itself */ + if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) { + printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk); + goto out_buf; + } + } + else + if ((ret = write_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk); + goto out_buf; + } + } + dquot->dq_off = 0; /* Quota is now unattached */ +out_buf: + freedqbuf(buf); + return ret; +} + +/* Remove reference to dquot from tree */ +static int remove_tree(struct dquot *dquot, uint *blk, int depth) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + dqbuf_t buf = getdqbuf(); + int ret = 0; + uint newblk; + u32 *ref = (u32 *)buf; + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, *blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); + goto out_buf; + } + newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (depth == V2_DQTREEDEPTH-1) { + ret = free_dqentry(dquot, newblk); + newblk = 0; + } + else + ret = remove_tree(dquot, &newblk, depth+1); + if (ret >= 0 && !newblk) { + int i; + ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0); + for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */ + if (i == V2_DQBLKSIZE) { + put_free_dqblk(filp, info, buf, *blk); + *blk = 0; + } + else + if ((ret = write_blk(filp, *blk, buf)) < 0) + printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk); + } +out_buf: + freedqbuf(buf); + return ret; +} + +/* Delete dquot from tree */ +static int v2_delete_dquot(struct dquot *dquot) +{ + uint tmp = V2_DQTREEOFF; + + if (!dquot->dq_off) /* Even not allocated? */ + return 0; + return remove_tree(dquot, &tmp, 0); +} + +/* Find entry in block */ +static loff_t find_block_dqentry(struct dquot *dquot, uint blk) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + dqbuf_t buf = getdqbuf(); + loff_t ret = 0; + int i; + struct v2_disk_dqblk *ddquot = GETENTRIES(buf); + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); + goto out_buf; + } + if (dquot->dq_id) + for (i = 0; i < V2_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++); + else { /* ID 0 as a bit more complicated searching... */ + struct v2_disk_dqblk fakedquot; + + memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); + for (i = 0; i < V2_DQSTRINBLK; i++) + if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk))) + break; + } + if (i == V2_DQSTRINBLK) { + printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id); + ret = -EIO; + goto out_buf; + } + else + ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree */ +static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth) +{ + struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + dqbuf_t buf = getdqbuf(); + loff_t ret = 0; + u32 *ref = (u32 *)buf; + + if (!buf) + return -ENOMEM; + if ((ret = read_blk(filp, blk, buf)) < 0) { + printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); + goto out_buf; + } + ret = 0; + blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); + if (!blk) /* No reference? */ + goto out_buf; + if (depth < V2_DQTREEDEPTH-1) + ret = find_tree_dqentry(dquot, blk, depth+1); + else + ret = find_block_dqentry(dquot, blk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree - wrapper function */ +static inline loff_t find_dqentry(struct dquot *dquot) +{ + return find_tree_dqentry(dquot, V2_DQTREEOFF, 0); +} + +static int v2_read_dquot(struct dquot *dquot) +{ + int type = dquot->dq_type; + struct file *filp; + mm_segment_t fs; + loff_t offset; + struct v2_disk_dqblk ddquot; + int ret = 0; + + filp = sb_dqopt(dquot->dq_sb)->files[type]; + +#ifdef __QUOTA_V2_PARANOIA + if (!filp || !dquot->dq_sb) { /* Invalidated quota? */ + printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); + return -EIO; + } +#endif + offset = find_dqentry(dquot); + if (offset <= 0) { /* Entry not present? */ + if (offset < 0) + printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id); + dquot->dq_off = 0; + dquot->dq_flags |= DQ_FAKE; + memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); + ret = offset; + } + else { + dquot->dq_off = offset; + fs = get_fs(); + set_fs(KERNEL_DS); + if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) { + if (ret >= 0) + ret = -EIO; + printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id); + memset(&ddquot, 0, sizeof(struct v2_disk_dqblk)); + } + else + ret = 0; + set_fs(fs); + disk2memdqb(&dquot->dq_dqb, &ddquot); + } + dqstats.reads++; + return ret; +} + +/* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */ +static int v2_commit_dquot(struct dquot *dquot) +{ + /* We clear the flag everytime so we don't loop when there was an IO error... */ + dquot->dq_flags &= ~DQ_MOD; + if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) + return v2_delete_dquot(dquot); + else + return v2_write_dquot(dquot); +} + +static struct quota_format_ops v2_format_ops = { + check_quota_file: v2_check_quota_file, + read_file_info: v2_read_file_info, + write_file_info: v2_write_file_info, + free_file_info: NULL, + read_dqblk: v2_read_dquot, + commit_dqblk: v2_commit_dquot, +}; + +static struct quota_format_type v2_quota_format = { + qf_fmt_id: QFMT_VFS_V0, + qf_ops: &v2_format_ops, + qf_owner: THIS_MODULE +}; + +static int __init init_v2_quota_format(void) +{ + return register_quota_format(&v2_quota_format); +} + +static void __exit exit_v2_quota_format(void) +{ + unregister_quota_format(&v2_quota_format); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_v2_quota_format); +module_exit(exit_v2_quota_format); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ramfs/inode.c linux.20pre2-ac1/fs/ramfs/inode.c --- linux.20pre2/fs/ramfs/inode.c 2002-08-13 13:58:15.000000000 +0100 +++ linux.20pre2-ac1/fs/ramfs/inode.c 2002-08-06 15:41:51.000000000 +0100 @@ -29,8 +29,18 @@ #include #include #include +#include +#include #include +#include + +#if PAGE_CACHE_SIZE % 1024 +#error Oh no, PAGE_CACHE_SIZE is not divisible by 1k! I cannot cope. +#endif + +#define IBLOCKS_PER_PAGE (PAGE_CACHE_SIZE / 512) +#define K_PER_PAGE (PAGE_CACHE_SIZE / 1024) /* some random number */ #define RAMFS_MAGIC 0x858458f6 @@ -40,8 +50,176 @@ static struct file_operations ramfs_file_operations; static struct inode_operations ramfs_dir_inode_operations; +/* + * ramfs super-block data in memory + */ +struct ramfs_sb_info { + /* Prevent races accessing the used block + * counts. Conceptually, this could probably be a semaphore, + * but the only thing we do while holding the lock is + * arithmetic, so there's no point */ + spinlock_t ramfs_lock; + + /* It is important that at least the free counts below be + signed. free_XXX may become negative if a limit is changed + downwards (by a remount) below the current usage. */ + + /* maximum number of pages in a file */ + long max_file_pages; + + /* max total number of data pages */ + long max_pages; + /* free_pages = max_pages - total number of pages currently in use */ + long free_pages; + + /* max number of inodes */ + long max_inodes; + /* free_inodes = max_inodes - total number of inodes currently in use */ + long free_inodes; + + /* max number of dentries */ + long max_dentries; + /* free_dentries = max_dentries - total number of dentries in use */ + long free_dentries; +}; + +#define RAMFS_SB(sb) ((struct ramfs_sb_info *)((sb)->u.generic_sbp)) + +/* + * Resource limit helper functions + */ + +static inline void lock_rsb(struct ramfs_sb_info *rsb) +{ + spin_lock(&(rsb->ramfs_lock)); +} + +static inline void unlock_rsb(struct ramfs_sb_info *rsb) +{ + spin_unlock(&(rsb->ramfs_lock)); +} + +/* Decrements the free inode count and returns true, or returns false + * if there are no free inodes */ +static int ramfs_alloc_inode(struct super_block *sb) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + int ret = 1; + + lock_rsb(rsb); + if (!rsb->max_inodes || rsb->free_inodes > 0) + rsb->free_inodes--; + else + ret = 0; + unlock_rsb(rsb); + + return ret; +} + +/* Increments the free inode count */ +static void ramfs_dealloc_inode(struct super_block *sb) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + + lock_rsb(rsb); + rsb->free_inodes++; + unlock_rsb(rsb); +} + +/* Decrements the free dentry count and returns true, or returns false + * if there are no free dentries */ +static int ramfs_alloc_dentry(struct super_block *sb) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + int ret = 1; + + lock_rsb(rsb); + if (!rsb->max_dentries || rsb->free_dentries > 0) + rsb->free_dentries--; + else + ret = 0; + unlock_rsb(rsb); + + return ret; +} + +/* Increments the free dentry count */ +static void ramfs_dealloc_dentry(struct super_block *sb) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + + lock_rsb(rsb); + rsb->free_dentries++; + unlock_rsb(rsb); +} + +/* If the given page can be added to the give inode for ramfs, return + * true and update the filesystem's free page count and the inode's + * i_blocks field. Always returns true if the file is already used by + * ramfs (ie. PageDirty(page) is true) */ +int ramfs_alloc_page(struct inode *inode, struct page *page) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(inode->i_sb); + int ret = 1; + + if (PageDirty(page)) /* It's already been allocated */ + return 1; + + lock_rsb(rsb); + + if ( (rsb->free_pages > 0) && + ( !rsb->max_file_pages || + (inode->i_data.nrpages <= rsb->max_file_pages) ) ) { + inode->i_blocks += IBLOCKS_PER_PAGE; + rsb->free_pages--; + SetPageDirty(page); + } else { + ClearPageUptodate(page); + ret = 0; + } + + unlock_rsb(rsb); + + return ret; +} + +void ramfs_dealloc_page(struct inode *inode, struct page *page) +{ + struct ramfs_sb_info *rsb = RAMFS_SB(inode->i_sb); + + if (! PageDirty(page)) /* The page was never allocated + this can happen if it was only read */ + return; + + lock_rsb(rsb); + + ClearPageDirty(page); + + rsb->free_pages++; + inode->i_blocks -= IBLOCKS_PER_PAGE; + + if (rsb->free_pages > rsb->max_pages) { + printk(KERN_ERR "ramfs: Error in page allocation, free_pages (%ld) > max_pages (%ld)\n", rsb->free_pages, rsb->max_pages); + } + + unlock_rsb(rsb); +} + + + static int ramfs_statfs(struct super_block *sb, struct statfs *buf) { + struct ramfs_sb_info *rsb = RAMFS_SB(sb); + + lock_rsb(rsb); + buf->f_blocks = rsb->max_pages; + buf->f_files = rsb->max_inodes; + + buf->f_bfree = rsb->free_pages; + buf->f_bavail = buf->f_bfree; + buf->f_ffree = rsb->free_inodes; + unlock_rsb(rsb); + buf->f_type = RAMFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; buf->f_namelen = 255; @@ -74,9 +252,26 @@ return 0; } +static int ramfs_writepage(struct page *page) +{ + struct inode *inode = (struct inode *)page->mapping->host; + + if (! ramfs_alloc_page(inode, page)) + return -ENOSPC; + + return 0; +} + static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { - void *addr = kmap(page); + struct inode *inode = (struct inode *)page->mapping->host; + void *addr; + + if (! ramfs_alloc_page(inode, page)) { + return -ENOSPC; + } + + addr = (void *) kmap(page); if (!Page_Uptodate(page)) { memset(addr, 0, PAGE_CACHE_SIZE); flush_dcache_page(page); @@ -97,9 +292,21 @@ return 0; } +static void ramfs_removepage(struct page *page) +{ + struct inode *inode = (struct inode *)page->mapping->host; + + ramfs_dealloc_page(inode, page); +} + struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev) { - struct inode * inode = new_inode(sb); + struct inode * inode; + + if (! ramfs_alloc_inode(sb)) + return NULL; + + inode = new_inode(sb); if (inode) { inode->i_mode = mode; @@ -125,23 +332,35 @@ inode->i_op = &page_symlink_inode_operations; break; } - } + } else + ramfs_dealloc_inode(sb); + return inode; } /* - * File creation. Allocate an inode, and we're done.. + * File creation. Allocate an inode, update free inode and dentry counts + * and we're done.. */ static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) { - struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev); + struct super_block *sb = dir->i_sb; + struct inode * inode; int error = -ENOSPC; + if (! ramfs_alloc_dentry(sb)) + return error; + + inode = ramfs_get_inode(dir->i_sb, mode, dev); + if (inode) { d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ error = 0; + } else { + ramfs_dealloc_dentry(sb); } + return error; } @@ -160,11 +379,15 @@ */ static int ramfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry) { + struct super_block *sb = dir->i_sb; struct inode *inode = old_dentry->d_inode; if (S_ISDIR(inode->i_mode)) return -EPERM; + if (! ramfs_alloc_dentry(sb)) + return -ENOSPC; + inode->i_nlink++; atomic_inc(&inode->i_count); /* New dentry reference */ dget(dentry); /* Extra pinning count for the created dentry */ @@ -211,6 +434,7 @@ */ static int ramfs_unlink(struct inode * dir, struct dentry *dentry) { + struct super_block *sb = dir->i_sb; int retval = -ENOTEMPTY; if (ramfs_empty(dentry)) { @@ -218,6 +442,9 @@ inode->i_nlink--; dput(dentry); /* Undo the count from "create" - this does all the work */ + + ramfs_dealloc_dentry(sb); + retval = 0; } return retval; @@ -233,6 +460,8 @@ */ static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry) { + struct super_block *sb = new_dir->i_sb; + int error = -ENOTEMPTY; if (ramfs_empty(new_dentry)) { @@ -240,6 +469,7 @@ if (inode) { inode->i_nlink--; dput(new_dentry); + ramfs_dealloc_dentry(sb); } error = 0; } @@ -264,11 +494,173 @@ return 0; } +static void ramfs_delete_inode(struct inode *inode) +{ + ramfs_dealloc_inode(inode->i_sb); + + clear_inode(inode); +} + +static void ramfs_put_super(struct super_block *sb) +{ + kfree(sb->u.generic_sbp); +} + +struct ramfs_params { + long pages; + long filepages; + long inodes; + long dentries; +}; + +static int parse_options(char * options, struct ramfs_params *p) +{ + char save = 0, *savep = NULL, *optname, *value; + + p->pages = -1; + p->filepages = -1; + p->inodes = -1; + p->dentries = -1; + + for (optname = strtok(options,","); optname; + optname = strtok(NULL,",")) { + if ((value = strchr(optname,'=')) != NULL) { + save = *value; + savep = value; + *value++ = 0; + } + + if (!strcmp(optname, "maxfilesize") && value) { + p->filepages = simple_strtoul(value, &value, 0) + / K_PER_PAGE; + if (*value) + return -EINVAL; + } else if (!strcmp(optname, "maxsize") && value) { + p->pages = simple_strtoul(value, &value, 0) + / K_PER_PAGE; + if (*value) + return -EINVAL; + } else if (!strcmp(optname, "maxinodes") && value) { + p->inodes = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } else if (!strcmp(optname, "maxdentries") && value) { + p->dentries = simple_strtoul(value, &value, 0); + if (*value) + return -EINVAL; + } + + if (optname != options) + *(optname-1) = ','; + if (value) + *savep = save; + } + + return 0; +} + +static void init_limits(struct ramfs_sb_info *rsb, struct ramfs_params *p) +{ + struct sysinfo si; + + si_meminfo(&si); + + /* By default we set the limits to be: + - Allow this ramfs to take up to half of all available RAM + - No limit on filesize (except no file may be bigger that + the total max size, obviously) + - dentries limited to one per 4k of data space + - No limit to the number of inodes (except that there + are never more inodes than dentries). + */ + rsb->max_pages = (si.totalram / 2); + + if (p->pages >= 0) + rsb->max_pages = p->pages; + + rsb->max_file_pages = 0; + if (p->filepages >= 0) + rsb->max_file_pages = p->filepages; + + rsb->max_dentries = rsb->max_pages * K_PER_PAGE / 4; + if (p->dentries >= 0) + rsb->max_dentries = p->dentries; + + rsb->max_inodes = 0; + if (p->inodes >= 0) + rsb->max_inodes = p->inodes; + + rsb->free_pages = rsb->max_pages; + rsb->free_inodes = rsb->max_inodes; + rsb->free_dentries = rsb->max_dentries; + + return; +} + +/* reset_limits is called during a remount to change the usage limits. + + This will suceed, even if the new limits are lower than current + usage. This is the intended behaviour - new allocations will fail + until usage falls below the new limit */ +static void reset_limits(struct ramfs_sb_info *rsb, struct ramfs_params *p) +{ + lock_rsb(rsb); + + if (p->pages >= 0) { + int used_pages = rsb->max_pages - rsb->free_pages; + + rsb->max_pages = p->pages; + rsb->free_pages = rsb->max_pages - used_pages; + } + + if (p->filepages >= 0) { + rsb->max_file_pages = p->filepages; + } + + + if (p->dentries >= 0) { + int used_dentries = rsb->max_dentries - rsb->free_dentries; + + rsb->max_dentries = p->dentries; + rsb->free_dentries = rsb->max_dentries - used_dentries; + } + + if (p->inodes >= 0) { + int used_inodes = rsb->max_inodes - rsb->free_inodes; + + rsb->max_inodes = p->inodes; + rsb->free_inodes = rsb->max_inodes - used_inodes; + } + + unlock_rsb(rsb); +} + +static int ramfs_remount(struct super_block * sb, int * flags, char * data) +{ + struct ramfs_params params; + struct ramfs_sb_info * rsb = RAMFS_SB(sb); + + if (parse_options((char *)data, ¶ms) != 0) + return -EINVAL; + + reset_limits(rsb, ¶ms); + + printk(KERN_DEBUG "ramfs: remounted with options: %s\n", + data ? (char *)data : "" ); + printk(KERN_DEBUG "ramfs: max_pages=%ld max_file_pages=%ld \ +max_inodes=%ld max_dentries=%ld\n", + rsb->max_pages, rsb->max_file_pages, + rsb->max_inodes, rsb->max_dentries); + + return 0; +} + static struct address_space_operations ramfs_aops = { readpage: ramfs_readpage, - writepage: fail_writepage, + writepage: ramfs_writepage, prepare_write: ramfs_prepare_write, - commit_write: ramfs_commit_write + commit_write: ramfs_commit_write, + removepage: ramfs_removepage, }; static struct file_operations ramfs_file_operations = { @@ -293,17 +685,37 @@ static struct super_operations ramfs_ops = { statfs: ramfs_statfs, put_inode: force_delete, + delete_inode: ramfs_delete_inode, + put_super: ramfs_put_super, + remount_fs: ramfs_remount, }; +/* + * Initialisation + */ + static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent) { struct inode * inode; struct dentry * root; + struct ramfs_sb_info * rsb; + struct ramfs_params params; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = RAMFS_MAGIC; sb->s_op = &ramfs_ops; + + sb->u.generic_sbp = kmalloc(sizeof(struct ramfs_sb_info), GFP_KERNEL); + rsb = RAMFS_SB(sb); + + spin_lock_init(&rsb->ramfs_lock); + + if (parse_options((char *)data, ¶ms) != 0) + return NULL; + + init_limits(rsb, ¶ms); + inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0); if (!inode) return NULL; @@ -314,6 +726,13 @@ return NULL; } sb->s_root = root; + + printk(KERN_DEBUG "ramfs: mounted with options: %s\n", + data ? (char *)data : "" ); + printk(KERN_DEBUG "ramfs: max_pages=%ld max_file_pages=%ld \ +max_inodes=%ld max_dentries=%ld\n", + rsb->max_pages, rsb->max_file_pages, + rsb->max_inodes, rsb->max_dentries); return sb; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/reiserfs/buffer2.c linux.20pre2-ac1/fs/reiserfs/buffer2.c --- linux.20pre2/fs/reiserfs/buffer2.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/reiserfs/buffer2.c 2002-08-13 14:43:51.000000000 +0100 @@ -33,8 +33,7 @@ buffer_journal_dirty(bh) ? ' ' : '!'); } run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } if (repeat_counter > 30000000) { reiserfs_warning("vs-3051: done waiting, ignore vs-3050 messages for (%b)\n", bh) ; @@ -52,11 +51,11 @@ struct buffer_head * reiserfs_bread (struct super_block *super, int n_block, int n_size) { struct buffer_head *result; - PROC_EXP( unsigned int ctx_switches = kstat.context_swtch ); + PROC_EXP( unsigned int ctx_switches = nr_context_switches(); ); result = bread (super -> s_dev, n_block, n_size); PROC_INFO_INC( super, breads ); - PROC_EXP( if( kstat.context_swtch != ctx_switches ) + PROC_EXP( if( nr_context_switches() != ctx_switches ) PROC_INFO_INC( super, bread_miss ) ); return result; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/reiserfs/journal.c linux.20pre2-ac1/fs/reiserfs/journal.c --- linux.20pre2/fs/reiserfs/journal.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/fs/reiserfs/journal.c 2002-08-13 14:44:32.000000000 +0100 @@ -151,8 +151,7 @@ } bn = allocate_bitmap_node(p_s_sb) ; if (!bn) { - current->policy |= SCHED_YIELD ; - schedule() ; + yield(); goto repeat ; } return bn ; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/super.c linux.20pre2-ac1/fs/super.c --- linux.20pre2/fs/super.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/super.c 2002-08-06 15:41:51.000000000 +0100 @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -279,6 +280,8 @@ sema_init(&s->s_dquot.dqio_sem, 1); sema_init(&s->s_dquot.dqoff_sem, 1); s->s_maxbytes = MAX_NON_LFS; + s->dq_op = sb_dquot_ops; + s->s_qcop = sb_quotactl_ops; } return s; } @@ -659,8 +662,7 @@ /* What device it is? */ if (!dev_name || !*dev_name) return ERR_PTR(-EINVAL); - if (path_init(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd)) - error = path_walk(dev_name, &nd); + error = path_lookup(dev_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd); if (error) return ERR_PTR(error); inode = nd.dentry->d_inode; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/fs/ufs/truncate.c linux.20pre2-ac1/fs/ufs/truncate.c --- linux.20pre2/fs/ufs/truncate.c 2002-08-13 13:58:14.000000000 +0100 +++ linux.20pre2-ac1/fs/ufs/truncate.c 2002-08-06 15:41:51.000000000 +0100 @@ -448,10 +448,7 @@ if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) ufs_sync_inode (inode); run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - schedule (); - - + yield(); } offset = inode->i_size & uspi->s_fshift; if (offset) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-alpha/bitops.h linux.20pre2-ac1/include/asm-alpha/bitops.h --- linux.20pre2/include/asm-alpha/bitops.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-alpha/bitops.h 2002-08-06 15:41:52.000000000 +0100 @@ -3,6 +3,7 @@ #include #include +#include /* * Copyright 1994, Linus Torvalds. @@ -74,6 +75,17 @@ * WARNING: non atomic version. */ static __inline__ void +__clear_bit(unsigned long nr, volatile void * addr) +{ + int *m = ((int *) addr) + (nr >> 5); + + *m &= ~(1 << (nr & 31)); +} + +/* + * WARNING: non atomic version. + */ +static __inline__ void __change_bit(unsigned long nr, volatile void * addr) { int *m = ((int *) addr) + (nr >> 5); @@ -264,6 +276,28 @@ #endif } +/* + * __ffs = Find First set bit in word. Undefined if no set bit exists. + */ +static inline unsigned long __ffs(unsigned long word) +{ +#if defined(__alpha_cix__) && defined(__alpha_fix__) + /* Whee. EV67 can calculate it directly. */ + unsigned long result; + __asm__("cttz %1,%0" : "=r"(result) : "r"(word)); + return result; +#else + unsigned long bits, qofs, bofs; + + __asm__("cmpbge $31,%1,%0" : "=r"(bits) : "r"(word)); + qofs = ffz_b(bits); + bits = __kernel_extbl(word, qofs); + bofs = ffz_b(~bits); + + return qofs*8 + bofs; +#endif +} + #ifdef __KERNEL__ /* @@ -365,13 +399,77 @@ } /* - * The optimizer actually does good code for this case.. + * Find next one bit in a bitmap reasonably efficiently. + */ +static inline unsigned long +find_next_bit(void * addr, unsigned long size, unsigned long offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset >> 6); + unsigned long result = offset & ~63UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 63UL; + if (offset) { + tmp = *(p++); + tmp &= ~0UL << offset; + if (size < 64) + goto found_first; + if (tmp) + goto found_middle; + size -= 64; + result += 64; + } + while (size & ~63UL) { + if ((tmp = *(p++))) + goto found_middle; + result += 64; + size -= 64; + } + if (!size) + return result; + tmp = *p; +found_first: + tmp &= ~0UL >> (64 - size); + if (!tmp) + return result + size; +found_middle: + return result + __ffs(tmp); +} + +/* + * The optimizer actually does good code for this case. */ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) +#define find_first_bit(addr, size) \ + find_next_bit((addr), (size), 0) #ifdef __KERNEL__ +/* + * Every architecture must define this function. It's the fastest + * way of searching a 140-bit bitmap where the first 100 bits are + * unlikely to be set. It's guaranteed that at least one of the 140 + * bits is set. + */ +static inline unsigned long +sched_find_first_bit(unsigned long b[3]) +{ + unsigned long b0 = b[0], b1 = b[1], b2 = b[2]; + unsigned long ofs; + + ofs = (b1 ? 64 : 128); + b1 = (b1 ? b1 : b2); + ofs = (b0 ? 0 : ofs); + b0 = (b0 ? b0 : b1); + + return __ffs(b0) + ofs; +} + + #define ext2_set_bit __test_and_set_bit #define ext2_clear_bit __test_and_clear_bit #define ext2_test_bit test_bit diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-alpha/ide.h linux.20pre2-ac1/include/asm-alpha/ide.h --- linux.20pre2/include/asm-alpha/ide.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-alpha/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -19,8 +19,6 @@ #define MAX_HWIFS 4 #endif -#define ide__sti() __sti() - static __inline__ int ide_default_irq(ide_ioreg_t base) { switch (base) { @@ -82,29 +80,6 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ - } b; -} control_t; - #define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) #define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) #define ide_check_region(from,extent) check_region((from), (extent)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-alpha/ioctls.h linux.20pre2-ac1/include/asm-alpha/ioctls.h --- linux.20pre2/include/asm-alpha/ioctls.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-alpha/ioctls.h 2002-08-06 15:41:52.000000000 +0100 @@ -9,6 +9,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) #define TIOCGETP _IOR('t', 8, struct sgttyb) #define TIOCSETP _IOW('t', 9, struct sgttyb) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-alpha/pgtable.h linux.20pre2-ac1/include/asm-alpha/pgtable.h --- linux.20pre2/include/asm-alpha/pgtable.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-alpha/pgtable.h 2002-08-06 15:41:52.000000000 +0100 @@ -213,8 +213,8 @@ pte_t pte; \ unsigned long pfn; \ \ - pfn = ((unsigned long)((page)-page_zone(page)->zone_mem_map)) << 32; \ - pfn += page_zone(page)->zone_start_paddr << (32-PAGE_SHIFT); \ + pfn = ((unsigned long)((page)-(page)->zone->zone_mem_map)) << 32; \ + pfn += (page)->zone->zone_start_paddr << (32-PAGE_SHIFT); \ pte_val(pte) = pfn | pgprot_val(pgprot); \ \ pte; \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-alpha/rmap.h linux.20pre2-ac1/include/asm-alpha/rmap.h --- linux.20pre2/include/asm-alpha/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-alpha/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _ALPHA_RMAP_H +#define _ALPHA_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-alpha/semaphore.h linux.20pre2-ac1/include/asm-alpha/semaphore.h --- linux.20pre2/include/asm-alpha/semaphore.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-alpha/semaphore.h 2002-08-13 17:30:32.000000000 +0100 @@ -80,6 +80,11 @@ extern void up(struct semaphore *); extern void __up_wakeup(struct semaphore *); +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + /* * Hidden out of line code is fun, but extremely messy. Rely on newer * compilers to do a respectable job with this. The contention cases diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-alpha/smp.h linux.20pre2-ac1/include/asm-alpha/smp.h --- linux.20pre2/include/asm-alpha/smp.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-alpha/smp.h 2002-08-06 15:41:52.000000000 +0100 @@ -55,7 +55,7 @@ #define cpu_logical_map(cpu) __cpu_logical_map[cpu] #define hard_smp_processor_id() __hard_smp_processor_id() -#define smp_processor_id() (current->processor) +#define smp_processor_id() (current->cpu) extern unsigned long cpu_present_mask; #define cpu_online_map cpu_present_mask diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-alpha/system.h linux.20pre2-ac1/include/asm-alpha/system.h --- linux.20pre2/include/asm-alpha/system.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-alpha/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -309,9 +309,11 @@ #define __sti() do { barrier(); setipl(IPL_MIN); } while(0) #define __save_flags(flags) ((flags) = rdps()) #define __save_and_cli(flags) do { (flags) = swpipl(IPL_MAX); barrier(); } while(0) +#define __save_and_sti(flags) do { (flags) = swpipl(IPL_MIN); barrier(); } while(0) #define __restore_flags(flags) do { barrier(); setipl(flags); barrier(); } while(0) #define local_irq_save(flags) __save_and_cli(flags) +#define local_irq_set(flags) __save_and_sti(flags) #define local_irq_restore(flags) __restore_flags(flags) #define local_irq_disable() __cli() #define local_irq_enable() __sti() @@ -320,8 +322,6 @@ extern int global_irq_holder; -#define save_and_cli(flags) (save_flags(flags), cli()) - extern void __global_cli(void); extern void __global_sti(void); extern unsigned long __global_save_flags(void); @@ -331,6 +331,8 @@ #define sti() __global_sti() #define save_flags(flags) ((flags) = __global_save_flags()) #define restore_flags(flags) __global_restore_flags(flags) +#define save_and_cli(flags) (save_flags(flags), cli()) +#define save_and_sti(flags) (save_flags(flags), sti()) #else /* CONFIG_SMP */ @@ -338,6 +340,7 @@ #define sti() __sti() #define save_flags(flags) __save_flags(flags) #define save_and_cli(flags) __save_and_cli(flags) +#define save_and_sti(flags) __save_and_sti(flags) #define restore_flags(flags) __restore_flags(flags) #endif /* CONFIG_SMP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/arch-cl7500/system.h linux.20pre2-ac1/include/asm-arm/arch-cl7500/system.h --- linux.20pre2/include/asm-arm/arch-cl7500/system.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/arch-cl7500/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -18,6 +18,6 @@ do { \ iomd_writeb(0, IOMD_ROMCR0); \ cpu_reset(0); \ - } while (0); + } while (0) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/arch-sa1100/keyboard.h linux.20pre2-ac1/include/asm-arm/arch-sa1100/keyboard.h --- linux.20pre2/include/asm-arm/arch-sa1100/keyboard.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/arch-sa1100/keyboard.h 2002-08-06 15:41:52.000000000 +0100 @@ -10,8 +10,8 @@ #include #include -#define kbd_disable_irq() do { } while(0); -#define kbd_enable_irq() do { } while(0); +#define kbd_disable_irq() do { } while(0) +#define kbd_enable_irq() do { } while(0) extern int sa1111_kbd_init_hw(void); extern void gc_kbd_init_hw(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/ide.h linux.20pre2-ac1/include/asm-arm/ide.h --- linux.20pre2/include/asm-arm/ide.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -17,33 +17,8 @@ #define MAX_HWIFS 4 #endif -#define ide__sti() __sti() - #include -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ - } b; -} control_t; - #define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) #define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) #define ide_check_region(from,extent) check_region((from), (extent)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/page.h linux.20pre2-ac1/include/asm-arm/page.h --- linux.20pre2/include/asm-arm/page.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/page.h 2002-08-06 15:41:52.000000000 +0100 @@ -106,6 +106,9 @@ #define VALID_PAGE(page) ((page - mem_map) < max_mapnr) #endif +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/proc-armo/system.h linux.20pre2-ac1/include/asm-arm/proc-armo/system.h --- linux.20pre2/include/asm-arm/proc-armo/system.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/proc-armo/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -127,4 +127,6 @@ : "memory"); \ } while (0) +#define __save_and_sti(x) ({__save_flags(x);__sti();}) + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/proc-armv/rmap.h linux.20pre2-ac1/include/asm-arm/proc-armv/rmap.h --- linux.20pre2/include/asm-arm/proc-armv/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/proc-armv/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,72 @@ +#ifndef _ARMV_RMAP_H +#define _ARMV_RMAP_H +/* + * linux/include/asm-arm/proc-armv/rmap.h + * + * Architecture dependant parts of the reverse mapping code, + * + * We use the struct page of the page table page to find a pointer + * to an array of two 'struct arm_rmap_info's, one for each of the + * two page tables in each page. + * + * - rmi->mm points to the process' mm_struct + * - rmi->index has the high bits of the address + * - the lower bits of the address are calculated from the + * offset of the page table entry within the page table page + */ +#include + +struct arm_rmap_info { + struct mm_struct *mm; + unsigned long index; +}; + +static inline void pgtable_add_rmap(pte_t * ptep, struct mm_struct * mm, unsigned long address) +{ + struct page * page = virt_to_page(ptep); + struct arm_rmap_info *rmi = (void *)page->mapping; + + if (((unsigned long)ptep)&2048) + rmi++; + + rmi->mm = mm; + rmi->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1); +} + +static inline void pgtable_remove_rmap(pte_t * ptep) +{ + struct page * page = virt_to_page(ptep); + struct arm_rmap_info *rmi = (void *)page->mapping; + + if (((unsigned long)ptep)&2048) + rmi++; + + rmi->mm = NULL; + rmi->index = 0; +} + +static inline struct mm_struct * ptep_to_mm(pte_t * ptep) +{ + struct page * page = virt_to_page(ptep); + struct arm_rmap_info *rmi = (void *)page->mapping; + + if (((unsigned long)ptep)&2048) + rmi++; + + return rmi->mm; +} + +static inline unsigned long ptep_to_address(pte_t * ptep) +{ + struct page * page = virt_to_page(ptep); + struct arm_rmap_info *rmi = (void *)page->mapping; + unsigned long low_bits; + + if (((unsigned long)ptep)&2048) + rmi++; + + low_bits = ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE; + return rmi->index + low_bits; +} + +#endif /* _ARMV_RMAP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/proc-armv/system.h linux.20pre2-ac1/include/asm-arm/proc-armv/system.h --- linux.20pre2/include/asm-arm/proc-armv/system.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/proc-armv/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -141,6 +141,8 @@ : "r" (x) \ : "memory") +#define __save_and_sti(x) ({__save_flags(x);__sti();}) + #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110) /* * On the StrongARM, "swp" is terminally broken since it bypasses the diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/rmap.h linux.20pre2-ac1/include/asm-arm/rmap.h --- linux.20pre2/include/asm-arm/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,6 @@ +#ifndef _ARM_RMAP_H +#define _ARM_RMAP_H + +#include + +#endif /* _ARM_RMAP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/semaphore.h linux.20pre2-ac1/include/asm-arm/semaphore.h --- linux.20pre2/include/asm-arm/semaphore.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -125,4 +125,9 @@ __up_op(sem, __up_wakeup); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-arm/system.h linux.20pre2-ac1/include/asm-arm/system.h --- linux.20pre2/include/asm-arm/system.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-arm/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -58,6 +58,7 @@ /* For spinlocks etc */ #define local_irq_save(x) __save_flags_cli(x) +#define local_irq_set(x) __save_and_sti(x) #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti() @@ -82,6 +83,8 @@ #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) #define save_flags_cli(x) __save_flags_cli(x) +#define save_and_cli(x) __save_flags_cli(x) +#define save_and_sti(x) __save_flags_sti(x) #endif /* CONFIG_SMP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-cris/ide.h linux.20pre2-ac1/include/asm-cris/ide.h --- linux.20pre2/include/asm-cris/ide.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-cris/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -22,8 +22,6 @@ #define MAX_HWIFS 4 -#define ide__sti() __sti() - static __inline__ int ide_default_irq(ide_ioreg_t base) { /* all IDE busses share the same IRQ, number 4. @@ -88,29 +86,6 @@ } } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ - } b; -} control_t; - /* some configuration options we don't need */ #undef SUPPORT_VLB_SYNC diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-cris/ioctls.h linux.20pre2-ac1/include/asm-cris/ioctls.h --- linux.20pre2/include/asm-cris/ioctls.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-cris/ioctls.h 2002-08-06 15:41:52.000000000 +0100 @@ -69,6 +69,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 #define TIOCSERSETRS485 0x5460 /* enable rs-485 */ #define TIOCSERWRRS485 0x5461 /* write rs-485 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-cris/rmap.h linux.20pre2-ac1/include/asm-cris/rmap.h --- linux.20pre2/include/asm-cris/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-cris/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _CRIS_RMAP_H +#define _CRIS_RMAP_H + +/* nothing to see, move along :) */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-cris/semaphore.h linux.20pre2-ac1/include/asm-cris/semaphore.h --- linux.20pre2/include/asm-cris/semaphore.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-cris/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -158,4 +158,9 @@ } } +static inline int sem_getcount(struct semaphore *sem) +{ + return sem->count; +} + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-cris/system.h linux.20pre2-ac1/include/asm-cris/system.h --- linux.20pre2/include/asm-cris/system.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-cris/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -69,6 +69,7 @@ /* For spinlocks etc */ #define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); +#define local_irq_set(x) __asm__ __volatile__ ("move $ccr,%0\n\tei" : "=rm" (x) : : "memory"); #define local_irq_restore(x) restore_flags(x) #define local_irq_disable() cli() @@ -80,7 +81,8 @@ #define sti() __sti() #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) -#define save_and_cli(x) do { __save_flags(x); cli(); } while(0) +#define save_and_cli(x) do { save_flags(x); cli(); } while(0) +#define save_and_sti(x) do { save_flags(x); sti(); } while(0) static inline unsigned long __xchg(unsigned long x, void * ptr, int size) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-generic/bitops.h linux.20pre2-ac1/include/asm-generic/bitops.h --- linux.20pre2/include/asm-generic/bitops.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/asm-generic/bitops.h 2002-08-06 15:41:52.000000000 +0100 @@ -51,6 +51,12 @@ return ((mask & *addr) != 0); } +/* + * fls: find last bit set. + */ + +#define fls(x) generic_fls(x) + #ifdef __KERNEL__ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-generic/rmap.h linux.20pre2-ac1/include/asm-generic/rmap.h --- linux.20pre2/include/asm-generic/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-generic/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,57 @@ +#ifndef _GENERIC_RMAP_H +#define _GENERIC_RMAP_H +/* + * linux/include/asm-generic/rmap.h + * + * Architecture dependant parts of the reverse mapping code, + * this version should work for most architectures with a + * 'normal' page table layout. + * + * We use the struct page of the page table page to find out + * the process and full address of a page table entry: + * - page->mapping points to the process' mm_struct + * - page->index has the high bits of the address + * - the lower bits of the address are calculated from the + * offset of the page table entry within the page table page + */ +#include + +static inline void pgtable_add_rmap(pte_t * ptep, struct mm_struct * mm, unsigned long address) +{ + struct page * page = virt_to_page(ptep); +#ifdef BROKEN_PPC_PTE_ALLOC_ONE + /* OK, so PPC calls pte_alloc() before mem_map[] is setup ... ;( */ + extern int mem_init_done; + + if (!mem_init_done) + return; +#endif + page->mapping = (void *)mm; + page->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1); +} + +static inline void pgtable_remove_rmap(pte_t * ptep) +{ + struct page * page = virt_to_page(ptep); + + page->mapping = NULL; + page->index = 0; +} + +static inline struct mm_struct * ptep_to_mm(pte_t * ptep) +{ + struct page * page = virt_to_page(ptep); + + return (struct mm_struct *) page->mapping; +} + +static inline unsigned long ptep_to_address(pte_t * ptep) +{ + struct page * page = virt_to_page(ptep); + unsigned long low_bits; + + low_bits = ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE; + return page->index + low_bits; +} + +#endif /* _GENERIC_RMAP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-generic/xor.h linux.20pre2-ac1/include/asm-generic/xor.h --- linux.20pre2/include/asm-generic/xor.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/asm-generic/xor.h 2002-08-06 15:41:52.000000000 +0100 @@ -13,6 +13,8 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + static void xor_8regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) { @@ -299,6 +301,364 @@ } while (--lines > 0); } +static void +xor_8regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + long lines = bytes / (sizeof (long)) / 8; + prefetchw(p1); + prefetch(p2); + + do { + prefetchw(p1+8); + prefetch(p2+8); + p1[0] ^= p2[0]; + p1[1] ^= p2[1]; + p1[2] ^= p2[2]; + p1[3] ^= p2[3]; + p1[4] ^= p2[4]; + p1[5] ^= p2[5]; + p1[6] ^= p2[6]; + p1[7] ^= p2[7]; + p1 += 8; + p2 += 8; + } while (--lines > 0); +} + +static void +xor_8regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + long lines = bytes / (sizeof (long)) / 8; + prefetchw(p1); + prefetch(p2); + prefetch(p3); + + do { + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + p1[0] ^= p2[0] ^ p3[0]; + p1[1] ^= p2[1] ^ p3[1]; + p1[2] ^= p2[2] ^ p3[2]; + p1[3] ^= p2[3] ^ p3[3]; + p1[4] ^= p2[4] ^ p3[4]; + p1[5] ^= p2[5] ^ p3[5]; + p1[6] ^= p2[6] ^ p3[6]; + p1[7] ^= p2[7] ^ p3[7]; + p1 += 8; + p2 += 8; + p3 += 8; + } while (--lines > 0); +} + +static void +xor_8regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + long lines = bytes / (sizeof (long)) / 8; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + prefetch(p4); + + do { + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + prefetch(p4+8); + + p1[0] ^= p2[0] ^ p3[0] ^ p4[0]; + p1[1] ^= p2[1] ^ p3[1] ^ p4[1]; + p1[2] ^= p2[2] ^ p3[2] ^ p4[2]; + p1[3] ^= p2[3] ^ p3[3] ^ p4[3]; + p1[4] ^= p2[4] ^ p3[4] ^ p4[4]; + p1[5] ^= p2[5] ^ p3[5] ^ p4[5]; + p1[6] ^= p2[6] ^ p3[6] ^ p4[6]; + p1[7] ^= p2[7] ^ p3[7] ^ p4[7]; + p1 += 8; + p2 += 8; + p3 += 8; + p4 += 8; + } while (--lines > 0); +} + +static void +xor_8regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + long lines = bytes / (sizeof (long)) / 8; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + prefetch(p4); + prefetch(p5); + + do { + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + prefetch(p4+8); + prefetch(p5+8); + + p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0]; + p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1]; + p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2]; + p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3]; + p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4]; + p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5]; + p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6]; + p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7]; + p1 += 8; + p2 += 8; + p3 += 8; + p4 += 8; + p5 += 8; + } while (--lines > 0); +} + +static void +xor_32regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + long lines = bytes / (sizeof (long)) / 8; + + prefetchw(p1); + prefetch(p2); + + do { + register long d0, d1, d2, d3, d4, d5, d6, d7; + + prefetchw(p1+8); + prefetch(p2+8); + + d0 = p1[0]; /* Pull the stuff into registers */ + d1 = p1[1]; /* ... in bursts, if possible. */ + d2 = p1[2]; + d3 = p1[3]; + d4 = p1[4]; + d5 = p1[5]; + d6 = p1[6]; + d7 = p1[7]; + d0 ^= p2[0]; + d1 ^= p2[1]; + d2 ^= p2[2]; + d3 ^= p2[3]; + d4 ^= p2[4]; + d5 ^= p2[5]; + d6 ^= p2[6]; + d7 ^= p2[7]; + p1[0] = d0; /* Store the result (in burts) */ + p1[1] = d1; + p1[2] = d2; + p1[3] = d3; + p1[4] = d4; + p1[5] = d5; + p1[6] = d6; + p1[7] = d7; + p1 += 8; + p2 += 8; + } while (--lines > 0); +} + +static void +xor_32regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + long lines = bytes / (sizeof (long)) / 8; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + + do { + register long d0, d1, d2, d3, d4, d5, d6, d7; + + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + + d0 = p1[0]; /* Pull the stuff into registers */ + d1 = p1[1]; /* ... in bursts, if possible. */ + d2 = p1[2]; + d3 = p1[3]; + d4 = p1[4]; + d5 = p1[5]; + d6 = p1[6]; + d7 = p1[7]; + d0 ^= p2[0]; + d1 ^= p2[1]; + d2 ^= p2[2]; + d3 ^= p2[3]; + d4 ^= p2[4]; + d5 ^= p2[5]; + d6 ^= p2[6]; + d7 ^= p2[7]; + d0 ^= p3[0]; + d1 ^= p3[1]; + d2 ^= p3[2]; + d3 ^= p3[3]; + d4 ^= p3[4]; + d5 ^= p3[5]; + d6 ^= p3[6]; + d7 ^= p3[7]; + p1[0] = d0; /* Store the result (in burts) */ + p1[1] = d1; + p1[2] = d2; + p1[3] = d3; + p1[4] = d4; + p1[5] = d5; + p1[6] = d6; + p1[7] = d7; + p1 += 8; + p2 += 8; + p3 += 8; + } while (--lines > 0); +} + +static void +xor_32regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + long lines = bytes / (sizeof (long)) / 8; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + prefetch(p4); + + do { + register long d0, d1, d2, d3, d4, d5, d6, d7; + + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + prefetch(p4+8); + + d0 = p1[0]; /* Pull the stuff into registers */ + d1 = p1[1]; /* ... in bursts, if possible. */ + d2 = p1[2]; + d3 = p1[3]; + d4 = p1[4]; + d5 = p1[5]; + d6 = p1[6]; + d7 = p1[7]; + d0 ^= p2[0]; + d1 ^= p2[1]; + d2 ^= p2[2]; + d3 ^= p2[3]; + d4 ^= p2[4]; + d5 ^= p2[5]; + d6 ^= p2[6]; + d7 ^= p2[7]; + d0 ^= p3[0]; + d1 ^= p3[1]; + d2 ^= p3[2]; + d3 ^= p3[3]; + d4 ^= p3[4]; + d5 ^= p3[5]; + d6 ^= p3[6]; + d7 ^= p3[7]; + d0 ^= p4[0]; + d1 ^= p4[1]; + d2 ^= p4[2]; + d3 ^= p4[3]; + d4 ^= p4[4]; + d5 ^= p4[5]; + d6 ^= p4[6]; + d7 ^= p4[7]; + p1[0] = d0; /* Store the result (in burts) */ + p1[1] = d1; + p1[2] = d2; + p1[3] = d3; + p1[4] = d4; + p1[5] = d5; + p1[6] = d6; + p1[7] = d7; + p1 += 8; + p2 += 8; + p3 += 8; + p4 += 8; + } while (--lines > 0); +} + +static void +xor_32regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + long lines = bytes / (sizeof (long)) / 8; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + prefetch(p4); + prefetch(p5); + + do { + register long d0, d1, d2, d3, d4, d5, d6, d7; + + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + prefetch(p4+8); + prefetch(p5+8); + + d0 = p1[0]; /* Pull the stuff into registers */ + d1 = p1[1]; /* ... in bursts, if possible. */ + d2 = p1[2]; + d3 = p1[3]; + d4 = p1[4]; + d5 = p1[5]; + d6 = p1[6]; + d7 = p1[7]; + d0 ^= p2[0]; + d1 ^= p2[1]; + d2 ^= p2[2]; + d3 ^= p2[3]; + d4 ^= p2[4]; + d5 ^= p2[5]; + d6 ^= p2[6]; + d7 ^= p2[7]; + d0 ^= p3[0]; + d1 ^= p3[1]; + d2 ^= p3[2]; + d3 ^= p3[3]; + d4 ^= p3[4]; + d5 ^= p3[5]; + d6 ^= p3[6]; + d7 ^= p3[7]; + d0 ^= p4[0]; + d1 ^= p4[1]; + d2 ^= p4[2]; + d3 ^= p4[3]; + d4 ^= p4[4]; + d5 ^= p4[5]; + d6 ^= p4[6]; + d7 ^= p4[7]; + d0 ^= p5[0]; + d1 ^= p5[1]; + d2 ^= p5[2]; + d3 ^= p5[3]; + d4 ^= p5[4]; + d5 ^= p5[5]; + d6 ^= p5[6]; + d7 ^= p5[7]; + p1[0] = d0; /* Store the result (in burts) */ + p1[1] = d1; + p1[2] = d2; + p1[3] = d3; + p1[4] = d4; + p1[5] = d5; + p1[6] = d6; + p1[7] = d7; + p1 += 8; + p2 += 8; + p3 += 8; + p4 += 8; + p5 += 8; + } while (--lines > 0); +} + static struct xor_block_template xor_block_8regs = { name: "8regs", do_2: xor_8regs_2, @@ -315,8 +675,26 @@ do_5: xor_32regs_5, }; +static struct xor_block_template xor_block_8regs_p = { + name: "8regs_prefetch", + do_2: xor_8regs_p_2, + do_3: xor_8regs_p_3, + do_4: xor_8regs_p_4, + do_5: xor_8regs_p_5, +}; + +static struct xor_block_template xor_block_32regs_p = { + name: "32regs_prefetch", + do_2: xor_32regs_p_2, + do_3: xor_32regs_p_3, + do_4: xor_32regs_p_4, + do_5: xor_32regs_p_5, +}; + #define XOR_TRY_TEMPLATES \ do { \ xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_8regs_p); \ xor_speed(&xor_block_32regs); \ + xor_speed(&xor_block_32regs_p); \ } while (0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/apicdef.h linux.20pre2-ac1/include/asm-i386/apicdef.h --- linux.20pre2/include/asm-i386/apicdef.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/apicdef.h 2002-08-06 18:24:33.000000000 +0100 @@ -11,8 +11,10 @@ #define APIC_DEFAULT_PHYS_BASE 0xfee00000 #define APIC_ID 0x20 -#define APIC_ID_MASK (0x0F<<24) -#define GET_APIC_ID(x) (((x)>>24)&0x0F) +#define APIC_ID_MASK (0xFF<<24) +#define GET_APIC_ID(x) (((x)>>24)&0xFF) +#define XAPIC_VER_LOW 0x14 /* Version num range */ +#define XAPIC_VER_HIGH 0x1F #define APIC_LVR 0x30 #define APIC_LVR_MASK 0xFF00FF #define GET_APIC_VERSION(x) ((x)&0xFF) @@ -32,6 +34,8 @@ #define SET_APIC_LOGICAL_ID(x) (((x)<<24)) #define APIC_ALL_CPUS 0xFF #define APIC_DFR 0xE0 +#define APIC_DFR_CLUSTER 0x0FFFFFFFul /* Clustered */ +#define APIC_DFR_FLAT 0xFFFFFFFFul /* Flat mode */ #define APIC_SPIV 0xF0 #define APIC_SPIV_FOCUS_DISABLED (1<<9) #define APIC_SPIV_APIC_ENABLED (1<<8) @@ -57,6 +61,7 @@ #define APIC_INT_LEVELTRIG 0x08000 #define APIC_INT_ASSERT 0x04000 #define APIC_ICR_BUSY 0x01000 +#define APIC_DEST_PHYSICAL 0x00000 #define APIC_DEST_LOGICAL 0x00800 #define APIC_DM_FIXED 0x00000 #define APIC_DM_LOWEST 0x00100 @@ -107,7 +112,14 @@ #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) -#define MAX_IO_APICS 8 +#ifdef CONFIG_MULTIQUAD +#define MAX_IO_APICS 32 +#else +#define MAX_IO_APICS 8 +#endif + +#define APIC_BROADCAST_ID_XAPIC 0xFF +#define APIC_BROADCAST_ID_APIC 0x0F /* * the local APIC register structure, memory mapped. Not terribly well diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/apic.h linux.20pre2-ac1/include/asm-i386/apic.h --- linux.20pre2/include/asm-i386/apic.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/apic.h 2002-08-14 14:41:29.000000000 +0100 @@ -85,7 +85,6 @@ extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback); extern void apic_pm_unregister(struct pm_dev*); -extern unsigned int apic_timer_irqs [NR_CPUS]; extern int check_nmi_watchdog (void); extern unsigned int nmi_watchdog; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/bitops.h linux.20pre2-ac1/include/asm-i386/bitops.h --- linux.20pre2/include/asm-i386/bitops.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/bitops.h 2002-08-06 17:16:30.000000000 +0100 @@ -6,6 +6,7 @@ */ #include +#include /* * These have to be done with inline assembly: that way the bit-setting @@ -75,6 +76,14 @@ :"=m" (ADDR) :"Ir" (nr)); } + +static __inline__ void __clear_bit(int nr, volatile void * addr) +{ + __asm__ __volatile__( + "btrl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} #define smp_mb__before_clear_bit() barrier() #define smp_mb__after_clear_bit() barrier() @@ -284,6 +293,34 @@ } /** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first set bit, not the number of the byte + * containing a bit. + */ +static __inline__ int find_first_bit(void * addr, unsigned size) +{ + int d0, d1; + int res; + + /* This looks at memory. Mark it volatile to tell gcc not to move it around */ + __asm__ __volatile__( + "xorl %%eax,%%eax\n\t" + "repe; scasl\n\t" + "jz 1f\n\t" + "leal -4(%%edi),%%edi\n\t" + "bsfl (%%edi),%%eax\n" + "1:\tsubl %%ebx,%%edi\n\t" + "shll $3,%%edi\n\t" + "addl %%edi,%%eax" + :"=a" (res), "=&c" (d0), "=&D" (d1) + :"1" ((size + 31) >> 5), "2" (addr), "b" (addr)); + return res; +} + +/** * find_next_zero_bit - find the first zero bit in a memory region * @addr: The address to base the search on * @offset: The bitnumber to start searching at @@ -296,7 +333,7 @@ if (bit) { /* - * Look for zero in first byte + * Look for zero in the first 32 bits. */ __asm__("bsfl %1,%0\n\t" "jne 1f\n\t" @@ -317,6 +354,39 @@ } /** + * find_next_bit - find the first set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static __inline__ int find_next_bit (void * addr, int size, int offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* + * Look for nonzero in the first 32 bits: + */ + __asm__("bsfl %1,%0\n\t" + "jne 1f\n\t" + "movl $32, %0\n" + "1:" + : "=r" (set) + : "r" (*p >> bit)); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* + * No set bit yet, search remaining full words for a bit + */ + res = find_first_bit (p, size - 32 * (p - (unsigned long *) addr)); + return (offset + set + res); +} + +/** * ffz - find first zero in word. * @word: The word to search * @@ -330,8 +400,47 @@ return word; } +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static __inline__ unsigned long __ffs(unsigned long word) +{ + __asm__("bsfl %1,%0" + :"=r" (word) + :"rm" (word)); + return word; +} + +/* + * fls: find last bit set. + */ + +#define fls(x) generic_fls(x) + #ifdef __KERNEL__ +/* + * Every architecture must define this function. It's the fastest + * way of searching a 140-bit bitmap where the first 100 bits are + * unlikely to be set. It's guaranteed that at least one of the 140 + * bits is cleared. + */ +static inline int _sched_find_first_bit(unsigned long *b) +{ + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 32; + if (unlikely(b[2])) + return __ffs(b[2]) + 64; + if (b[3]) + return __ffs(b[3]) + 96; + return __ffs(b[4]) + 128; +} + /** * ffs - find first bit set * @x: the word to search diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/desc.h linux.20pre2-ac1/include/asm-i386/desc.h --- linux.20pre2/include/asm-i386/desc.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/desc.h 2002-08-06 15:41:52.000000000 +0100 @@ -18,23 +18,31 @@ * 9 - APM BIOS support * 10 - APM BIOS support * 11 - APM BIOS support + * 12 - PNPBIOS support + * 13 - PNPBIOS support + * 14 - PNPBIOS support + * 15 - PNPBIOS support + * 16 - PNPBIOS support + * 17 - not used + * 18 - not used + * 19 - not used * * The TSS+LDT descriptors are spread out a bit so that every CPU * has an exclusive cacheline for the per-CPU TSS and LDT: * - * 12 - CPU#0 TSS <-- new cacheline - * 13 - CPU#0 LDT - * 14 - not used - * 15 - not used - * 16 - CPU#1 TSS <-- new cacheline - * 17 - CPU#1 LDT - * 18 - not used - * 19 - not used + * 20 - CPU#0 TSS <-- new cacheline + * 21 - CPU#0 LDT + * 22 - not used + * 23 - not used + * 24 - CPU#1 TSS <-- new cacheline + * 25 - CPU#1 LDT + * 26 - not used + * 27 - not used * ... NR_CPUS per-CPU TSS+LDT's if on SMP * * Entry into gdt where to find first TSS. */ -#define __FIRST_TSS_ENTRY 12 +#define __FIRST_TSS_ENTRY 20 #define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1) #define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/hardirq.h linux.20pre2-ac1/include/asm-i386/hardirq.h --- linux.20pre2/include/asm-i386/hardirq.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/hardirq.h 2002-08-14 14:41:30.000000000 +0100 @@ -12,7 +12,11 @@ unsigned int __local_bh_count; unsigned int __syscall_count; struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ + unsigned long idle_timestamp; unsigned int __nmi_count; /* arch dependent */ +#if CONFIG_X86_LOCAL_APIC + unsigned int apic_timer_irqs; /* arch dependent */ +#endif } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/ide.h linux.20pre2-ac1/include/asm-i386/ide.h --- linux.20pre2/include/asm-i386/ide.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/ide.h 2002-08-06 18:24:33.000000000 +0100 @@ -23,8 +23,6 @@ # endif #endif -#define ide__sti() __sti() - static __inline__ int ide_default_irq(ide_ioreg_t base) { switch (base) { @@ -79,6 +77,7 @@ int index; for(index = 0; index < MAX_HWIFS; index++) { + memset(&hw, 0, sizeof hw); ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); hw.irq = ide_default_irq(ide_default_io_base(index)); ide_register_hw(&hw, NULL); @@ -86,29 +85,6 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ - } b; -} control_t; - #define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) #define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) #define ide_check_region(from,extent) check_region((from), (extent)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/io_apic.h linux.20pre2-ac1/include/asm-i386/io_apic.h --- linux.20pre2/include/asm-i386/io_apic.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/io_apic.h 2002-08-06 18:24:33.000000000 +0100 @@ -97,7 +97,7 @@ extern int mp_irq_entries; /* MP IRQ source entries */ -extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; +extern struct mpc_config_intsrc *mp_irqs; /* non-0 if default (table-less) MP configuration */ extern int mpc_default_type; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/ioctls.h linux.20pre2-ac1/include/asm-i386/ioctls.h --- linux.20pre2/include/asm-i386/ioctls.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/ioctls.h 2002-08-06 15:41:52.000000000 +0100 @@ -67,6 +67,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/mmu_context.h linux.20pre2-ac1/include/asm-i386/mmu_context.h --- linux.20pre2/include/asm-i386/mmu_context.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/mmu_context.h 2002-08-14 14:41:30.000000000 +0100 @@ -27,13 +27,13 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) { - if (prev != next) { + if (likely(prev != next)) { /* stop flush ipis for the previous mm */ clear_bit(cpu, &prev->cpu_vm_mask); /* * Re-load LDT if necessary */ - if (prev->context.segments != next->context.segments) + if (unlikely(prev->context.segments != next->context.segments)) load_LDT(next); #ifdef CONFIG_SMP cpu_tlbstate[cpu].state = TLBSTATE_OK; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/mpspec.h linux.20pre2-ac1/include/asm-i386/mpspec.h --- linux.20pre2/include/asm-i386/mpspec.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/mpspec.h 2002-08-06 18:24:33.000000000 +0100 @@ -14,7 +14,8 @@ #define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') /* - * a maximum of 16 APICs with the current APIC ID architecture. + * a maximum of 16 APICs with the classic APIC ID architecture. + * xAPICs can have up to 256. SAPICs have 16 ID bits. */ #ifdef CONFIG_MULTIQUAD #define MAX_APICS 256 @@ -184,11 +185,7 @@ * 7 2 CPU MCA+PCI */ -#ifdef CONFIG_MULTIQUAD -#define MAX_IRQ_SOURCES 512 -#else /* !CONFIG_MULTIQUAD */ #define MAX_IRQ_SOURCES 256 -#endif /* CONFIG_MULTIQUAD */ #define MAX_MP_BUSSES 32 enum mp_bustype { @@ -197,24 +194,23 @@ MP_BUS_PCI, MP_BUS_MCA }; -extern int mp_bus_id_to_type [MAX_MP_BUSSES]; -extern int mp_bus_id_to_node [MAX_MP_BUSSES]; -extern int mp_bus_id_to_local [MAX_MP_BUSSES]; +extern int *mp_bus_id_to_type; +extern int *mp_bus_id_to_node; +extern int *mp_bus_id_to_local; +extern int *mp_bus_id_to_pci_bus; extern int quad_local_to_mp_bus_id [NR_CPUS/4][4]; -extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; extern unsigned int boot_cpu_physical_apicid; +extern unsigned int boot_cpu_logical_apicid; extern unsigned long phys_cpu_present_map; extern int smp_found_config; extern void find_smp_config (void); extern void get_smp_config (void); extern int nr_ioapics; extern int apic_version [MAX_APICS]; -extern int mp_bus_id_to_type [MAX_MP_BUSSES]; extern int mp_irq_entries; -extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; +extern struct mpc_config_intsrc *mp_irqs; extern int mpc_default_type; -extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; extern int mp_current_pci_id; extern unsigned long mp_lapic_addr; extern int pic_mode; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/pci.h linux.20pre2-ac1/include/asm-i386/pci.h --- linux.20pre2/include/asm-i386/pci.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/pci.h 2002-08-14 14:41:30.000000000 +0100 @@ -103,7 +103,9 @@ if (direction == PCI_DMA_NONE) out_of_line_bug(); - return (dma_addr_t)(page - mem_map) * PAGE_SIZE + offset; + return ((dma_addr_t)(page - mem_map) * + (dma_addr_t) PAGE_SIZE + + (dma_addr_t) offset); } static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/pgalloc.h linux.20pre2-ac1/include/asm-i386/pgalloc.h --- linux.20pre2/include/asm-i386/pgalloc.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/pgalloc.h 2002-08-14 14:41:30.000000000 +0100 @@ -224,7 +224,7 @@ { struct mm_struct *active_mm; int state; -}; +} ____cacheline_aligned; extern struct tlb_state cpu_tlbstate[NR_CPUS]; #endif /* CONFIG_SMP */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/processor.h linux.20pre2-ac1/include/asm-i386/processor.h --- linux.20pre2/include/asm-i386/processor.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/processor.h 2002-08-14 14:40:57.000000000 +0100 @@ -96,7 +96,13 @@ extern void identify_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); -extern void dodgy_tsc(void); +extern int select_tsc(void); + +#define TSC_NONE 0 /* No TSC available, fall back to PIT */ +#define TSC_CPU 1 /* Use processor TSC */ +#define TSC_VISWS 2 /* VISWS hardware */ +#define TSC_CYCLONE 3 /* IBM cyclone timer */ +#define TSC_HPET 4 /* AMD HPET */ /* * EFLAGS bits @@ -510,4 +516,10 @@ #endif +/* We have an SMP load balancer */ + +/* If you are seeing weird crashes please retest with this commented out */ + +#define ARCH_HAS_SMP_BALANCE + #endif /* __ASM_I386_PROCESSOR_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/rmap.h linux.20pre2-ac1/include/asm-i386/rmap.h --- linux.20pre2/include/asm-i386/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _I386_RMAP_H +#define _I386_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/rwsem.h linux.20pre2-ac1/include/asm-i386/rwsem.h --- linux.20pre2/include/asm-i386/rwsem.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/rwsem.h 2002-08-14 14:41:29.000000000 +0100 @@ -4,6 +4,8 @@ * * Derived from asm-i386/semaphore.h * + * Trylock by Brian Watson (Brian.J.Watson@compaq.com). + * * * The MSW of the count is the negated number of active writers and waiting * lockers, and the LSW is the total number of active locks @@ -117,6 +119,29 @@ } /* + * trylock for reading -- returns 1 if successful, 0 if contention + */ +static inline int __down_read_trylock(struct rw_semaphore *sem) +{ + __s32 result, tmp; + __asm__ __volatile__( + "# beginning __down_read_trylock\n\t" + " movl %0,%1\n\t" + "1:\n\t" + " movl %1,%2\n\t" + " addl %3,%2\n\t" + " jle 2f\n\t" +LOCK_PREFIX " cmpxchgl %2,%0\n\t" + " jnz 1b\n\t" + "2:\n\t" + "# ending __down_read_trylock\n\t" + : "+m"(sem->count), "=&a"(result), "=&r"(tmp) + : "i"(RWSEM_ACTIVE_READ_BIAS) + : "memory", "cc"); + return result>=0 ? 1 : 0; +} + +/* * lock for writing */ static inline void __down_write(struct rw_semaphore *sem) @@ -144,6 +169,19 @@ } /* + * trylock for writing -- returns 1 if successful, 0 if contention + */ +static inline int __down_write_trylock(struct rw_semaphore *sem) +{ + signed long ret = cmpxchg(&sem->count, + RWSEM_UNLOCKED_VALUE, + RWSEM_ACTIVE_WRITE_BIAS); + if (ret == RWSEM_UNLOCKED_VALUE) + return 1; + return 0; +} + +/* * unlock after reading */ static inline void __up_read(struct rw_semaphore *sem) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/semaphore.h linux.20pre2-ac1/include/asm-i386/semaphore.h --- linux.20pre2/include/asm-i386/semaphore.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/semaphore.h 2002-08-14 14:41:29.000000000 +0100 @@ -213,5 +213,10 @@ :"memory"); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/smp_balance.h linux.20pre2-ac1/include/asm-i386/smp_balance.h --- linux.20pre2/include/asm-i386/smp_balance.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/smp_balance.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,43 @@ +#ifndef _ASM_SMP_BALANCE_H +#define _ASM_SMP_BALANCE_H + +/* + * Find any idle processor package (i.e. both virtual processors are idle) + */ + +static inline int find_idle_package(int this_cpu) +{ + int i = this_cpu + 1; + + if (i == smp_num_cpus) + i = 0; + + while (i != this_cpu) { + int physical, sibling; + physical = cpu_logical_map(i); + sibling = cpu_sibling_map[physical]; + + if (i++ == smp_num_cpus) + i = 0; + if (idle_cpu(physical) && idle_cpu(sibling)) + return physical; + } + return -1; /* not found */ +} + +static inline int arch_load_balance(int this_cpu, int idle) +{ + /* Special hack for hyperthreading */ + if (smp_num_siblings > 1 && idle && !idle_cpu(cpu_sibling_map[this_cpu])) { + int found; + struct runqueue *rq_target; + + if ((found = find_idle_package(this_cpu)) >= 0 ) { + rq_target = cpu_rq(found); + resched_task(rq_target->idle); + return 1; + } + } + return 0; +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/smpboot.h linux.20pre2-ac1/include/asm-i386/smpboot.h --- linux.20pre2/include/asm-i386/smpboot.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/smpboot.h 2002-08-14 14:41:30.000000000 +0100 @@ -1,62 +1,55 @@ #ifndef __ASM_SMPBOOT_H #define __ASM_SMPBOOT_H -#ifndef clustered_apic_mode - #ifdef CONFIG_MULTIQUAD - #define clustered_apic_mode (1) - #else /* !CONFIG_MULTIQUAD */ - #define clustered_apic_mode (0) - #endif /* CONFIG_MULTIQUAD */ -#endif - -#ifdef CONFIG_MULTIQUAD - #define TRAMPOLINE_LOW phys_to_virt(0x8) - #define TRAMPOLINE_HIGH phys_to_virt(0xa) -#else /* !CONFIG_MULTIQUAD */ - #define TRAMPOLINE_LOW phys_to_virt(0x467) - #define TRAMPOLINE_HIGH phys_to_virt(0x469) -#endif /* CONFIG_MULTIQUAD */ - -#ifdef CONFIG_MULTIQUAD - #define boot_cpu_apicid boot_cpu_logical_apicid -#else /* !CONFIG_MULTIQUAD */ - #define boot_cpu_apicid boot_cpu_physical_apicid -#endif /* CONFIG_MULTIQUAD */ +#ifndef __ASM_SMP_H +#include "asm/smp.h" +#endif + +#define TRAMPOLINE_LOW phys_to_virt(clustered_apic_logical?0x8:0x467) +#define TRAMPOLINE_HIGH phys_to_virt(clustered_apic_logical?0xa:0x469) + +extern unsigned char raw_phys_apicid[NR_CPUS]; /* - * How to map from the cpu_present_map + * To build the logical APIC ID for each CPU we have three cases: + * 1) Normal flat mode: use a bitmap of the CPU numbers + * 2) Logical multi-quad (NUMA-Q): do nothing, the BIOS has set it up + * 3) Physical multi-quad (xAPIC clusters): convert the Intel standard + * physical APIC ID to a cluster nibble/cpu bitmap nibble + * + *** mps_cpu (index number): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... + *** CPUs have xAPIC phys IDs: 00, 01, 02, 03, 10, 11, 12, 13, 20, 21, ... + *** its logical ID: 01, 02, 04, 08, 11, 12, 14, 18, 21, 22, ... */ -#ifdef CONFIG_MULTIQUAD - #define cpu_present_to_apicid(mps_cpu) ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) ) -#else /* !CONFIG_MULTIQUAD */ - #define cpu_present_to_apicid(apicid) (apicid) -#endif /* CONFIG_MULTIQUAD */ + +#define physical_to_logical_apicid(phys_apic) ( (1ul << ((phys_apic) & 0x3)) | ((phys_apic) & APIC_DEST_CLUSTER_MASK) ) + +static inline int cpu_present_to_apicid(int mps_cpu) +{ + if(clustered_apic_logical) + return (mps_cpu/4)*16 + (1<<(mps_cpu%4)); + if(clustered_apic_physical) + return raw_phys_apicid[mps_cpu]; + return 1 << mps_cpu; +} + +static inline unsigned long apicid_to_phys_cpu_present(int apicid) +{ + if(clustered_apic_mode) + return 1UL << (((apicid >> 4) << 2) + (apicid & 0x3)); + return 1UL << apicid; +} /* * Mappings between logical cpu number and logical / physical apicid - * The first four macros are trivial, but it keeps the abstraction consistent + * The first two macros are trivial, but it keeps the abstraction consistent */ -extern volatile int logical_apicid_2_cpu[]; -extern volatile int cpu_2_logical_apicid[]; -extern volatile int physical_apicid_2_cpu[]; -extern volatile int cpu_2_physical_apicid[]; - -#define logical_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid] -#define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu] -#define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] -#define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu] -#ifdef CONFIG_MULTIQUAD /* use logical IDs to bootstrap */ -#define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid] -#define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu] -#else /* !CONFIG_MULTIQUAD */ /* use physical IDs to bootstrap */ -#define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] -#define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu] -#endif /* CONFIG_MULTIQUAD */ - - -#ifdef CONFIG_MULTIQUAD -#else /* !CONFIG_MULTIQUAD */ -#endif /* CONFIG_MULTIQUAD */ + +extern volatile u8 cpu_2_logical_apicid[]; +extern volatile u8 cpu_2_physical_apicid[]; + +#define cpu_to_logical_apicid(cpu) (int)cpu_2_logical_apicid[cpu] +#define cpu_to_physical_apicid(cpu) (int)cpu_2_physical_apicid[cpu] #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/smp.h linux.20pre2-ac1/include/asm-i386/smp.h --- linux.20pre2/include/asm-i386/smp.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/smp.h 2002-08-14 14:41:29.000000000 +0100 @@ -22,37 +22,54 @@ #endif #endif -#ifdef CONFIG_SMP +#ifdef CONFIG_X86_LOCAL_APIC # ifdef CONFIG_MULTIQUAD -# define TARGET_CPUS 0xf /* all CPUs in *THIS* quad */ -# define INT_DELIVERY_MODE 0 /* physical delivery on LOCAL quad */ +#define TARGET_CPUS (__target_cpus()) +#define INT_DEST_ADDR_MODE (int_dest_addr_mode) +#define INT_DELIVERY_MODE (int_delivery_mode) # else -# define TARGET_CPUS cpu_online_map -# define INT_DELIVERY_MODE 1 /* logical delivery broadcast to all procs */ +#define TARGET_CPUS cpu_online_map +#define INT_DEST_ADDR_MODE APIC_DEST_LOGICAL /* logical delivery */ +#define INT_DELIVERY_MODE (dest_LowestPrio) # endif #else -# define INT_DELIVERY_MODE 1 /* logical delivery */ -# define TARGET_CPUS 0x01 +#define clustered_apic_mode (0) +#define apic_broadcast_id (0x0Fu) +#define esr_disable (0) +#define logical_cpu_present_map (1) +#define TARGET_CPUS 0x01 +#define INT_DEST_ADDR_MODE 0x800u /* logical delivery */ +#define INT_DELIVERY_MODE (1) /* dest_LowestPrio */ #endif -#ifndef clustered_apic_mode - #ifdef CONFIG_MULTIQUAD - #define clustered_apic_mode (1) - #define esr_disable (1) - #else /* !CONFIG_MULTIQUAD */ - #define clustered_apic_mode (0) - #define esr_disable (0) - #endif /* CONFIG_MULTIQUAD */ -#endif +#define APIC_DEST_CLUSTER_MASK 0xF0u /* Destination masks */ +#define APIC_DEST_CPUS_MASK 0x0Fu /* when clustered. */ + +#define CLUSTERED_APIC_LOGICAL 0x01 +#define CLUSTERED_APIC_PHYSICAL 0x02 +#define clustered_apic_logical (clustered_apic_mode & CLUSTERED_APIC_LOGICAL) +#define clustered_apic_physical (clustered_apic_mode & CLUSTERED_APIC_PHYSICAL) -#ifdef CONFIG_SMP #ifndef __ASSEMBLY__ +#ifdef CONFIG_X86_LOCAL_APIC + +extern unsigned char clustered_apic_mode; +extern unsigned char esr_disable; +extern unsigned char int_delivery_mode; +extern unsigned int int_dest_addr_mode; +extern unsigned int apic_broadcast_id; + +#endif + +#ifdef CONFIG_SMP + /* * Private routines/data */ extern void smp_alloc_memory(void); +extern unsigned long logical_cpu_present_map; extern unsigned long phys_cpu_present_map; extern unsigned long cpu_online_map; extern volatile unsigned long smp_invalidate_needed; @@ -63,6 +80,7 @@ extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_send_reschedule(int cpu); +extern void smp_send_reschedule_all(void); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings (void); @@ -86,6 +104,7 @@ * the real APIC ID <-> CPU # mapping. */ #define MAX_APICID 256 +#define BAD_APICID 0xFFu extern volatile int cpu_to_physical_apicid[NR_CPUS]; extern volatile int physical_apicid_to_cpu[MAX_APICID]; extern volatile int cpu_to_logical_apicid[NR_CPUS]; @@ -104,7 +123,7 @@ * so this is correct in the x86 case. */ -#define smp_processor_id() (current->processor) +#define smp_processor_id() (current->cpu) static __inline int hard_smp_processor_id(void) { @@ -118,21 +137,8 @@ return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR)); } +#endif #endif /* !__ASSEMBLY__ */ #define NO_PROC_ID 0xFF /* No processor magic marker */ - -/* - * This magic constant controls our willingness to transfer - * a process across CPUs. Such a transfer incurs misses on the L1 - * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My - * gut feeling is this will vary by board in value. For a board - * with separate L2 cache it probably depends also on the RSS, and - * for a board with shared L2 cache it ought to decay fast as other - * processes are run. - */ - -#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */ - -#endif #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/spinlock.h linux.20pre2-ac1/include/asm-i386/spinlock.h --- linux.20pre2/include/asm-i386/spinlock.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/spinlock.h 2002-08-06 18:24:34.000000000 +0100 @@ -49,7 +49,7 @@ * We make no fairness assumptions. They have a cost. */ -#define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0) +#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0) #define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) #define spin_lock_string \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/system.h linux.20pre2-ac1/include/asm-i386/system.h --- linux.20pre2/include/asm-i386/system.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/system.h 2002-08-13 22:28:54.000000000 +0100 @@ -12,25 +12,22 @@ struct task_struct; /* one of the stranger aspects of C forward declarations.. */ extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); -#define prepare_to_switch() do { } while(0) #define switch_to(prev,next,last) do { \ asm volatile("pushl %%esi\n\t" \ "pushl %%edi\n\t" \ "pushl %%ebp\n\t" \ "movl %%esp,%0\n\t" /* save ESP */ \ - "movl %3,%%esp\n\t" /* restore ESP */ \ + "movl %2,%%esp\n\t" /* restore ESP */ \ "movl $1f,%1\n\t" /* save EIP */ \ - "pushl %4\n\t" /* restore EIP */ \ + "pushl %3\n\t" /* restore EIP */ \ "jmp __switch_to\n" \ "1:\t" \ "popl %%ebp\n\t" \ "popl %%edi\n\t" \ "popl %%esi\n\t" \ - :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \ - "=b" (last) \ + :"=m" (prev->thread.esp),"=m" (prev->thread.eip) \ :"m" (next->thread.esp),"m" (next->thread.eip), \ - "a" (prev), "d" (next), \ - "b" (prev)); \ + "a" (prev), "d" (next)); \ } while (0) #define _set_base(addr,base) do { unsigned long __pr; \ @@ -322,8 +319,18 @@ /* used in the idle loop; sti takes one instruction cycle to complete */ #define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory") +#define __save_and_cli(x) do { __save_flags(x); __cli(); } while(0); +#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0); + /* For spinlocks etc */ +#if 0 #define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") +#define local_irq_set(x) __asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory") +#else +#define local_irq_save(x) __save_and_cli(x) +#define local_irq_set(x) __save_and_sti(x) +#endif + #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti() @@ -338,6 +345,8 @@ #define sti() __global_sti() #define save_flags(x) ((x)=__global_save_flags()) #define restore_flags(x) __global_restore_flags(x) +#define save_and_cli(x) do { save_flags(x); cli(); } while(0); +#define save_and_sti(x) do { save_flags(x); sti(); } while(0); #else @@ -345,6 +354,8 @@ #define sti() __sti() #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) +#define save_and_cli(x) __save_and_cli(x) +#define save_and_sti(x) __save_and_sti(x) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-i386/termios.h linux.20pre2-ac1/include/asm-i386/termios.h --- linux.20pre2/include/asm-i386/termios.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-i386/termios.h 2002-08-06 15:41:52.000000000 +0100 @@ -37,6 +37,8 @@ #define TIOCM_OUT2 0x4000 #define TIOCM_LOOP 0x8000 +#define TIOCM_MODEM_BITS TIOCM_OUT2 /* IRDA support */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ /* line disciplines */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ia64/efi.h linux.20pre2-ac1/include/asm-ia64/efi.h --- linux.20pre2/include/asm-ia64/efi.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ia64/efi.h 2002-08-06 15:41:52.000000000 +0100 @@ -32,13 +32,18 @@ typedef u8 efi_bool_t; typedef u16 efi_char16_t; /* UNICODE character */ + typedef struct { - u32 data1; - u16 data2; - u16 data3; - u8 data4[8]; + u8 b[16]; } efi_guid_t; +#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ +((efi_guid_t) \ +{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ + (b) & 0xff, ((b) >> 8) & 0xff, \ + (c) & 0xff, ((c) >> 8) & 0xff, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) + /* * Generic EFI table header */ @@ -165,21 +170,23 @@ /* * EFI Configuration Table and GUID definitions */ +#define NULL_GUID \ + EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) #define MPS_TABLE_GUID \ - ((efi_guid_t) { 0xeb9d2d2f, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) + EFI_GUID( 0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) #define ACPI_TABLE_GUID \ - ((efi_guid_t) { 0xeb9d2d30, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) + EFI_GUID( 0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) #define ACPI_20_TABLE_GUID \ - ((efi_guid_t) { 0x8868e871, 0xe4f1, 0x11d3, { 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 }}) + EFI_GUID( 0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 ) #define SMBIOS_TABLE_GUID \ - ((efi_guid_t) { 0xeb9d2d31, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) + EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) #define SAL_SYSTEM_TABLE_GUID \ - ((efi_guid_t) { 0xeb9d2d32, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}) + EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) #define HCDP_TABLE_GUID \ ((efi_guid_t) { 0xf951938d, 0x620b, 0x42ef, {0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98}}) @@ -237,6 +244,17 @@ return memcmp(&left, &right, sizeof (efi_guid_t)); } +static inline char * +efi_guid_unparse(efi_guid_t *guid, char *out) +{ + sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->b[0], guid->b[1], guid->b[2], guid->b[3], + guid->b[4], guid->b[5], guid->b[6], guid->b[7], + guid->b[8], guid->b[9], guid->b[10], guid->b[11], + guid->b[12], guid->b[13], guid->b[14], guid->b[15]); + return out; +} + extern void efi_init (void); extern void efi_map_pal_code (void); extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ia64/ide.h linux.20pre2-ac1/include/asm-ia64/ide.h --- linux.20pre2/include/asm-ia64/ide.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ia64/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -25,8 +25,6 @@ # endif #endif -#define ide__sti() __sti() - static __inline__ int ide_default_irq (ide_ioreg_t base) { @@ -92,29 +90,6 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ - } b; -} control_t; - #define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) #define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) #define ide_check_region(from,extent) check_region((from), (extent)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ia64/ioctls.h linux.20pre2-ac1/include/asm-ia64/ioctls.h --- linux.20pre2/include/asm-ia64/ioctls.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ia64/ioctls.h 2002-08-06 15:41:52.000000000 +0100 @@ -72,6 +72,7 @@ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ #define TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ +#define FIOQSIZE 0x5460 /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ia64/rmap.h linux.20pre2-ac1/include/asm-ia64/rmap.h --- linux.20pre2/include/asm-ia64/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ia64/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _IA64_RMAP_H +#define _IA64_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ia64/sal.h linux.20pre2-ac1/include/asm-ia64/sal.h --- linux.20pre2/include/asm-ia64/sal.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ia64/sal.h 2002-08-06 15:41:52.000000000 +0100 @@ -241,32 +241,32 @@ /* SAL Error Record Section GUID Definitions */ #define SAL_PROC_DEV_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf1, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID ( 0xe429faf1, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_MEM_DEV_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf2, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf2, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_SEL_DEV_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf3, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf3, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_PCI_BUS_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf4, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf4, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf5, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf5, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_PCI_COMP_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf6, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf6, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_SPECIFIC_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf7, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf7, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_HOST_CTLR_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf8, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf8, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define SAL_PLAT_BUS_ERR_SECT_GUID \ - ((efi_guid_t) { 0xe429faf9, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ - 0xc7, 0x3c, 0x88, 0x81 }} ) + EFI_GUID( 0xe429faf9, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 ) #define MAX_CACHE_ERRORS 6 #define MAX_TLB_ERRORS 6 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ia64/semaphore.h linux.20pre2-ac1/include/asm-ia64/semaphore.h --- linux.20pre2/include/asm-ia64/semaphore.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ia64/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -117,4 +117,9 @@ __up(sem); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif /* _ASM_IA64_SEMAPHORE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ia64/system.h linux.20pre2-ac1/include/asm-ia64/system.h --- linux.20pre2/include/asm-ia64/system.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ia64/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -165,6 +165,15 @@ :: "r" (x) : "memory") #endif /* !CONFIG_IA64_DEBUG_IRQ */ +#error andre hedrick screwed this up please help unscrew in order to clean up +/* + * __save_and_sti(x) == __save_flags(x); ide__sti(); + * __save_flags(x); __sti(); + * + * local_irq_set(x) == __save_and_sti(x) + */ + + #define local_irq_enable() __asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory") #define __cli() local_irq_disable () diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-m68k/ide.h linux.20pre2-ac1/include/asm-m68k/ide.h --- linux.20pre2/include/asm-m68k/ide.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-m68k/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -80,29 +80,6 @@ { } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit7 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit5 : 1; /* always 1 */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned head : 4; /* always zeros here */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned HOB : 1; /* 48-bit address ordering */ - unsigned reserved456 : 3; - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned bit0 : 1; - } b; -} control_t; - static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id) { @@ -352,34 +329,6 @@ #define ide_ack_intr(hwif) ((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1) -/* - * On the Atari, we sometimes can't enable interrupts: - */ - -/* MSch: changed sti() to STI() wherever possible in ide.c; moved STI() def. - * to asm/ide.h - */ -/* The Atari interrupt structure strictly requires that the IPL isn't lowered - * uncontrolled in an interrupt handler. In the concrete case, the IDE - * interrupt is already a slow int, so the irq is already disabled at the time - * the handler is called, and the IPL has been lowered to the minimum value - * possible. To avoid going below that, STI() checks for being called inside - * an interrupt, and in that case it does nothing. Hope that is reasonable and - * works. (Roman) - */ -#ifdef MACH_ATARI_ONLY -#define ide__sti() \ - do { \ - if (!in_interrupt()) __sti(); \ - } while(0) -#elif defined(CONFIG_ATARI) -#define ide__sti() \ - do { \ - if (!MACH_IS_ATARI || !in_interrupt()) sti(); \ - } while(0) -#else /* !defined(CONFIG_ATARI) */ -#define ide__sti() __sti() -#endif #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-m68k/ioctls.h linux.20pre2-ac1/include/asm-m68k/ioctls.h --- linux.20pre2/include/asm-m68k/ioctls.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-m68k/ioctls.h 2002-08-06 15:41:52.000000000 +0100 @@ -65,6 +65,7 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define FIOQSIZE 0x545E /* Used for packet mode */ #define TIOCPKT_DATA 0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-m68k/rmap.h linux.20pre2-ac1/include/asm-m68k/rmap.h --- linux.20pre2/include/asm-m68k/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-m68k/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _M86K_RMAP_H +#define _M86K_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-m68k/semaphore.h linux.20pre2-ac1/include/asm-m68k/semaphore.h --- linux.20pre2/include/asm-m68k/semaphore.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-m68k/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -182,6 +182,12 @@ : "memory"); } + +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif /* __ASSEMBLY__ */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-m68k/system.h linux.20pre2-ac1/include/asm-m68k/system.h --- linux.20pre2/include/asm-m68k/system.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-m68k/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -47,7 +47,6 @@ (last) = _last; \ } - /* interrupt control.. */ #if 0 #define __sti() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory") @@ -64,6 +63,7 @@ /* For spinlocks etc */ #define local_irq_save(x) ({ __save_flags(x); __cli(); }) +#define local_irq_set(x) ({ __save_flags(x); __sti(); }) #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti() @@ -72,7 +72,8 @@ #define sti() __sti() #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) -#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0) +#define save_and_cli(x) do { save_flags(x); cli(); } while(0) +#define save_and_set(x) do { save_flags(x); sti(); } while(0) /* * Force strict CPU ordering. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-mips/ide.h linux.20pre2-ac1/include/asm-mips/ide.h --- linux.20pre2/include/asm-mips/ide.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-mips/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -24,8 +24,6 @@ # endif #endif -#define ide__sti() __sti() - struct ide_ops { int (*ide_default_irq)(ide_ioreg_t base); ide_ioreg_t (*ide_default_io_base)(int index); @@ -73,46 +71,6 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { -#ifdef __MIPSEB__ - unsigned bit7 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit5 : 1; /* always 1 */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned head : 4; /* always zeros here */ -#else - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ -#endif - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { -#ifdef __MIPSEB__ - unsigned HOB : 1; /* 48-bit address ordering */ - unsigned reserved456 : 3; - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned bit0 : 1; -#else - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ -#endif - } b; -} control_t; - static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-mips/rmap.h linux.20pre2-ac1/include/asm-mips/rmap.h --- linux.20pre2/include/asm-mips/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-mips/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _MIPS_RMAP_H +#define _MIPS_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-mips/semaphore.h linux.20pre2-ac1/include/asm-mips/semaphore.h --- linux.20pre2/include/asm-mips/semaphore.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-mips/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -194,4 +194,9 @@ __up(sem); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif /* _ASM_SEMAPHORE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-mips/system.h linux.20pre2-ac1/include/asm-mips/system.h --- linux.20pre2/include/asm-mips/system.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-mips/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -111,6 +111,8 @@ : /* no inputs */ \ : "memory") +#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0); + __asm__(".macro\t__restore_flags flags\n\t" ".set\tnoreorder\n\t" ".set\tnoat\n\t" @@ -149,6 +151,7 @@ # define save_flags(x) do { x = __global_save_flags(); } while (0) # define restore_flags(x) __global_restore_flags(x) # define save_and_cli(x) do { save_flags(x); cli(); } while(0) +# define save_and_sti(x) do { save_flags(x); sti(); } while(0) #else /* Single processor */ @@ -157,11 +160,13 @@ # define save_flags(x) __save_flags(x) # define save_and_cli(x) __save_and_cli(x) # define restore_flags(x) __restore_flags(x) +# define save_and_sti(x) __save_and_sti(x) #endif /* SMP */ /* For spinlocks etc */ #define local_irq_save(x) __save_and_cli(x) +#define local_irq_set(x) __save_and_sti(x) #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti() diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-mips64/ide.h linux.20pre2-ac1/include/asm-mips64/ide.h --- linux.20pre2/include/asm-mips64/ide.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-mips64/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -27,8 +27,6 @@ # endif #endif -#define ide__sti() __sti() - struct ide_ops { int (*ide_default_irq)(ide_ioreg_t base); ide_ioreg_t (*ide_default_io_base)(int index); @@ -76,38 +74,6 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { -#ifdef __MIPSEB__ - unsigned HOB : 1; /* 48-bit address ordering */ - unsigned reserved456 : 3; - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned bit0 : 1; -#else - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ -#endif - } b; -} control_t; - static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-mips64/rmap.h linux.20pre2-ac1/include/asm-mips64/rmap.h --- linux.20pre2/include/asm-mips64/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-mips64/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _MIPS64_RMAP_H +#define _MIPS64_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-mips64/semaphore.h linux.20pre2-ac1/include/asm-mips64/semaphore.h --- linux.20pre2/include/asm-mips64/semaphore.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-mips64/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -170,4 +170,9 @@ __up(sem); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif /* _ASM_SEMAPHORE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-mips64/system.h linux.20pre2-ac1/include/asm-mips64/system.h --- linux.20pre2/include/asm-mips64/system.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-mips64/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -106,6 +106,8 @@ : /* no inputs */ \ : "memory") +#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0); + __asm__(".macro\t__restore_flags flags\n\t" ".set\tnoreorder\n\t" ".set\tnoat\n\t" @@ -144,6 +146,7 @@ #define save_flags(x) ((x)=__global_save_flags()) #define restore_flags(x) __global_restore_flags(x) #define save_and_cli(x) do { save_flags(x); cli(); } while(0) +#define save_and_sti(x) do { save_flags(x); sti(); } while(0) #else @@ -152,11 +155,13 @@ #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) #define save_and_cli(x) __save_and_cli(x) +#define save_and_sti(x) __save_and_sti(x) #endif /* CONFIG_SMP */ /* For spinlocks etc */ #define local_irq_save(x) __save_and_cli(x) +#define local_irq_set(x) __save_and_sti(x) #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti() diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc/hw_irq.h linux.20pre2-ac1/include/asm-ppc/hw_irq.h --- linux.20pre2/include/asm-ppc/hw_irq.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc/hw_irq.h 2002-08-13 14:46:37.000000000 +0100 @@ -21,6 +21,7 @@ #define __save_flags(flags) __save_flags_ptr((unsigned long *)&flags) #define __save_and_cli(flags) ({__save_flags(flags);__cli();}) +#define __save_and_sti(flags) ({__save_flags(flags);__sti();}) extern void do_lost_interrupts(unsigned long); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc/ide.h linux.20pre2-ac1/include/asm-ppc/ide.h --- linux.20pre2/include/asm-ppc/ide.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -57,8 +57,6 @@ #undef SUPPORT_VLB_SYNC #define SUPPORT_VLB_SYNC 0 -#define ide__sti() __sti() - static __inline__ int ide_default_irq(ide_ioreg_t base) { if (ppc_ide_md.default_irq) @@ -118,29 +116,6 @@ ppc_ide_md.ide_release_region(from, extent); } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit7 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit5 : 1; /* always 1 */ - unsigned unit : 1; /* drive select number, 0/1 */ - unsigned head : 4; /* always zeros here */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned HOB : 1; /* 48-bit address ordering */ - unsigned reserved456 : 3; - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned bit0 : 1; - } b; -} control_t; - #if !defined(ide_request_irq) #define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc/rmap.h linux.20pre2-ac1/include/asm-ppc/rmap.h --- linux.20pre2/include/asm-ppc/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,9 @@ +#ifndef _PPC_RMAP_H +#define _PPC_RMAP_H + +/* PPC calls pte_alloc() before mem_map[] is setup ... */ +#define BROKEN_PPC_PTE_ALLOC_ONE + +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc/semaphore.h linux.20pre2-ac1/include/asm-ppc/semaphore.h --- linux.20pre2/include/asm-ppc/semaphore.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -133,6 +133,11 @@ __up(sem); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif /* __KERNEL__ */ #endif /* !(_PPC_SEMAPHORE_H) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc/system.h linux.20pre2-ac1/include/asm-ppc/system.h --- linux.20pre2/include/asm-ppc/system.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -105,6 +105,7 @@ #define save_flags(flags) __save_flags(flags) #define restore_flags(flags) __restore_flags(flags) #define save_and_cli(flags) __save_and_cli(flags) +#define save_and_sti(flags) __save_and_sti(flags) #else /* CONFIG_SMP */ @@ -117,11 +118,15 @@ #define save_flags(x) ((x)=__global_save_flags()) #define restore_flags(x) __global_restore_flags(x) +#define save_and_cli(x) do { save_flags(x); cli(); } while(0); +#define save_and_sti(x) do { save_flags(x); sti(); } while(0); + #endif /* !CONFIG_SMP */ #define local_irq_disable() __cli() #define local_irq_enable() __sti() #define local_irq_save(flags) __save_and_cli(flags) +#define local_irq_set(flags) __save_and_sti(flags) #define local_irq_restore(flags) __restore_flags(flags) static __inline__ unsigned long diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc64/hw_irq.h linux.20pre2-ac1/include/asm-ppc64/hw_irq.h --- linux.20pre2/include/asm-ppc64/hw_irq.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc64/hw_irq.h 2002-08-06 15:41:55.000000000 +0100 @@ -31,6 +31,7 @@ #define __save_flags(flags) ((flags) = __no_use_save_flags()) #define __restore_flags(flags) __no_use_restore_flags((unsigned long)flags) #define __save_and_cli(flags) ({__save_flags(flags);__cli();}) +#define __save_and_sti(flags) ({__save_flags(flags);__sti();}) #else @@ -63,6 +64,7 @@ } #define __save_and_cli(flags) __do_save_and_cli(&flags) +#define __save_and_sti(flags) ({__save_flags(flags);__sti();}) #endif /* CONFIG_PPC_ISERIES */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc64/ide.h linux.20pre2-ac1/include/asm-ppc64/ide.h --- linux.20pre2/include/asm-ppc64/ide.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc64/ide.h 2002-08-06 15:41:55.000000000 +0100 @@ -22,8 +22,6 @@ #define MAX_HWIFS 4 #endif -#define ide__sti() __sti() - void ppc64_ide_fix_driveid(struct hd_driveid *id); #define ide_fix_driveid(id) ppc64_ide_fix_driveid((id)) @@ -53,17 +51,6 @@ { } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; - } select_t; - #define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) #define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) #define ide_check_region(from,extent) check_region((from), (extent)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc64/semaphore.h linux.20pre2-ac1/include/asm-ppc64/semaphore.h --- linux.20pre2/include/asm-ppc64/semaphore.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc64/semaphore.h 2002-08-06 15:41:56.000000000 +0100 @@ -130,6 +130,11 @@ __up(sem); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif /* __KERNEL__ */ #endif /* !(_PPC64_SEMAPHORE_H) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-ppc64/system.h linux.20pre2-ac1/include/asm-ppc64/system.h --- linux.20pre2/include/asm-ppc64/system.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-ppc64/system.h 2002-08-06 15:41:56.000000000 +0100 @@ -102,6 +102,7 @@ #define save_flags(flags) __save_flags(flags) #define restore_flags(flags) __restore_flags(flags) #define save_and_cli(flags) __save_and_cli(flags) +#define save_and_sti(flags) __save_and_sti(flags) #else /* CONFIG_SMP */ @@ -114,11 +115,15 @@ #define save_flags(x) ((x)=__global_save_flags()) #define restore_flags(x) __global_restore_flags(x) +#define save_and_cli(x) do { save_flags(x); cli(); } while(0); +#define save_and_sti(x) do { save_flags(x); sti(); } while(0); + #endif /* !CONFIG_SMP */ #define local_irq_disable() __cli() #define local_irq_enable() __sti() #define local_irq_save(flags) __save_and_cli(flags) +#define local_irq_set(flags) __save_and_sti(flags) #define local_irq_restore(flags) __restore_flags(flags) static __inline__ int __is_processor(unsigned long pv) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-s390/ide.h linux.20pre2-ac1/include/asm-s390/ide.h --- linux.20pre2/include/asm-s390/ide.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-s390/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -15,31 +15,6 @@ #define MAX_HWIFS 0 #endif -#define ide__sti() do {} while (0) - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ - } b; -} control_t; - #define ide_request_irq(irq,hand,flg,dev,id) do {} while (0) #define ide_free_irq(irq,dev_id) do {} while (0) #define ide_check_region(from,extent) do {} while (0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-s390/rmap.h linux.20pre2-ac1/include/asm-s390/rmap.h --- linux.20pre2/include/asm-s390/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-s390/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _S390_RMAP_H +#define _S390_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-s390/semaphore.h linux.20pre2-ac1/include/asm-s390/semaphore.h --- linux.20pre2/include/asm-s390/semaphore.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-s390/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -92,4 +92,9 @@ __up(sem); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-s390/system.h linux.20pre2-ac1/include/asm-s390/system.h --- linux.20pre2/include/asm-s390/system.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/asm-s390/system.h 2002-08-13 14:46:55.000000000 +0100 @@ -206,8 +206,12 @@ : "cc", "0", "1", "2"); \ }) +#define __save_and_cli(x) do { __save_flags(x); __cli(); } while(0); +#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0); + /* For spinlocks etc */ #define local_irq_save(x) ((x) = __cli()) +#define local_irq_set(x) __save_and_sti(x) #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti() @@ -223,6 +227,8 @@ #define sti() __global_sti() #define save_flags(x) ((x)=__global_save_flags()) #define restore_flags(x) __global_restore_flags(x) +#define save_and_cli(x) do { save_flags(x); cli(); } while(0); +#define save_and_sti(x) do { save_flags(x); sti(); } while(0); extern void smp_ctl_set_bit(int cr, int bit); extern void smp_ctl_clear_bit(int cr, int bit); @@ -235,6 +241,8 @@ #define sti() __sti() #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) +#define save_and_cli(x) __save_and_cli(x) +#define save_and_sti(x) __save_and_sti(x) #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit) #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-s390x/ide.h linux.20pre2-ac1/include/asm-s390x/ide.h --- linux.20pre2/include/asm-s390x/ide.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-s390x/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -15,31 +15,6 @@ #define MAX_HWIFS 0 #endif -#define ide__sti() do {} while (0) - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ - } b; -} control_t; - #define ide_request_irq(irq,hand,flg,dev,id) do {} while (0) #define ide_free_irq(irq,dev_id) do {} while (0) #define ide_check_region(from,extent) do {} while (0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-s390x/rmap.h linux.20pre2-ac1/include/asm-s390x/rmap.h --- linux.20pre2/include/asm-s390x/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-s390x/rmap.h 2002-08-06 15:41:55.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _S390X_RMAP_H +#define _S390X_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-s390x/semaphore.h linux.20pre2-ac1/include/asm-s390x/semaphore.h --- linux.20pre2/include/asm-s390x/semaphore.h 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/include/asm-s390x/semaphore.h 2002-08-06 15:41:55.000000000 +0100 @@ -92,4 +92,9 @@ __up(sem); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-s390x/system.h linux.20pre2-ac1/include/asm-s390x/system.h --- linux.20pre2/include/asm-s390x/system.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/asm-s390x/system.h 2002-08-13 14:46:55.000000000 +0100 @@ -216,8 +216,13 @@ : "cc", "0", "1", "2"); \ }) + +#define __save_and_cli(x) do { __save_flags(x); __cli(); } while(0); +#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0); + /* For spinlocks etc */ #define local_irq_save(x) ((x) = __cli()) +#define local_irq_set(x) __save_and_sti(x) #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti() @@ -233,6 +238,8 @@ #define sti() __global_sti() #define save_flags(x) ((x)=__global_save_flags()) #define restore_flags(x) __global_restore_flags(x) +#define save_and_cli(x) do { save_flags(x); cli(); } while(0); +#define save_and_sti(x) do { save_flags(x); sti(); } while(0); extern void smp_ctl_set_bit(int cr, int bit); extern void smp_ctl_clear_bit(int cr, int bit); @@ -245,6 +252,8 @@ #define sti() __sti() #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) +#define save_and_cli(x) __save_and_cli(x) +#define save_and_sti(x) __save_and_sti(x) #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit) #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sh/ide.h linux.20pre2-ac1/include/asm-sh/ide.h --- linux.20pre2/include/asm-sh/ide.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sh/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -22,8 +22,6 @@ #define MAX_HWIFS 2 #endif -#define ide__sti() __sti() - static __inline__ int ide_default_irq_hp600(ide_ioreg_t base) { switch (base) { @@ -107,29 +105,6 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ } -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned head : 4; /* always zeros here */ - unsigned unit : 1; /* drive select number, 0 or 1 */ - unsigned bit5 : 1; /* always 1 */ - unsigned lba : 1; /* using LBA instead of CHS */ - unsigned bit7 : 1; /* always 1 */ - } b; -} select_t; - -typedef union { - unsigned all : 8; /* all of the bits together */ - struct { - unsigned bit0 : 1; - unsigned nIEN : 1; /* device INTRQ to host */ - unsigned SRST : 1; /* host soft reset bit */ - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned reserved456 : 3; - unsigned HOB : 1; /* 48-bit address ordering */ - } b; -} control_t; - #define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) #define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) #define ide_check_region(from,extent) check_region((from), (extent)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sh/ioctls.h linux.20pre2-ac1/include/asm-sh/ioctls.h --- linux.20pre2/include/asm-sh/ioctls.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sh/ioctls.h 2002-08-06 15:41:52.000000000 +0100 @@ -9,6 +9,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) #define TCGETS 0x5401 #define TCSETS 0x5402 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sh/rmap.h linux.20pre2-ac1/include/asm-sh/rmap.h --- linux.20pre2/include/asm-sh/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sh/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _SH_RMAP_H +#define _SH_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sh/semaphore.h linux.20pre2-ac1/include/asm-sh/semaphore.h --- linux.20pre2/include/asm-sh/semaphore.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sh/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -135,5 +135,10 @@ __up(sem); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif #endif /* __ASM_SH_SEMAPHORE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sh/system.h linux.20pre2-ac1/include/asm-sh/system.h --- linux.20pre2/include/asm-sh/system.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sh/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -215,8 +215,11 @@ : "=&r" (__dummy)); \ } while (0) +#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0); + /* For spinlocks etc */ #define local_irq_save(x) x = __save_and_cli() +#define local_irq_set(x) __save_and_sti(x) #define local_irq_restore(x) __restore_flags(x) #define local_irq_disable() __cli() #define local_irq_enable() __sti() @@ -231,13 +234,14 @@ #define sti() __global_sti() #define save_flags(x) ((x)=__global_save_flags()) #define restore_flags(x) __global_restore_flags(x) - +#define save_and_sti(x) do { save_flags(x); sti(); } while(0); #else #define cli() __cli() #define sti() __sti() #define save_flags(x) __save_flags(x) #define save_and_cli(x) x = __save_and_cli() +#define save_and_sti(x) __save_and_sti(x) #define restore_flags(x) __restore_flags(x) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc/elf.h linux.20pre2-ac1/include/asm-sparc/elf.h --- linux.20pre2/include/asm-sparc/elf.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc/elf.h 2002-08-06 15:41:52.000000000 +0100 @@ -41,7 +41,7 @@ dest[34] = src->npc; \ dest[35] = src->y; \ dest[36] = dest[37] = 0; /* XXX */ \ -} while(0); +} while(0) typedef struct { union { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc/ide.h linux.20pre2-ac1/include/asm-sparc/ide.h --- linux.20pre2/include/asm-sparc/ide.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -20,8 +20,6 @@ #undef MAX_HWIFS #define MAX_HWIFS 2 -#define ide__sti() __sti() - static __inline__ int ide_default_irq(ide_ioreg_t base) { return 0; @@ -73,29 +71,6 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ } -typedef union { - unsigned int all : 8; /* all of the bits together */ - struct { - unsigned int bit7 : 1; - unsigned int lba : 1; - unsigned int bit5 : 1; - unsigned int unit : 1; - unsigned int head : 4; - } b; -} select_t; - -typedef union { - unsigned int all : 8; /* all of the bits together */ - struct { - unsigned int HOB : 1; /* 48-bit address ordering */ - unsigned int reserved456: 3; - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned int SRST : 1; /* host soft reset bit */ - unsigned int nIEN : 1; /* device INTRQ to host */ - unsigned int bit0 : 1; - } b; -} control_t; - static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *name, void *devid) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc/ioctls.h linux.20pre2-ac1/include/asm-sparc/ioctls.h --- linux.20pre2/include/asm-sparc/ioctls.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc/ioctls.h 2002-08-06 15:41:52.000000000 +0100 @@ -86,6 +86,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it * someday. This is completely bogus, I know... diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc/rmap.h linux.20pre2-ac1/include/asm-sparc/rmap.h --- linux.20pre2/include/asm-sparc/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _SPARC_RMAP_H +#define _SPARC_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc/semaphore.h linux.20pre2-ac1/include/asm-sparc/semaphore.h --- linux.20pre2/include/asm-sparc/semaphore.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -213,6 +213,11 @@ : "g3", "g4", "g7", "memory", "cc"); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif /* __KERNEL__ */ #endif /* !(_SPARC_SEMAPHORE_H) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc/system.h linux.20pre2-ac1/include/asm-sparc/system.h --- linux.20pre2/include/asm-sparc/system.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -241,20 +241,21 @@ return retval; } +#define __save_and_sti(flags) do { __save_flags(flags); __sti(); } while(0); + #define __save_flags(flags) ((flags) = getipl()) #define __save_and_cli(flags) ((flags) = read_psr_and_cli()) #define __restore_flags(flags) setipl((flags)) #define local_irq_disable() __cli() #define local_irq_enable() __sti() #define local_irq_save(flags) __save_and_cli(flags) +#define local_irq_set(flags) __save_and_sti(flags) #define local_irq_restore(flags) __restore_flags(flags) #ifdef CONFIG_SMP extern unsigned char global_irq_holder; -#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0) - extern void __global_cli(void); extern void __global_sti(void); extern unsigned long __global_save_flags(void); @@ -263,6 +264,7 @@ #define sti() __global_sti() #define save_flags(flags) ((flags)=__global_save_flags()) #define restore_flags(flags) __global_restore_flags(flags) +#define save_and_sti(flags) do { save_flags(flags); sti(); } while(0); #else @@ -271,6 +273,7 @@ #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) #define save_and_cli(x) __save_and_cli(x) +#define save_and_sti(x) __save_and_sti(x) #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc64/ide.h linux.20pre2-ac1/include/asm-sparc64/ide.h --- linux.20pre2/include/asm-sparc64/ide.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc64/ide.h 2002-08-06 15:41:52.000000000 +0100 @@ -20,8 +20,6 @@ #undef MAX_HWIFS #define MAX_HWIFS 2 -#define ide__sti() __sti() - static __inline__ int ide_default_irq(ide_ioreg_t base) { return 0; @@ -69,29 +67,6 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ } -typedef union { - unsigned int all : 8; /* all of the bits together */ - struct { - unsigned int bit7 : 1; - unsigned int lba : 1; - unsigned int bit5 : 1; - unsigned int unit : 1; - unsigned int head : 4; - } b; -} select_t; - -typedef union { - unsigned int all : 8; /* all of the bits together */ - struct { - unsigned int HOB : 1; /* 48-bit address ordering */ - unsigned int reserved456: 3; - unsigned bit3 : 1; /* ATA-2 thingy */ - unsigned int SRST : 1; /* host soft reset bit */ - unsigned int nIEN : 1; /* device INTRQ to host */ - unsigned int bit0 : 1; - } b; -} control_t; - static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *name, void *devid) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc64/ioctls.h linux.20pre2-ac1/include/asm-sparc64/ioctls.h --- linux.20pre2/include/asm-sparc64/ioctls.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc64/ioctls.h 2002-08-06 15:41:52.000000000 +0100 @@ -87,6 +87,7 @@ #define FIONBIO _IOW('f', 126, int) #define FIONREAD _IOR('f', 127, int) #define TIOCINQ FIONREAD +#define FIOQSIZE _IOR('f', 128, loff_t) /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it * someday. This is completely bogus, I know... diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc64/rmap.h linux.20pre2-ac1/include/asm-sparc64/rmap.h --- linux.20pre2/include/asm-sparc64/rmap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc64/rmap.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _SPARC64_RMAP_H +#define _SPARC64_RMAP_H + +/* nothing to see, move along */ +#include + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc64/semaphore.h linux.20pre2-ac1/include/asm-sparc64/semaphore.h --- linux.20pre2/include/asm-sparc64/semaphore.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc64/semaphore.h 2002-08-06 15:41:52.000000000 +0100 @@ -226,6 +226,11 @@ : "g5", "g7", "memory", "cc"); } +static inline int sem_getcount(struct semaphore *sem) +{ + return atomic_read(&sem->count); +} + #endif /* __KERNEL__ */ #endif /* !(_SPARC64_SEMAPHORE_H) */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/asm-sparc64/system.h linux.20pre2-ac1/include/asm-sparc64/system.h --- linux.20pre2/include/asm-sparc64/system.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/asm-sparc64/system.h 2002-08-06 15:41:52.000000000 +0100 @@ -65,9 +65,13 @@ #define __save_flags(flags) ((flags) = getipl()) #define __save_and_cli(flags) ((flags) = read_pil_and_cli()) #define __restore_flags(flags) setipl((flags)) + +#define __save_and_sti(flags) ({ __save_flags(flags); __sti(); }) + #define local_irq_disable() __cli() #define local_irq_enable() __sti() #define local_irq_save(flags) __save_and_cli(flags) +#define local_irq_set(flags) __save_and_sti(flags) #define local_irq_restore(flags) __restore_flags(flags) #ifndef CONFIG_SMP @@ -76,6 +80,7 @@ #define save_flags(x) __save_flags(x) #define restore_flags(x) __restore_flags(x) #define save_and_cli(x) __save_and_cli(x) +#define save_and_sti(x) __save_and_sti(x) #else #ifndef __ASSEMBLY__ @@ -90,6 +95,7 @@ #define save_flags(x) ((x) = __global_save_flags()) #define restore_flags(flags) __global_restore_flags(flags) #define save_and_cli(flags) do { save_flags(flags); cli(); } while(0) +#define save_and_sti(flags) do { save_flags(flags); sti(); } while(0) #endif @@ -143,7 +149,11 @@ #define flush_user_windows flushw_user #define flush_register_windows flushw_all -#define prepare_to_switch flushw_all + +#define prepare_arch_schedule(prev) task_lock(prev) +#define finish_arch_schedule(prev) task_unlock(prev) +#define prepare_arch_switch(rq) do { spin_unlock(&(rq)->lock); flushw_all(); } +#define finish_arch_switch(rq) __sti() #ifndef CONFIG_DEBUG_SPINLOCK #define CHECK_LOCKS(PREV) do { } while(0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/acct.h linux.20pre2-ac1/include/linux/acct.h --- linux.20pre2/include/linux/acct.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/acct.h 2002-08-06 18:24:33.000000000 +0100 @@ -56,7 +56,9 @@ comp_t ac_swaps; /* Accounting Number of Swaps */ __u32 ac_exitcode; /* Accounting Exitcode */ char ac_comm[ACCT_COMM + 1]; /* Accounting Command Name */ - char ac_pad[10]; /* Accounting Padding Bytes */ + char ac_pad[2]; /* Accounting Padding Bytes */ + __u32 ac_uid32; /* 32 bit UID */ + __u32 ac_gid32; /* 32 bit GID */ }; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/binfmts.h linux.20pre2-ac1/include/linux/binfmts.h --- linux.20pre2/include/linux/binfmts.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/binfmts.h 2002-08-14 14:41:29.000000000 +0100 @@ -16,6 +16,8 @@ #ifdef __KERNEL__ +struct file; + /* * This structure is used to hold the arguments that are used when loading binaries. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/bitops.h linux.20pre2-ac1/include/linux/bitops.h --- linux.20pre2/include/linux/bitops.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/bitops.h 2002-08-06 18:24:33.000000000 +0100 @@ -1,6 +1,6 @@ #ifndef _LINUX_BITOPS_H #define _LINUX_BITOPS_H - +#include /* * ffs: find first bit set. This is defined the same way as @@ -38,6 +38,47 @@ } /* + * fls: find last bit set. + */ + +extern __inline__ int generic_fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000)) { + x <<= 1; + r -= 1; + } + return r; +} + +extern __inline__ int get_bitmask_order(unsigned int count) +{ + int order; + + order = fls(count); + return order; /* We could be slightly more clever with -1 here... */ +} + +/* * hweightN: returns the hamming weight (i.e. the number * of bits set) of a N-bit word */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/blkcdb.h linux.20pre2-ac1/include/linux/blkcdb.h --- linux.20pre2/include/linux/blkcdb.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/blkcdb.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,101 @@ +/* + * 2.5 Command Descriptor Block (CDB) Block Pre-Handler. + * + * Copyright (C) 2001 Andre Hedrick + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 Licens + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- + */ + +#ifndef _LINUX_BLKCDB_H +#define _LINUX_BLKCDB_H + +typedef struct cdb_list { +#if 0 + unsigned char cdb_0; + unsigned char cdb_1; + unsigned char cdb_2; + unsigned char cdb_3; + unsigned char cdb_4; + unsigned char cdb_5; + unsigned char cdb_6; + unsigned char cdb_7; + unsigned char cdb_8; + unsigned char cdb_9; + unsigned char cdb_10; + unsigned char cdb_11; + unsigned char cdb_12; + unsigned char cdb_13; + unsigned char cdb_14; + unsigned char cdb_15; +#else + unsigned char cdb_regs[16]; +#endif +} cdb_list_t; + +#if 0 + +typedef cdb_list_t * (queue_proc) (kdev_t dev); + +request_queue_t *ide_get_queue (kdev_t dev) +{ + ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data; + + return &hwif->drives[DEVICE_NR(dev) & 1].queue; +} + +static request_queue_t *sd_find_queue(kdev_t dev) +{ + Scsi_Disk *dpnt; + int target; + target = DEVICE_NR(dev); + + dpnt = &rscsi_disks[target]; + if (!dpnt) + return NULL; /* No such device */ + return &dpnt->device->request_queue; +} + +prebuilder: NULL, +block_device_operations +struct block_device { + +void do_ide_request(request_queue_t *q) + +ide_do_request + +typedef cdb_list_t (request_cdb_proc) (request_queue_t *q); + +typedef cdb_list_t (request_cdb_proc) (request_queue_t *q); +typedef void (request_fn_proc) (request_queue_t *q); + +srb + +switch (SCpnt->request.cmd) +SCpnt->cmnd[0] = WRITE_6/READ_6; +SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? + ((SCpnt->lun << 5) & 0xe0) : 0; +SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; +SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; +SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; +SCpnt->cmnd[5] = (unsigned char) block & 0xff; +SCpnt->cmnd[6] = 0; +SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff; +SCpnt->cmnd[8] = (unsigned char) this_count & 0xff; +SCpnt->cmnd[9] = 0; + +#endif + +#endif /* _LINUX_BLKCDB_H */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/blkdev.h linux.20pre2-ac1/include/linux/blkdev.h --- linux.20pre2/include/linux/blkdev.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/blkdev.h 2002-08-14 14:41:30.000000000 +0100 @@ -224,6 +224,8 @@ extern int * max_segments[MAX_BLKDEV]; +extern char * blkdev_varyio[MAX_BLKDEV]; + #define MAX_SEGMENTS 128 #define MAX_SECTORS 255 @@ -277,4 +279,12 @@ return retval; } +static inline int get_blkdev_varyio(int major, int minor) +{ + int retval = 0; + if (blkdev_varyio[major]) { + retval = blkdev_varyio[major][minor]; + } + return retval; +} #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/brlock.h linux.20pre2-ac1/include/linux/brlock.h --- linux.20pre2/include/linux/brlock.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/brlock.h 2002-08-13 22:28:55.000000000 +0100 @@ -28,13 +28,15 @@ * load-locked/store-conditional cpus (ALPHA/MIPS/PPC) and * compare-and-swap cpus (Sparc64). So we control which * implementation to use with a __BRLOCK_USE_ATOMICS define. -DaveM + * + * Added BR_LLC_LOCK for use in net/core/ext8022.c -acme */ /* Register bigreader lock indices here. */ enum brlock_indices { BR_GLOBALIRQ_LOCK, BR_NETPROTO_LOCK, - + BR_LLC_LOCK, __BR_END }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/console.h linux.20pre2-ac1/include/linux/console.h --- linux.20pre2/include/linux/console.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/console.h 2002-08-13 22:28:55.000000000 +0100 @@ -90,6 +90,7 @@ #define CON_PRINTBUFFER (1) #define CON_CONSDEV (2) /* Last on the command line */ #define CON_ENABLED (4) +#define CON_BOOT (8) /* Only used for initial boot */ struct console { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/cpufreq.h linux.20pre2-ac1/include/linux/cpufreq.h --- linux.20pre2/include/linux/cpufreq.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/cpufreq.h 2002-08-06 18:24:33.000000000 +0100 @@ -0,0 +1,81 @@ +/* + * linux/include/linux/cpufreq.h + * + * Copyright (C) 2001 Russell King + * (C) 2002 Dominik Brodowski + * + * + * $Id: cpufreq.h,v 1.9 2002/06/26 15:33:29 db Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _LINUX_CPUFREQ_H +#define _LINUX_CPUFREQ_H + +#include +#include + + +/* speed setting interface */ + +int cpufreq_setmax(void); +int cpufreq_set(unsigned int khz); +unsigned int cpufreq_get(void); + +#ifdef CONFIG_PM +int cpufreq_restore(void); +#endif + + +/* notifier interface */ + +/* + * The max and min frequency rates that the registered device + * can tolerate. Never set any element this structure directly - + * always use cpufreq_updateminmax. + */ +struct cpufreq_freqs { + unsigned int min; + unsigned int max; + unsigned int cur; + unsigned int new; +}; + +static inline +void cpufreq_updateminmax(struct cpufreq_freqs *freq, + unsigned int min, + unsigned int max) +{ + if (freq->min < min) + freq->min = min; + if (freq->max > max) + freq->max = max; +} + +#define CPUFREQ_MINMAX (0) +#define CPUFREQ_PRECHANGE (1) +#define CPUFREQ_POSTCHANGE (2) + +int cpufreq_register_notifier(struct notifier_block *nb); +int cpufreq_unregister_notifier(struct notifier_block *nb); + + + +/* cpufreq driver interface */ + +typedef unsigned int (*cpufreq_verify_t) (unsigned int kHz); +typedef void (*cpufreq_setspeed_t) (unsigned int kHz); + +struct cpufreq_driver { + struct cpufreq_freqs freq; + cpufreq_verify_t validate; + cpufreq_setspeed_t setspeed; + unsigned int initialised; +}; + +int cpufreq_register(struct cpufreq_driver driver_data); +int cpufreq_unregister(void); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/dcache.h linux.20pre2-ac1/include/linux/dcache.h --- linux.20pre2/include/linux/dcache.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/dcache.h 2002-08-13 22:28:54.000000000 +0100 @@ -62,7 +62,8 @@ return end_name_hash(hash); } -#define DNAME_INLINE_LEN 16 +/* XXX: check good value for 64bit */ +#define DNAME_INLINE_LEN 32 struct dentry { atomic_t d_count; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/device-mapper.h linux.20pre2-ac1/include/linux/device-mapper.h --- linux.20pre2/include/linux/device-mapper.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/device-mapper.h 2002-08-12 22:46:07.000000000 +0100 @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#ifndef _LINUX_DEVICE_MAPPER_H +#define _LINUX_DEVICE_MAPPER_H + +#define DM_DIR "mapper" /* Slashes not supported */ +#define DM_MAX_TYPE_NAME 16 +#define DM_NAME_LEN 128 +#define DM_UUID_LEN 129 + +#ifdef __KERNEL__ + +struct dm_table; +struct dm_dev; +typedef unsigned long offset_t; + +typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t; + +/* + * Prototypes for functions for a target + */ +typedef int (*dm_ctr_fn) (struct dm_table *t, offset_t b, offset_t l, + int argc, char **argv, void **context); +typedef void (*dm_dtr_fn) (struct dm_table *t, void *c); +typedef int (*dm_map_fn) (struct buffer_head *bh, int rw, void *context); +typedef int (*dm_err_fn) (struct buffer_head *bh, int rw, void *context); +typedef int (*dm_status_fn) (status_type_t status_type, char *result, + int maxlen, void *context); + +void dm_error(const char *message); + +/* + * Constructors should call these functions to ensure destination devices + * are opened/closed correctly + */ +int dm_table_get_device(struct dm_table *t, const char *path, + offset_t start, offset_t len, + int mode, struct dm_dev **result); +void dm_table_put_device(struct dm_table *table, struct dm_dev *d); + +/* + * Information about a target type + */ +struct target_type { + const char *name; + struct module *module; + dm_ctr_fn ctr; + dm_dtr_fn dtr; + dm_map_fn map; + dm_err_fn err; + dm_status_fn status; +}; + +int dm_register_target(struct target_type *t); +int dm_unregister_target(struct target_type *t); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_DEVICE_MAPPER_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/dm-ioctl.h linux.20pre2-ac1/include/linux/dm-ioctl.h --- linux.20pre2/include/linux/dm-ioctl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/dm-ioctl.h 2002-08-12 22:46:13.000000000 +0100 @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2001 Sistina Software (UK) Limited. + * + * This file is released under the LGPL. + */ + +#ifndef _LINUX_DM_IOCTL_H +#define _LINUX_DM_IOCTL_H + +#include "device-mapper.h" +#include "types.h" + +/* + * Implements a traditional ioctl interface to the device mapper. + */ + +/* + * All ioctl arguments consist of a single chunk of memory, with + * this structure at the start. If a uuid is specified any + * lookup (eg. for a DM_INFO) will be done on that, *not* the + * name. + */ +struct dm_ioctl { + /* + * The version number is made up of three parts: + * major - no backward or forward compatibility, + * minor - only backwards compatible, + * patch - both backwards and forwards compatible. + * + * All clients of the ioctl interface should fill in the + * version number of the interface that they were + * compiled with. + * + * All recognised ioctl commands (ie. those that don't + * return -ENOTTY) fill out this field, even if the + * command failed. + */ + uint32_t version[3]; /* in/out */ + uint32_t data_size; /* total size of data passed in + * including this struct */ + + uint32_t data_start; /* offset to start of data + * relative to start of this struct */ + + uint32_t target_count; /* in/out */ + uint32_t open_count; /* out */ + uint32_t flags; /* in/out */ + + __kernel_dev_t dev; /* in/out */ + + char name[DM_NAME_LEN]; /* device name */ + char uuid[DM_UUID_LEN]; /* unique identifier for + * the block device */ +}; + +/* + * Used to specify tables. These structures appear after the + * dm_ioctl. + */ +struct dm_target_spec { + int32_t status; /* used when reading from kernel only */ + uint64_t sector_start; + uint32_t length; + + /* + * Offset in bytes (from the start of this struct) to + * next target_spec. + */ + uint32_t next; + + char target_type[DM_MAX_TYPE_NAME]; + + /* + * Parameter string starts immediately after this object. + * Be careful to add padding after string to ensure correct + * alignment of subsequent dm_target_spec. + */ +}; + +/* + * Used to retrieve the target dependencies. + */ +struct dm_target_deps { + uint32_t count; + + __kernel_dev_t dev[0]; /* out */ +}; + +/* + * If you change this make sure you make the corresponding change + * to dm-ioctl.c:lookup_ioctl() + */ +enum { + /* Top level cmds */ + DM_VERSION_CMD = 0, + DM_REMOVE_ALL_CMD, + + /* device level cmds */ + DM_DEV_CREATE_CMD, + DM_DEV_REMOVE_CMD, + DM_DEV_RELOAD_CMD, + DM_DEV_RENAME_CMD, + DM_DEV_SUSPEND_CMD, + DM_DEV_DEPS_CMD, + DM_DEV_STATUS_CMD, + + /* target level cmds */ + DM_TARGET_STATUS_CMD, + DM_TARGET_WAIT_CMD +}; + +#define DM_IOCTL 0xfd + +#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl) +#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl) + +#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl) +#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl) +#define DM_DEV_RELOAD _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl) +#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl) +#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl) +#define DM_DEV_DEPS _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl) +#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl) + +#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl) +#define DM_TARGET_WAIT _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl) + +#define DM_VERSION_MAJOR 1 +#define DM_VERSION_MINOR 0 +#define DM_VERSION_PATCHLEVEL 3 +#define DM_VERSION_EXTRA "-ioctl-bk (2002-08-5)" + +/* Status bits */ +#define DM_READONLY_FLAG 0x00000001 +#define DM_SUSPEND_FLAG 0x00000002 +#define DM_EXISTS_FLAG 0x00000004 +#define DM_PERSISTENT_DEV_FLAG 0x00000008 + +/* + * Flag passed into ioctl STATUS command to get table information + * rather than current status. + */ +#define DM_STATUS_TABLE_FLAG 0x00000010 + +#endif /* _LINUX_DM_IOCTL_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/dqblk_v1.h linux.20pre2-ac1/include/linux/dqblk_v1.h --- linux.20pre2/include/linux/dqblk_v1.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/dqblk_v1.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,18 @@ +/* + * File with in-memory structures of old quota format + */ + +#ifndef _LINUX_DQBLK_V1_H +#define _LINUX_DQBLK_V1_H + +/* Id of quota format */ +#define QFMT_VFS_OLD 1 + +/* Root squash turned on */ +#define V1_DQF_RSQUASH 1 + +/* Special information about quotafile */ +struct v1_mem_dqinfo { +}; + +#endif /* _LINUX_DQBLK_V1_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/dqblk_v2.h linux.20pre2-ac1/include/linux/dqblk_v2.h --- linux.20pre2/include/linux/dqblk_v2.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/dqblk_v2.h 2002-08-06 18:24:33.000000000 +0100 @@ -0,0 +1,20 @@ +/* + * Definitions of structures for vfsv0 quota format + */ + +#ifndef _LINUX_DQBLK_V2_H +#define _LINUX_DQBLK_V2_H + +#include + +/* id numbers of quota format */ +#define QFMT_VFS_V0 2 + +/* Inmemory copy of version specific information */ +struct v2_mem_dqinfo { + unsigned int dqi_blocks; + unsigned int dqi_free_blk; + unsigned int dqi_free_entry; +}; + +#endif /* _LINUX_DQBLK_V2_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/dqblk_xfs.h linux.20pre2-ac1/include/linux/dqblk_xfs.h --- linux.20pre2/include/linux/dqblk_xfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/dqblk_xfs.h 2002-08-06 18:24:33.000000000 +0100 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + * USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _LINUX_DQBLK_XFS_H +#define _LINUX_DQBLK_XFS_H + +#include + +/* + * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM). + */ + +#define XQM_CMD(x) (('X'<<8)+(x)) /* note: forms first QCMD argument */ +#define Q_XQUOTAON XQM_CMD(0x1) /* enable accounting/enforcement */ +#define Q_XQUOTAOFF XQM_CMD(0x2) /* disable accounting/enforcement */ +#define Q_XGETQUOTA XQM_CMD(0x3) /* get disk limits and usage */ +#define Q_XSETQLIM XQM_CMD(0x4) /* set disk limits */ +#define Q_XGETQSTAT XQM_CMD(0x5) /* get quota subsystem status */ +#define Q_XQUOTARM XQM_CMD(0x6) /* free disk space used by dquots */ + +/* + * fs_disk_quota structure: + * + * This contains the current quota information regarding a user/proj/group. + * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of + * 512 bytes. + */ +#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ +typedef struct fs_disk_quota { + __s8 d_version; /* version of this structure */ + __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ + __u16 d_fieldmask; /* field specifier */ + __u32 d_id; /* user, project, or group ID */ + __u64 d_blk_hardlimit;/* absolute limit on disk blks */ + __u64 d_blk_softlimit;/* preferred limit on disk blks */ + __u64 d_ino_hardlimit;/* maximum # allocated inodes */ + __u64 d_ino_softlimit;/* preferred inode limit */ + __u64 d_bcount; /* # disk blocks owned by the user */ + __u64 d_icount; /* # inodes owned by the user */ + __s32 d_itimer; /* zero if within inode limits */ + /* if not, we refuse service */ + __s32 d_btimer; /* similar to above; for disk blocks */ + __u16 d_iwarns; /* # warnings issued wrt num inodes */ + __u16 d_bwarns; /* # warnings issued wrt disk blocks */ + __s32 d_padding2; /* padding2 - for future use */ + __u64 d_rtb_hardlimit;/* absolute limit on realtime blks */ + __u64 d_rtb_softlimit;/* preferred limit on RT disk blks */ + __u64 d_rtbcount; /* # realtime blocks owned */ + __s32 d_rtbtimer; /* similar to above; for RT disk blks */ + __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ + __s16 d_padding3; /* padding3 - for future use */ + char d_padding4[8]; /* yet more padding */ +} fs_disk_quota_t; + +/* + * These fields are sent to Q_XSETQLIM to specify fields that need to change. + */ +#define FS_DQ_ISOFT (1<<0) +#define FS_DQ_IHARD (1<<1) +#define FS_DQ_BSOFT (1<<2) +#define FS_DQ_BHARD (1<<3) +#define FS_DQ_RTBSOFT (1<<4) +#define FS_DQ_RTBHARD (1<<5) +#define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ + FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) +/* + * These timers can only be set in super user's dquot. For others, timers are + * automatically started and stopped. Superusers timer values set the limits + * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values + * defined below are used. + * These values also apply only to the d_fieldmask field for Q_XSETQLIM. + */ +#define FS_DQ_BTIMER (1<<6) +#define FS_DQ_ITIMER (1<<7) +#define FS_DQ_RTBTIMER (1<<8) +#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) + +/* + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). These may be modified by the quotactl(2) + * system call with the Q_XSETQLIM command. + */ +#define DQ_FTIMELIMIT (7 * 24*60*60) /* 1 week */ +#define DQ_BTIMELIMIT (7 * 24*60*60) /* 1 week */ + +/* + * Various flags related to quotactl(2). Only relevant to XFS filesystems. + */ +#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ +#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ +#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ +#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ + +#define XFS_USER_QUOTA (1<<0) /* user quota type */ +#define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */ +#define XFS_GROUP_QUOTA (1<<2) /* group quota type */ + +/* + * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. + * Provides a centralized way to get meta infomation about the quota subsystem. + * eg. space taken up for user and group quotas, number of dquots currently + * incore. + */ +#define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ + +/* + * Some basic infomation about 'quota files'. + */ +typedef struct fs_qfilestat { + __u64 qfs_ino; /* inode number */ + __u64 qfs_nblks; /* number of BBs 512-byte-blks */ + __u32 qfs_nextents; /* number of extents */ +} fs_qfilestat_t; + +typedef struct fs_quota_stat { + __s8 qs_version; /* version number for future changes */ + __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ + __s8 qs_pad; /* unused */ + fs_qfilestat_t qs_uquota; /* user quota storage information */ + fs_qfilestat_t qs_gquota; /* group quota storage information */ + __u32 qs_incoredqs; /* number of dquots incore */ + __s32 qs_btimelimit; /* limit for blks timer */ + __s32 qs_itimelimit; /* limit for inodes timer */ + __s32 qs_rtbtimelimit;/* limit for rt blks timer */ + __u16 qs_bwarnlimit; /* limit for num warnings */ + __u16 qs_iwarnlimit; /* limit for num warnings */ +} fs_quota_stat_t; + +#endif /* _LINUX_DQBLK_XFS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/ext2_fs_sb.h linux.20pre2-ac1/include/linux/ext2_fs_sb.h --- linux.20pre2/include/linux/ext2_fs_sb.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/ext2_fs_sb.h 2002-08-06 15:41:52.000000000 +0100 @@ -22,7 +22,7 @@ */ /* #define EXT2_MAX_GROUP_DESC 8 */ -#define EXT2_MAX_GROUP_LOADED 8 +#define EXT2_MAX_GROUP_LOADED 32 /* * second extended-fs super-block data in memory diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/ext3_fs.h linux.20pre2-ac1/include/linux/ext3_fs.h --- linux.20pre2/include/linux/ext3_fs.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/ext3_fs.h 2002-08-06 18:24:34.000000000 +0100 @@ -36,8 +36,8 @@ /* * The second extended file system version */ -#define EXT3FS_DATE "10 Jan 2002" -#define EXT3FS_VERSION "2.4-0.9.17" +#define EXT3FS_DATE "14 May 2002" +#define EXT3FS_VERSION "2.4-0.9.18" /* * Debug code diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/ext3_fs_sb.h linux.20pre2-ac1/include/linux/ext3_fs_sb.h --- linux.20pre2/include/linux/ext3_fs_sb.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/ext3_fs_sb.h 2002-08-14 14:41:29.000000000 +0100 @@ -27,7 +27,7 @@ */ /* #define EXT3_MAX_GROUP_DESC 8 */ -#define EXT3_MAX_GROUP_LOADED 8 +#define EXT3_MAX_GROUP_LOADED 32 /* * third extended-fs super-block data in memory diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/fs.h linux.20pre2-ac1/include/linux/fs.h --- linux.20pre2/include/linux/fs.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/fs.h 2002-08-14 14:41:29.000000000 +0100 @@ -206,6 +206,7 @@ extern void buffer_init(unsigned long); extern void inode_init(unsigned long); extern void mnt_init(unsigned long); +extern void files_init(unsigned long); /* bh state bits */ enum bh_state_bits { @@ -219,6 +220,7 @@ BH_Wait_IO, /* 1 if we should write out this buffer */ BH_Launder, /* 1 if we can throttle on this buffer */ BH_JBD, /* 1 if it has an attached journal_head */ + BH_Inode, /* 1 if it is attached to i_dirty[_data]_buffers */ BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities @@ -261,11 +263,10 @@ struct page *b_page; /* the page this bh is mapped to */ void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */ void *b_private; /* reserved for b_end_io */ - + void *b_journal_head; /* ext3 journal_heads */ unsigned long b_rsector; /* Real buffer location on disk */ wait_queue_head_t b_wait; - struct inode * b_inode; struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */ }; @@ -395,6 +396,7 @@ int (*releasepage) (struct page *, int); #define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */ int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int); + void (*removepage)(struct page *); /* called when page gets removed from the inode */ }; struct address_space { @@ -453,6 +455,7 @@ unsigned long i_blksize; unsigned long i_blocks; unsigned long i_version; + unsigned short i_bytes; struct semaphore i_sem; struct semaphore i_zombie; struct inode_operations *i_op; @@ -513,6 +516,39 @@ } u; }; +static inline void inode_add_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks += bytes >> 9; + bytes &= 511; + inode->i_bytes += bytes; + if (inode->i_bytes >= 512) { + inode->i_blocks++; + inode->i_bytes -= 512; + } +} + +static inline void inode_sub_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks -= bytes >> 9; + bytes &= 511; + if (inode->i_bytes < bytes) { + inode->i_blocks--; + inode->i_bytes += 512; + } + inode->i_bytes -= bytes; +} + +static inline loff_t inode_get_bytes(struct inode *inode) +{ + return (((loff_t)inode->i_blocks) << 9) + inode->i_bytes; +} + +static inline void inode_set_bytes(struct inode *inode, loff_t bytes) +{ + inode->i_blocks = bytes >> 9; + inode->i_bytes = bytes & 511; +} + struct fown_struct { int pid; /* pid or -pgrp where SIGIO should be sent */ uid_t uid, euid; /* uid/euid of process setting the owner */ @@ -595,6 +631,7 @@ void (*fl_remove)(struct file_lock *); /* lock removal callback */ struct fasync_struct * fl_fasync; /* for lease break notifications */ + unsigned long fl_break_time; /* for nonblocking lease breaks */ union { struct nfs_lock_info nfs_fl; @@ -657,20 +694,6 @@ int last_type; }; -#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ -#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ - -struct quota_mount_options -{ - unsigned int flags; /* Flags for diskquotas on this device */ - struct semaphore dqio_sem; /* lock device while I/O in progress */ - struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */ - struct file *files[MAXQUOTAS]; /* fp's to quotafiles */ - time_t inode_expire[MAXQUOTAS]; /* expiretime for inode-quota */ - time_t block_expire[MAXQUOTAS]; /* expiretime for block-quota */ - char rsquash[MAXQUOTAS]; /* for quotas threat root as any other user */ -}; - /* * Umount options */ @@ -718,6 +741,7 @@ struct file_system_type *s_type; struct super_operations *s_op; struct dquot_operations *dq_op; + struct quotactl_ops *s_qcop; unsigned long s_flags; unsigned long s_magic; struct dentry *s_root; @@ -732,7 +756,7 @@ struct block_device *s_bdev; struct list_head s_instances; - struct quota_mount_options s_dquot; /* Diskquota specific options */ + struct quota_info s_dquot; /* Diskquota specific options */ union { struct minix_sb_info minix_sb; @@ -948,16 +972,6 @@ __mark_inode_dirty(inode, I_DIRTY_PAGES); } -struct dquot_operations { - void (*initialize) (struct inode *, short); - void (*drop) (struct inode *); - int (*alloc_block) (struct inode *, unsigned long, char); - int (*alloc_inode) (const struct inode *, unsigned long); - void (*free_block) (struct inode *, unsigned long); - void (*free_inode) (const struct inode *, unsigned long); - int (*transfer) (struct inode *, struct iattr *); -}; - struct file_system_type { const char *name; int fs_flags; @@ -1051,7 +1065,7 @@ static inline int get_lease(struct inode *inode, unsigned int mode) { - if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE)) + if (inode->i_flock) return __get_lease(inode, mode); return 0; } @@ -1181,6 +1195,21 @@ clear_bit(BH_Async, &bh->b_state); } +static inline void set_buffer_inode(struct buffer_head *bh) +{ + set_bit(BH_Inode, &bh->b_state); +} + +static inline void clear_buffer_inode(struct buffer_head *bh) +{ + clear_bit(BH_Inode, &bh->b_state); +} + +static inline int buffer_inode(struct buffer_head *bh) +{ + return test_bit(BH_Inode, &bh->b_state); +} + /* * If an error happens during the make_request, this function * has to be recalled. It marks the buffer as clean and not @@ -1327,6 +1356,7 @@ extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *)); extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *)); extern int FASTCALL(path_walk(const char *, struct nameidata *)); +extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *)); extern int FASTCALL(link_path_walk(const char *, struct nameidata *)); extern void path_release(struct nameidata *); extern int follow_down(struct vfsmount **, struct dentry **); @@ -1371,6 +1401,7 @@ extern struct buffer_head * getblk(kdev_t, int, int); extern void ll_rw_block(int, int, struct buffer_head * bh[]); extern void submit_bh(int, struct buffer_head *); +extern void submit_bh_blknr(int, struct buffer_head *); extern int is_read_only(kdev_t); extern void __brelse(struct buffer_head *); static inline void brelse(struct buffer_head *buf) @@ -1468,8 +1499,6 @@ } return 0; } -unsigned long generate_cluster(kdev_t, int b[], int); -unsigned long generate_cluster_swab32(kdev_t, int b[], int); extern kdev_t ROOT_DEV; extern char root_device_name[]; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/hdreg.h linux.20pre2-ac1/include/linux/hdreg.h --- linux.20pre2/include/linux/hdreg.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/hdreg.h 2002-08-06 18:24:33.000000000 +0100 @@ -131,8 +131,8 @@ */ #define IDE_TASKFILE_STD_OUT_FLAGS 0xFE #define IDE_TASKFILE_STD_IN_FLAGS 0xFE -#define IDE_HOB_STD_OUT_FLAGS 0xC0 -#define IDE_HOB_STD_IN_FLAGS 0xC0 +#define IDE_HOB_STD_OUT_FLAGS 0x3C /* sector, nsector lcyl and hcyl */ +#define IDE_HOB_STD_IN_FLAGS 0x3C typedef struct ide_task_request_s { task_ioreg_t io_ports[8]; @@ -177,29 +177,67 @@ /* ATA/ATAPI Commands pre T13 Spec */ #define WIN_NOP 0x00 +/* + * 0x01->0x02 Reserved + */ #define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ +/* + * 0x04->0x07 Reserved + */ #define WIN_SRST 0x08 /* ATAPI soft reset command */ #define WIN_DEVICE_RESET 0x08 -#define WIN_RESTORE 0x10 +/* + * 0x09->0x0F Reserved + */ +#define WIN_RECAL 0x10 +/* + * 0x10->0x1F Reserved + */ +#define WIN_RESTORE WIN_RECAL #define WIN_READ 0x20 /* 28-Bit */ +#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */ +#define WIN_READ_LONG 0x22 /* 28-Bit */ +#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */ #define WIN_READ_EXT 0x24 /* 48-Bit */ #define WIN_READDMA_EXT 0x25 /* 48-Bit */ #define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ #define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ #define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ +/* + * 0x2A->0x2F Reserved + */ #define WIN_WRITE 0x30 /* 28-Bit */ +#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */ +#define WIN_WRITE_LONG 0x32 /* 28-Bit */ +#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */ #define WIN_WRITE_EXT 0x34 /* 48-Bit */ #define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ #define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ #define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ #define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ #define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ +/* + * 0x3A->0x3B Reserved + */ #define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ +/* + * 0x3D->0x3F Reserved + */ #define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ +#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */ #define WIN_VERIFY_EXT 0x42 /* 48-Bit */ +/* + * 0x43->0x4F Reserved + */ #define WIN_FORMAT 0x50 +/* + * 0x51->0x5F Reserved + */ #define WIN_INIT 0x60 -#define WIN_SEEK 0x70 +/* + * 0x61->0x5F Reserved + */ +#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */ #define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ #define WIN_DIAGNOSE 0x90 #define WIN_SPECIFY 0x91 /* set drive geometry translation */ @@ -208,6 +246,9 @@ #define WIN_SETIDLE2 0x97 #define WIN_CHECKPOWERMODE2 0x98 #define WIN_SLEEPNOW2 0x99 +/* + * 0x9A VENDOR + */ #define WIN_PACKETCMD 0xA0 /* Send a packet command. */ #define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ #define WIN_QUEUED_SERVICE 0xA2 @@ -218,7 +259,9 @@ #define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ #define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ #define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ +#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */ #define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ +#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ #define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ #define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ #define WIN_GETMEDIASTATUS 0xDA @@ -233,6 +276,7 @@ #define WIN_SLEEPNOW1 0xE6 #define WIN_FLUSH_CACHE 0xE7 #define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ +#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */ #define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ #define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ #define WIN_MEDIAEJECT 0xED @@ -270,7 +314,7 @@ #define SMART_HCYL_PASS 0xC2 /* WIN_SETFEATURES sub-commands */ - +#define SETFEATURES_EN_8BIT 0x01 /* Enable 8-Bit Transfers */ #define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */ #define SETFEATURES_XFER 0x03 /* Set transfer mode */ # define XFER_UDMA_7 0x47 /* 0100|0111 */ @@ -296,17 +340,25 @@ #define SETFEATURES_DIS_DEFECT 0x04 /* Disable Defect Management */ #define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */ #define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */ +#define SETFEATURES_DIS_RETRY 0x33 /* Disable Retry */ #define SETFEATURES_EN_AAM 0x42 /* Enable Automatic Acoustic Management */ +#define SETFEATURES_RW_LONG 0x44 /* Set Lenght of VS bytes */ +#define SETFEATURES_SET_CACHE 0x54 /* Set Cache segments to SC Reg. Val */ #define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */ #define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */ #define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */ #define SETFEATURES_DIS_RPOD 0x66 /* Disable reverting to power on defaults */ +#define SETFEATURES_DIS_ECC 0x77 /* Disable ECC byte count */ +#define SETFEATURES_DIS_8BIT 0x81 /* Disable 8-Bit Transfers */ #define SETFEATURES_DIS_WCACHE 0x82 /* Disable write cache */ #define SETFEATURES_EN_DEFECT 0x84 /* Enable Defect Management */ #define SETFEATURES_DIS_APM 0x85 /* Disable advanced power management */ +#define SETFEATURES_EN_ECC 0x88 /* Enable ECC byte count */ #define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */ +#define SETFEATURES_EN_RETRY 0x99 /* Enable Retry */ #define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */ #define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */ +#define SETFEATURES_4B_RW_LONG 0xBB /* Set Lenght of 4 bytes */ #define SETFEATURES_DIS_AAM 0xC2 /* Disable Automatic Acoustic Management */ #define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */ #define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt */ @@ -501,7 +553,10 @@ * cmd set-feature supported extensions * 15: Shall be ZERO * 14: Shall be ONE - * 13:3 reserved + * 13:6 reserved + * 5: General Purpose Logging + * 4: Streaming Feature Set + * 3: Media Card Pass Through * 2: Media Serial Number Valid * 1: SMART selt-test supported * 0: SMART error logging @@ -548,19 +603,22 @@ * command set-feature default * 15: Shall be ZERO * 14: Shall be ONE - * 13:3 reserved + * 13:6 reserved + * 5: General Purpose Logging enabled + * 4: Valid CONFIGURE STREAM executed + * 3: Media Card Pass Through enabled * 2: Media Serial Number Valid * 1: SMART selt-test supported * 0: SMART error logging */ unsigned short dma_ultra; /* (word 88) */ - unsigned short word89; /* reserved (word 89) */ - unsigned short word90; /* reserved (word 90) */ + unsigned short trseuc; /* time required for security erase */ + unsigned short trsEuc; /* time required for enhanced erase */ unsigned short CurAPMvalues; /* current APM values */ - unsigned short word92; /* reserved (word 92) */ + unsigned short mprc; /* master password revision code */ unsigned short hw_config; /* hardware config (word 93) - * 15: - * 14: + * 15: Shall be ZERO + * 14: Shall be ONE * 13: * 12: * 11: @@ -574,18 +632,17 @@ * 3: * 2: * 1: - * 0: + * 0: Shall be ONE */ unsigned short acoustic; /* (word 94) * 15:8 Vendor's recommended value * 7:0 current value */ - unsigned short words95_99[5]; /* reserved words 95-99 */ -#if 0 - unsigned short words100_103[4] ;/* reserved words 100-103 */ -#else + unsigned short msrqs; /* min stream request size */ + unsigned short sxfert; /* stream transfer time */ + unsigned short sal; /* stream access latency */ + unsigned int spg; /* stream performance granularity */ unsigned long long lba_capacity_2;/* 48-bit total number of sectors */ -#endif unsigned short words104_125[22];/* reserved words 104-125 */ unsigned short last_lun; /* (word 126) */ unsigned short word127; /* (word 127) Feature Set diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/ide.h linux.20pre2-ac1/include/linux/ide.h --- linux.20pre2/include/linux/ide.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/ide.h 2002-08-14 14:41:30.000000000 +0100 @@ -14,7 +14,16 @@ #include #include #include +#include +#include #include +#include + +#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT +# define __IDEDMA_TIMEOUT +#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ +# undef __IDEDMA_TIMEOUT +#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */ /* * This is the multiple IDE interface driver, as evolved from hd.c. @@ -306,23 +315,23 @@ */ #ifndef HAVE_ARCH_OUT_BYTE -#ifdef REALLY_FAST_IO -#define OUT_BYTE(b,p) outb((b),(p)) -#define OUT_WORD(w,p) outw((w),(p)) -#else -#define OUT_BYTE(b,p) outb_p((b),(p)) -#define OUT_WORD(w,p) outw_p((w),(p)) -#endif +# ifdef REALLY_FAST_IO +# define OUT_BYTE(b,p) outb((b),(p)) +# define OUT_WORD(w,p) outw((w),(p)) +# else +# define OUT_BYTE(b,p) outb_p((b),(p)) +# define OUT_WORD(w,p) outw_p((w),(p)) +# endif #endif #ifndef HAVE_ARCH_IN_BYTE -#ifdef REALLY_FAST_IO -#define IN_BYTE(p) (byte)inb(p) -#define IN_WORD(p) (short)inw(p) -#else -#define IN_BYTE(p) (byte)inb_p(p) -#define IN_WORD(p) (short)inw_p(p) -#endif +# ifdef REALLY_FAST_IO +# define IN_BYTE(p) (byte)inb(p) +# define IN_WORD(p) (short)inw(p) +# else +# define IN_BYTE(p) (byte)inb_p(p) +# define IN_WORD(p) (short)inw_p(p) +# endif #endif /* @@ -339,14 +348,74 @@ typedef union { unsigned all : 8; /* all of the bits together */ struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned set_geometry : 1; /* respecify drive geometry */ unsigned recalibrate : 1; /* seek to cyl 0 */ unsigned set_multmode : 1; /* set multmode count */ unsigned set_tune : 1; /* tune interface for drive */ - unsigned reserved : 4; /* unused */ + unsigned serviced : 1; /* service command */ + unsigned reserved : 3; /* unused */ +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned reserved : 3; /* unused */ + unsigned serviced : 1; /* service command */ + unsigned set_tune : 1; /* tune interface for drive */ + unsigned set_multmode : 1; /* set multmode count */ + unsigned recalibrate : 1; /* seek to cyl 0 */ + unsigned set_geometry : 1; /* respecify drive geometry */ +#else +#error "Please fix " +#endif } b; } special_t; +typedef union { + unsigned all : 8; /* all of the bits together */ + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned head : 4; /* always zeros here */ + unsigned unit : 1; /* drive select number: 0/1 */ + unsigned bit5 : 1; /* always 1 */ + unsigned lba : 1; /* using LBA instead of CHS */ + unsigned bit7 : 1; /* always 1 */ +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned bit7 : 1; /* always 1 */ + unsigned lba : 1; /* using LBA instead of CHS */ + unsigned bit5 : 1; /* always 1 */ + unsigned unit : 1; /* drive select number: 0/1 */ + unsigned head : 4; /* always zeros here */ +#else +#error "Please fix " +#endif + } b; +} select_t; + +typedef union { + unsigned all : 8; /* all of the bits together */ + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned bit0 : 1; + unsigned nIEN : 1; /* device INTRQ to host */ + unsigned SRST : 1; /* host soft reset bit */ + unsigned bit3 : 1; /* ATA-2 thingy */ + unsigned reserved456 : 3; + unsigned HOB : 1; /* 48-bit address ordering */ +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned HOB : 1; /* 48-bit address ordering */ + unsigned reserved456 : 3; + unsigned bit3 : 1; /* ATA-2 thingy */ + unsigned SRST : 1; /* host soft reset bit */ + unsigned nIEN : 1; /* device INTRQ to host */ + unsigned bit0 : 1; +#else +#error "Please fix " +#endif + } b; +} control_t; + + +struct ide_driver_s; +struct ide_settings_s; + typedef struct ide_drive_s { request_queue_t queue; /* request queue */ struct ide_drive_s *next; /* circular list of hwgroup drives */ @@ -381,7 +450,12 @@ unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */ unsigned ata_flash : 1; /* 1=present, 0=default */ - unsigned addressing; /* : 2; 0=28-bit, 1=48-bit, 2=64-bit */ + unsigned addressing; /* : 3; + * 0=28-bit + * 1=48-bit + * 2=48-bit doing 28-bit + * 3=64-bit + */ byte scsi; /* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */ byte media; /* disk, cdrom, tape, floppy, ... */ select_t select; /* basic drive/head select reg value */ @@ -404,16 +478,16 @@ unsigned long capacity; /* total number of sectors */ unsigned long long capacity48; /* total number of sectors */ unsigned int drive_data; /* for use by tuneproc/selectproc as needed */ - void *hwif; /* actually (ide_hwif_t *) */ + struct hwif_s *hwif; /* actually (ide_hwif_t *) */ wait_queue_head_t wqueue; /* used to wait for drive in open() */ struct hd_driveid *id; /* drive model identification info */ struct hd_struct *part; /* drive partition table */ char name[4]; /* drive name, such as "hda" */ - void *driver; /* (ide_driver_t *) */ + struct ide_driver_s *driver; /* (ide_driver_t *) */ void *driver_data; /* extra driver data */ devfs_handle_t de; /* directory for device */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ - void *settings; /* /proc/ide/ drive settings */ + struct ide_settings_s *settings; /* /proc/ide/ drive settings */ char driver_req[10]; /* requests specific driver */ int last_lun; /* last logical unit */ int forced_lun; /* if hdxlun was given at boot */ @@ -444,6 +518,7 @@ typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, ide_dma_end, ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly, ide_dma_test_irq, + ide_dma_host_on, ide_dma_host_off, ide_dma_bad_drive, ide_dma_good_drive, ide_dma_verbose, ide_dma_retune, ide_dma_lostirq, ide_dma_timeout @@ -469,6 +544,81 @@ typedef void (ide_ideproc_t)(ide_ide_action_t, ide_drive_t *, void *, unsigned int); /* + * mapping stuff, prepare for highmem... + * + * temporarily mapping a (possible) highmem bio for PIO transfer + */ +#define ide_rq_offset(rq) \ + (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9) + +extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags) +{ + return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq); +} + +extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags) +{ + bh_kunmap_irq(buffer, flags); +} + +/* + * A Verbose noise maker for debugging on the attempted transfer rates. + */ +extern inline char *ide_xfer_verbose (byte xfer_rate) +{ + switch(xfer_rate) { + case XFER_UDMA_7: return("UDMA 7"); + case XFER_UDMA_6: return("UDMA 6"); + case XFER_UDMA_5: return("UDMA 5"); + case XFER_UDMA_4: return("UDMA 4"); + case XFER_UDMA_3: return("UDMA 3"); + case XFER_UDMA_2: return("UDMA 2"); + case XFER_UDMA_1: return("UDMA 1"); + case XFER_UDMA_0: return("UDMA 0"); + case XFER_MW_DMA_2: return("MW DMA 2"); + case XFER_MW_DMA_1: return("MW DMA 1"); + case XFER_MW_DMA_0: return("MW DMA 0"); + case XFER_SW_DMA_2: return("SW DMA 2"); + case XFER_SW_DMA_1: return("SW DMA 1"); + case XFER_SW_DMA_0: return("SW DMA 0"); + case XFER_PIO_4: return("PIO 4"); + case XFER_PIO_3: return("PIO 3"); + case XFER_PIO_2: return("PIO 2"); + case XFER_PIO_1: return("PIO 1"); + case XFER_PIO_0: return("PIO 0"); + case XFER_PIO_SLOW: return("PIO SLOW"); + default: return("XFER ERROR"); + } +} + +/* + * A Verbose noise maker for debugging on the attempted dmaing calls. + */ +extern inline char *ide_dmafunc_verbose (ide_dma_action_t dmafunc) +{ + switch (dmafunc) { + case ide_dma_read: return("ide_dma_read"); + case ide_dma_write: return("ide_dma_write"); + case ide_dma_begin: return("ide_dma_begin"); + case ide_dma_end: return("ide_dma_end:"); + case ide_dma_check: return("ide_dma_check"); + case ide_dma_on: return("ide_dma_on"); + case ide_dma_off: return("ide_dma_off"); + case ide_dma_off_quietly: return("ide_dma_off_quietly"); + case ide_dma_test_irq: return("ide_dma_test_irq"); + case ide_dma_host_on: return("ide_dma_host_on"); + case ide_dma_host_off: return("ide_dma_host_off"); + case ide_dma_bad_drive: return("ide_dma_bad_drive"); + case ide_dma_good_drive: return("ide_dma_good_drive"); + case ide_dma_verbose: return("ide_dma_verbose"); + case ide_dma_retune: return("ide_dma_retune"); + case ide_dma_lostirq: return("ide_dma_lostirq"); + case ide_dma_timeout: return("ide_dma_timeout"); + default: return("unknown"); + } +} + +/* * An ide_tuneproc_t() is used to set the speed of an IDE interface * to a particular PIO mode. The "byte" parameter is used * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255 @@ -513,21 +663,29 @@ typedef struct hwif_s { struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ - void *hwgroup; /* actually (ide_hwgroup_t *) */ + struct hwgroup_s *hwgroup; /* actually (ide_hwgroup_t *) */ ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */ +/* + * FIXME!! need a generic register set :-/ PPC guys ideas?? + * + * ide_mmioreg_t mm_ports[IDE_NR_PORTS]; "task file registers" + * + */ hw_regs_t hw; /* Hardware info */ ide_drive_t drives[MAX_DRIVES]; /* drive info */ struct gendisk *gd; /* gendisk structure */ - ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */ - ide_speedproc_t *speedproc; /* routine to retune DMA modes for drives */ - ide_selectproc_t *selectproc; /* tweaks hardware to select drive */ - ide_resetproc_t *resetproc; /* routine to reset controller after a disk reset */ - ide_intrproc_t *intrproc; /* special interrupt handling for shared pci interrupts */ - ide_maskproc_t *maskproc; /* special host masking for drive selection */ - ide_quirkproc_t *quirkproc; /* check host's drive quirk list */ - ide_rw_proc_t *rwproc; /* adjust timing based upon rq->cmd direction */ - ide_ideproc_t *ideproc; /* CPU-polled transfer routine */ - ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ + int addressing; /* hosts addressing */ + void (*tuneproc)(ide_drive_t *, byte); /* routine to tune PIO mode for drives */ + int (*speedproc)(ide_drive_t *, byte); /* routine to retune DMA modes for drives */ + void (*selectproc)(ide_drive_t *); /* tweaks hardware to select drive */ + void (*resetproc)(ide_drive_t *); /* routine to reset controller after a disk reset */ + void (*intrproc)(ide_drive_t *); /* special interrupt handling for shared pci interrupts */ + void (*maskproc)(ide_drive_t *, int); /* special host masking for drive selection */ + int (*quirkproc)(ide_drive_t *); /* check host's drive quirk list */ + void (*rwproc)(ide_drive_t *, ide_dma_action_t); /* adjust timing based upon rq->cmd direction */ + void (*ideproc)(ide_ide_action_t, ide_drive_t *, void *, unsigned int); /* CPU-polled transfer routine */ + int (*dmaproc)(ide_dma_action_t, ide_drive_t *); /* dma read/write/abort routine */ + int (*busproc)(ide_drive_t *, int); /* driver soft-power interface */ unsigned int *dmatable_cpu; /* dma physical region descriptor table (cpu view) */ dma_addr_t dmatable_dma; /* dma physical region descriptor table (dma view) */ struct scatterlist *sg_table; /* Scatter-gather list used to build the above */ @@ -552,7 +710,7 @@ unsigned reset : 1; /* reset after probe */ unsigned autodma : 1; /* automatically try to enable DMA at boot */ unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */ - unsigned no_highio : 1; /* don't trust pci dma mask, bounce */ + unsigned no_highio : 1; /* can't do full 32-bit dma */ byte channel; /* for dual-port chips: 0=primary, 1=secondary */ #ifdef CONFIG_BLK_DEV_IDEPCI struct pci_dev *pci_dev; /* for pci chipsets */ @@ -563,7 +721,6 @@ #endif byte straight8; /* Alan's straight 8 check */ void *hwif_data; /* extra hwif data */ - ide_busproc_t *busproc; /* driver soft-power interface */ byte bus_state; /* power state of the IDE bus */ } ide_hwif_t; @@ -590,6 +747,7 @@ typedef struct hwgroup_s { ide_handler_t *handler;/* irq handler, if active */ + ide_handler_t *handler_save;/* irq handler, if active */ volatile int busy; /* BOOL: protects all fields below */ int sleeping; /* BOOL: wake us up on timer expiry */ ide_drive_t *drive; /* current drive */ @@ -599,6 +757,7 @@ struct request wrq; /* local copy of current write rq */ unsigned long poll_timeout; /* timeout value during long polls */ ide_expiry_t *expiry; /* queried upon timeouts */ + int pio_clock; /* ide_system_bus_speed */ } ide_hwgroup_t; /* structure attached to the request for IDE_TASK_CMDS */ @@ -686,24 +845,6 @@ */ #define IDE_SUBDRIVER_VERSION 1 -typedef int (ide_cleanup_proc)(ide_drive_t *); -typedef int (ide_standby_proc)(ide_drive_t *); -typedef int (ide_flushcache_proc)(ide_drive_t *); -typedef ide_startstop_t (ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long); -typedef void (ide_end_request_proc)(byte, ide_hwgroup_t *); -typedef int (ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long); -typedef int (ide_open_proc)(struct inode *, struct file *, ide_drive_t *); -typedef void (ide_release_proc)(struct inode *, struct file *, ide_drive_t *); -typedef int (ide_check_media_change_proc)(ide_drive_t *); -typedef void (ide_revalidate_proc)(ide_drive_t *); -typedef void (ide_pre_reset_proc)(ide_drive_t *); -typedef unsigned long (ide_capacity_proc)(ide_drive_t *); -typedef ide_startstop_t (ide_special_proc)(ide_drive_t *); -typedef void (ide_setting_proc)(ide_drive_t *); -typedef int (ide_reinit_proc)(ide_drive_t *); -typedef void (ata_prebuilder_proc)(ide_drive_t *); -typedef void (atapi_prebuilder_proc)(ide_drive_t *); - typedef struct ide_driver_s { const char *name; const char *version; @@ -711,26 +852,31 @@ unsigned busy : 1; unsigned supports_dma : 1; unsigned supports_dsc_overlap : 1; - ide_cleanup_proc *cleanup; - ide_standby_proc *standby; - ide_flushcache_proc *flushcache; - ide_do_request_proc *do_request; - ide_end_request_proc *end_request; - ide_ioctl_proc *ioctl; - ide_open_proc *open; - ide_release_proc *release; - ide_check_media_change_proc *media_change; - ide_revalidate_proc *revalidate; - ide_pre_reset_proc *pre_reset; - ide_capacity_proc *capacity; - ide_special_proc *special; - ide_proc_entry_t *proc; - ide_reinit_proc *reinit; - ata_prebuilder_proc *ata_prebuilder; - atapi_prebuilder_proc *atapi_prebuilder; + int (*cleanup)(ide_drive_t *); + int (*standby)(ide_drive_t *); + int (*suspend)(ide_drive_t *); + int (*resume)(ide_drive_t *); + int (*flushcache)(ide_drive_t *); + ide_startstop_t (*do_request)(ide_drive_t *, struct request *, unsigned long); + int (*end_request)(ide_drive_t *, int); + byte (*sense)(ide_drive_t *, const char *, byte); + ide_startstop_t (*error)(ide_drive_t *, const char *, byte); + int (*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long); + int (*open)(struct inode *, struct file *, ide_drive_t *); + void (*release)(struct inode *, struct file *, ide_drive_t *); + int (*media_change)(ide_drive_t *); + void (*revalidate)(ide_drive_t *); + void (*pre_reset)(ide_drive_t *); + unsigned long (*capacity)(ide_drive_t *); + ide_startstop_t (*special)(ide_drive_t *); + ide_proc_entry_t *proc; + int (*init)(void); + int (*reinit)(ide_drive_t *); + void (*ata_prebuilder)(ide_drive_t *); + void (*atapi_prebuilder)(ide_drive_t *); } ide_driver_t; -#define DRIVER(drive) ((ide_driver_t *)((drive)->driver)) +#define DRIVER(drive) ((drive)->driver) /* * IDE modules. @@ -770,23 +916,7 @@ #define LOCAL_END_REQUEST /* Don't generate end_request in blk.h */ #include -void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); - -/* - * This is used for (nearly) all data transfers from/to the IDE interface - * FIXME for 2.5, to a pointer pass verses memcpy........ - */ -void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); -void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount); - -/* - * This is used for (nearly) all ATAPI data transfers from/to the IDE interface - * FIXME for 2.5, to a pointer pass verses memcpy........ - */ -void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); -void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); - -int drive_is_ready (ide_drive_t *drive); +int ide_end_request (ide_drive_t *drive, int uptodate); /* * This is used on exit from the driver, to designate the next irq handler @@ -829,8 +959,6 @@ */ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout); -int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout); - /* * This routine is called from the partition-table code in genhd.c * to "convert" a drive to a logical geometry with fewer than 1024 cyls. @@ -857,7 +985,7 @@ * Re-Start an operation for an IDE interface. * The caller should return immediately after invoking this. */ -ide_startstop_t restart_request (ide_drive_t *); +int restart_request (ide_drive_t *, struct request *); /* * This function is intended to be used prior to invoking ide_do_drive_cmd(). @@ -875,21 +1003,6 @@ } ide_action_t; /* - * temporarily mapping a (possible) highmem bio - */ -#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9) - -extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags) -{ - return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq); -} - -extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags) -{ - bh_kunmap_irq(buffer, flags); -} - -/* * This function issues a special IDE device request * onto the request queue. * @@ -940,9 +1053,8 @@ ide_pre_handler_t *prehandler; ide_handler_t *handler; ide_post_handler_t *posthandler; - void *special; /* valid_t generally */ struct request *rq; /* copy of request */ - unsigned long block; /* copy of block */ + void *special; /* valid_t generally */ } ide_task_t; typedef struct pkt_task_s { @@ -950,25 +1062,31 @@ int data_phase; int command_type; ide_handler_t *handler; - void *special; struct request *rq; /* copy of request */ - unsigned long block; /* copy of block */ + void *special; } pkt_task_t; +void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); +void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount); +void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); +void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); +void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); +void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount); + +int drive_is_ready (ide_drive_t *drive); +int wait_for_ready (ide_drive_t *drive, int timeout); + /* - * taskfile io for disks for now... + * taskfile io for disks for now...and builds request from ide_ioctl */ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task); -/* - * Builds request from ide_ioctl - */ -void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler); +void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err); /* * Special Flagged Register Validation Caller */ -// ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task); +ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task); ide_startstop_t set_multmode_intr (ide_drive_t *drive); ide_startstop_t set_geometry_intr (ide_drive_t *drive); @@ -978,19 +1096,21 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive); ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq); ide_startstop_t task_out_intr (ide_drive_t *drive); +ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq); ide_startstop_t task_mulout_intr (ide_drive_t *drive); void ide_init_drive_taskfile (struct request *rq); -int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf); - int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf); ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile); ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile); +ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile); /* Expects args is a full set of TF registers and parses the command type */ int ide_cmd_type_parser (ide_task_t *args); int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); #ifdef CONFIG_PKT_TASK_IOCTL int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); @@ -1005,6 +1125,7 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed); byte eighty_ninty_three (ide_drive_t *drive); int set_transfer (ide_drive_t *drive, ide_task_t *args); +int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf); /* * ide_system_bus_speed() returns what we think is the system VESA/PCI @@ -1015,12 +1136,6 @@ int ide_system_bus_speed (void); /* - * ide_multwrite() transfers a block of up to mcount sectors of data - * to a drive as part of a disk multwrite operation. - */ -int ide_multwrite (ide_drive_t *drive, unsigned int mcount); - -/* * ide_stall_queue() can be used by a drive to give excess bandwidth back * to the hwgroup by sleeping for timeout jiffies. */ @@ -1093,6 +1208,56 @@ # define OFF_BOARD NEVER_BOARD #endif /* CONFIG_BLK_DEV_OFFBOARD */ + +typedef struct ide_pci_enablebit_s { + byte reg; /* byte pci reg holding the enable-bit */ + byte mask; /* mask to isolate the enable-bit */ + byte val; /* value of masked reg when "enabled" */ +} ide_pci_enablebit_t; + +typedef struct ide_pci_device_s { + ide_pci_devid_t devid; + char *name; + void (*fixup_device)(struct pci_dev *, struct ide_pci_device_s *); + unsigned int (*init_chipset)(struct pci_dev *, const char *); + unsigned int (*ata66_check)(ide_hwif_t *); + void (*init_hwif)(ide_hwif_t *); + void (*dma_init)(ide_hwif_t *, unsigned long); + ide_pci_enablebit_t enablebits[2]; + byte bootable; + unsigned int extra; +} ide_pci_device_t; + +#ifdef LINUX_PCI_H +extern inline void ide_register_xp_fix(struct pci_dev *dev) +{ + int i; + unsigned short cmd; + unsigned long flags; + unsigned long base_address[4] = { 0x1f0, 0x3f4, 0x170, 0x374 }; + + local_irq_save(flags); + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); + for (i=0; i<4; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } + for (i=0; i<4; i++) { + dev->resource[i].start = base_address[i]; + dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; + pci_write_config_dword(dev, + (PCI_BASE_ADDRESS_0 + (i * 4)), + dev->resource[i].start); + } + pci_write_config_word(dev, PCI_COMMAND, cmd); + local_irq_restore(flags); +} + +void ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) __init; +#endif /* LINUX_PCI_H */ + unsigned long ide_find_free_region (unsigned short size) __init; void ide_scan_pcibus (int scan_direction) __init; #endif @@ -1108,7 +1273,7 @@ int ide_release_dma (ide_hwif_t *hwif); void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init; unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init; -#endif +#endif /* CONFIG_BLK_DEV_IDEPCI */ void hwif_unregister (ide_hwif_t *hwif); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/input.h linux.20pre2-ac1/include/linux/input.h --- linux.20pre2/include/linux/input.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/input.h 2002-08-14 14:41:30.000000000 +0100 @@ -471,6 +471,7 @@ #define BUS_PCI 0x01 #define BUS_ISAPNP 0x02 #define BUS_USB 0x03 +#define BUS_HIL 0x04 #define BUS_ISA 0x10 #define BUS_I8042 0x11 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/iobuf.h linux.20pre2-ac1/include/linux/iobuf.h --- linux.20pre2/include/linux/iobuf.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/iobuf.h 2002-08-14 14:41:30.000000000 +0100 @@ -28,6 +28,8 @@ #define KIO_STATIC_PAGES (KIO_MAX_ATOMIC_IO / (PAGE_SIZE >> 10) + 1) #define KIO_MAX_SECTORS (KIO_MAX_ATOMIC_IO * 2) +#define RAWIO_BLOCKSIZE 4096 + /* The main kiobuf struct used for all our IO! */ struct kiobuf @@ -37,7 +39,9 @@ int offset; /* Offset to start of valid data */ int length; /* Number of valid bytes of data */ - unsigned int locked : 1; /* If set, pages has been locked */ + unsigned int locked : 1, /* If set, pages has been locked */ + dovary : 1; /* If set, do variable size IO */ + struct page ** maplist; struct buffer_head ** bh; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/ioport.h linux.20pre2-ac1/include/linux/ioport.h --- linux.20pre2/include/linux/ioport.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/ioport.h 2002-08-06 15:41:52.000000000 +0100 @@ -40,7 +40,6 @@ #define IORESOURCE_CACHEABLE 0x00004000 #define IORESOURCE_RANGELENGTH 0x00008000 #define IORESOURCE_SHADOWABLE 0x00010000 -#define IORESOURCE_BUS_HAS_VGA 0x00080000 #define IORESOURCE_UNSET 0x20000000 #define IORESOURCE_AUTO 0x40000000 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/jbd.h linux.20pre2-ac1/include/linux/jbd.h --- linux.20pre2/include/linux/jbd.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/jbd.h 2002-08-14 14:41:30.000000000 +0100 @@ -32,6 +32,14 @@ #define journal_oom_retry 1 +/* + * Define JBD_PARANOID_WRITES to cause a kernel BUG() check if ext3 + * finds a buffer unexpectedly dirty. This is useful for debugging, but + * can cause spurious kernel panics if there are applications such as + * tune2fs modifying our buffer_heads behind our backs. + */ +#undef JBD_PARANOID_WRITES + #ifdef CONFIG_JBD_DEBUG /* * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal @@ -246,7 +254,7 @@ static inline struct journal_head *bh2jh(struct buffer_head *bh) { - return bh->b_private; + return bh->b_journal_head; } struct jbd_revoke_table_s; @@ -352,7 +360,7 @@ */ struct journal_head * t_async_datalist; - /* Doubly-linked circular list of all forget buffers (superseded + /* Doubly-linked circular list of all forget buffers (superceded buffers which we can un-checkpoint once this transaction commits) */ struct journal_head * t_forget; @@ -730,6 +738,10 @@ schedule(); \ } while (1) +extern void __jbd_unexpected_dirty_buffer(char *, int, struct journal_head *); +#define jbd_unexpected_dirty_buffer(jh) \ + __jbd_unexpected_dirty_buffer(__FUNCTION__, __LINE__, (jh)) + /* * is_journal_abort * @@ -793,7 +805,7 @@ #define BJ_SyncData 1 /* Normal data: flush before commit */ #define BJ_AsyncData 2 /* writepage data: wait on it before commit */ #define BJ_Metadata 3 /* Normal journaled metadata */ -#define BJ_Forget 4 /* Buffer superseded by this transaction */ +#define BJ_Forget 4 /* Buffer superceded by this transaction */ #define BJ_IO 5 /* Buffer is for temporary IO use */ #define BJ_Shadow 6 /* Buffer contents being shadowed to the log */ #define BJ_LogCtl 7 /* Buffer contains log descriptors */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/kd.h linux.20pre2-ac1/include/linux/kd.h --- linux.20pre2/include/linux/kd.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/kd.h 2002-08-06 18:24:33.000000000 +0100 @@ -132,6 +132,19 @@ #define KDSIGACCEPT 0x4B4E /* accept kbd generated signals */ +struct hwclk_time { + unsigned sec; /* 0..59 */ + unsigned min; /* 0..59 */ + unsigned hour; /* 0..23 */ + unsigned day; /* 1..31 */ + unsigned mon; /* 0..11 */ + unsigned year; /* 70... */ + int wday; /* 0..6, 0 is Sunday, -1 means unknown/don't set */ +}; + +#define KDGHWCLK 0x4B50 /* get hardware clock */ +#define KDSHWCLK 0x4B51 /* set hardware clock */ + struct kbd_repeat { int delay; /* in msec; <= 0: don't change */ int rate; /* in msec; <= 0: don't change */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/kernel_stat.h linux.20pre2-ac1/include/linux/kernel_stat.h --- linux.20pre2/include/linux/kernel_stat.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/kernel_stat.h 2002-08-14 14:41:30.000000000 +0100 @@ -26,20 +26,31 @@ unsigned int dk_drive_wblk[DK_MAX_MAJOR][DK_MAX_DISK]; unsigned int pgpgin, pgpgout; unsigned int pswpin, pswpout; -#if !defined(CONFIG_ARCH_S390) +#if defined (__hppa__) + unsigned int irqs[NR_IRQ_REGS][IRQ_PER_REGION]; +#elif !defined(CONFIG_ARCH_S390) unsigned int irqs[NR_CPUS][NR_IRQS]; #endif - unsigned int context_swtch; }; extern struct kernel_stat kstat; -#if !defined(CONFIG_ARCH_S390) +extern unsigned long nr_context_switches(void); + +#if defined (__hppa__) /* * Number of interrupts per specific IRQ source, since bootup */ static inline int kstat_irqs (int irq) { + return kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)]; +} +#elif !defined(CONFIG_ARCH_S390) +/* + * Number of interrupts per specific IRQ source, since bootup + */ +extern inline int kstat_irqs (int irq) +{ int i, sum=0; for (i = 0 ; i < smp_num_cpus ; i++) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/keyboard.h linux.20pre2-ac1/include/linux/keyboard.h --- linux.20pre2/include/linux/keyboard.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/keyboard.h 2002-08-14 14:41:30.000000000 +0100 @@ -44,6 +44,7 @@ #define KT_ASCII 9 #define KT_LOCK 10 #define KT_SLOCK 12 +#define KT_SPKUP 13 #define K(t,v) (((t)<<8)|(v)) #define KTYP(x) ((x) >> 8) @@ -361,7 +362,9 @@ #define K_DDIERE K(KT_DEAD,4) #define K_DCEDIL K(KT_DEAD,5) -#define NR_DEAD 6 +/* adjust diacriticals for goto keyboard function */ +#define K_DSPKUP K(KT_DEAD,6) +#define NR_DEAD 7 #define K_DOWN K(KT_CUR,0) #define K_LEFT K(KT_CUR,1) @@ -427,5 +430,49 @@ #define NR_LOCK 8 +/* speakup key macros */ +#define K_QUICK_QUIET K(KT_SPKUP,QUICK_QUIET) +#define K_LINE_QUIET K(KT_SPKUP,LINE_QUIET) +#define K_FULL_QUIET K(KT_SPKUP,FULL_QUIET) +#define K_SAY_CHAR K(KT_SPKUP,SAY_CHAR) +#define K_SAY_PREV_CHAR K(KT_SPKUP,SAY_PREV_CHAR) +#define K_SAY_NEXT_CHAR K(KT_SPKUP,SAY_NEXT_CHAR) +#define K_SAY_WORD K(KT_SPKUP,SAY_WORD) +#define K_SAY_PREV_WORD K(KT_SPKUP,SAY_PREV_WORD) +#define K_SAY_NEXT_WORD K(KT_SPKUP,SAY_NEXT_WORD) +#define K_SAY_LINE K(KT_SPKUP,SAY_LINE) +#define K_SAY_PREV_LINE K(KT_SPKUP,SAY_PREV_LINE) +#define K_SAY_NEXT_LINE K(KT_SPKUP,SAY_NEXT_LINE) +#define K_TOP_EDGE K(KT_SPKUP,TOP_EDGE) +#define K_BOTTOM_EDGE K(KT_SPKUP,BOTTOM_EDGE) +#define K_LEFT_EDGE K(KT_SPKUP,LEFT_EDGE) +#define K_RIGHT_EDGE K(KT_SPKUP,RIGHT_EDGE ) +#define K_SAY_PHONETIC_CHAR K(KT_SPKUP,SAY_PHONETIC_CHAR) +#define K_SPELL_WORD K(KT_SPKUP,SPELL_WORD) +#define K_SPELL_PHONETIC_WORD K(KT_SPKUP,SPELL_PHONETIC_WORD) +#define K_SAY_SCREEN K(KT_SPKUP,SAY_SCREEN) +#define K_SAY_WINDOW K(KT_SPKUP,SAY_WINDOW) +#define K_SET_SPEED K(KT_SPKUP,SET_SPEED) +#define K_SET_PITCH K(KT_SPKUP,SET_PITCH) +#define K_SET_PUNCTUATION K(KT_SPKUP,SET_PUNCTUATION) +#define K_SET_VOICE K(KT_SPKUP,SET_VOICE) +#define K_SET_TONE K(KT_SPKUP,SET_TONE) +#define K_SAY_POSITION K(KT_SPKUP,SAY_POSITION) +#define K_SPEECH_OFF K(KT_SPKUP,SPEECH_OFF) +#define K_SAY_ATTRIBUTES K(KT_SPKUP,SAY_ATTRIBUTES) +#define K_SPEAKUP_PARKED K(KT_SPKUP,SPEAKUP_PARKED) +#define K_INS_TOGGLE K(KT_SPKUP,INS_TOGGLE) +#define K_SAY_FROM_TOP K(KT_SPKUP,SAY_FROM_TOP) +#define K_SAY_TO_BOTTOM K(KT_SPKUP,SAY_TO_BOTTOM) +#define K_SAY_FROM_LEFT K(KT_SPKUP,SAY_FROM_LEFT) +#define K_SAY_TO_RIGHT K(KT_SPKUP,SAY_TO_RIGHT) +#define K_SAY_CHAR_NUM K(KT_SPKUP,SAY_CHAR_NUM) +#define K_SPEECH_KILL K(KT_SPKUP,SPEECH_KILL) +#define K_SPEAKUP_CURSORING K(KT_SPKUP,SPEAKUP_CURSORING) +#define K_SPEAKUP_CUT K(KT_SPKUP,SPEAKUP_CUT) +#define K_SPEAKUP_PASTE K(KT_SPKUP,SPEAKUP_PASTE) + +#define NR_SPKUP 0x29 + #define MAX_DIACR 256 #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/list.h linux.20pre2-ac1/include/linux/list.h --- linux.20pre2/include/linux/list.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/list.h 2002-08-14 14:41:29.000000000 +0100 @@ -19,6 +19,8 @@ struct list_head *next, *prev; }; +typedef struct list_head list_t; + #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/llc.h linux.20pre2-ac1/include/linux/llc.h --- linux.20pre2/include/linux/llc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/llc.h 2002-08-06 18:24:33.000000000 +0100 @@ -0,0 +1,102 @@ +#ifndef __LINUX_LLC_H +#define __LINUX_LLC_H +/* + * IEEE 802.2 User Interface SAPs for Linux, data structures and indicators. + * + * Copyright (c) 2001 by Jay Schulist + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#define __LLC_SOCK_SIZE__ 28 /* sizeof(sockaddr_llc), word align. */ +struct sockaddr_llc { + sa_family_t sllc_family; /* AF_LLC */ + sa_family_t sllc_arphrd; /* ARPHRD_ETHER */ + unsigned char sllc_test; + unsigned char sllc_xid; + unsigned char sllc_ua; /* UA data, only for SOCK_STREAM. */ + unsigned char sllc_dsap; + unsigned char sllc_ssap; + unsigned char sllc_dmac[IFHWADDRLEN]; + unsigned char sllc_smac[IFHWADDRLEN]; + unsigned char sllc_mmac[IFHWADDRLEN]; + unsigned char __pad[__LLC_SOCK_SIZE__ - sizeof(sa_family_t) * 2 - + sizeof(unsigned char) * 5 - IFHWADDRLEN * 3]; +}; + +/* sockopt definitions. */ +enum llc_sockopts { + LLC_OPT_UNKNOWN = 0, + LLC_OPT_RETRY, /* max retrans attempts. */ + LLC_OPT_SIZE, /* max PDU size (octets). */ + LLC_OPT_ACK_TMR_EXP, /* ack expire time (secs). */ + LLC_OPT_P_TMR_EXP, /* pf cycle expire time (secs). */ + LLC_OPT_REJ_TMR_EXP, /* rej sent expire time (secs). */ + LLC_OPT_BUSY_TMR_EXP, /* busy state expire time (secs). */ + LLC_OPT_TX_WIN, /* tx window size. */ + LLC_OPT_RX_WIN, /* rx window size. */ + LLC_OPT_MAX +}; + +#define LLC_OPT_MAX_RETRY 100 +#define LLC_OPT_MAX_SIZE 4196 +#define LLC_OPT_MAX_WIN 127 +#define LLC_OPT_MAX_ACK_TMR_EXP 60 +#define LLC_OPT_MAX_P_TMR_EXP 60 +#define LLC_OPT_MAX_REJ_TMR_EXP 60 +#define LLC_OPT_MAX_BUSY_TMR_EXP 60 + +/* LLC SAP types. */ +#define LLC_SAP_NULL 0x00 /* NULL SAP. */ +#define LLC_SAP_LLC 0x02 /* LLC Sublayer Managment. */ +#define LLC_SAP_SNA 0x04 /* SNA Path Control. */ +#define LLC_SAP_PNM 0x0E /* Proway Network Managment. */ +#define LLC_SAP_IP 0x06 /* TCP/IP. */ +#define LLC_SAP_BSPAN 0x42 /* Bridge Spanning Tree Proto */ +#define LLC_SAP_MMS 0x4E /* Manufacturing Message Srv. */ +#define LLC_SAP_8208 0x7E /* ISO 8208 */ +#define LLC_SAP_3COM 0x80 /* 3COM. */ +#define LLC_SAP_PRO 0x8E /* Proway Active Station List */ +#define LLC_SAP_SNAP 0xAA /* SNAP. */ +#define LLC_SAP_BANYAN 0xBC /* Banyan. */ +#define LLC_SAP_IPX 0xE0 /* IPX/SPX. */ +#define LLC_SAP_NETBEUI 0xF0 /* NetBEUI. */ +#define LLC_SAP_LANMGR 0xF4 /* LanManager. */ +#define LLC_SAP_IMPL 0xF8 /* IMPL */ +#define LLC_SAP_DISC 0xFC /* Discovery */ +#define LLC_SAP_OSI 0xFE /* OSI Network Layers. */ +#define LLC_SAP_LAR 0xDC /* LAN Address Resolution */ +#define LLC_SAP_RM 0xD4 /* Resource Management */ +#define LLC_SAP_GLOBAL 0xFF /* Global SAP. */ + +#ifdef __KERNEL__ +#define LLC_SAP_DYN_START 0xC0 +#define LLC_SAP_DYN_STOP 0xDE +#define LLC_SAP_DYN_TRIES 4 + +struct sock; + +struct llc_ui_opt { + u16 link; /* network layer link number */ + struct llc_sap *sap; /* pointer to parent SAP */ + struct sock *core_sk; + struct net_device *dev; /* device to send to remote */ + struct sockaddr_llc addr; /* address sock is bound to */ +}; + +#define llc_ui_sk(__sk) ((struct llc_ui_opt *)(__sk)->protinfo.destruct_hook) +#define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0])) + +#ifdef CONFIG_LLC_UI +extern int llc_ui_init(void); +extern void llc_ui_exit(void); +#else +#define llc_ui_init() +#define llc_ui_exit() +#endif +#endif /* __KERNEL__ */ +#endif /* __LINUX_LLC_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/lockd/lockd.h linux.20pre2-ac1/include/linux/lockd/lockd.h --- linux.20pre2/include/linux/lockd/lockd.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/lockd/lockd.h 2002-08-14 14:41:30.000000000 +0100 @@ -89,8 +89,11 @@ /* * This is a server block (i.e. a lock requested by some client which * couldn't be granted because of a conflicting lock). + * + * XXX: Beware of signedness errors. b_when is passed as a signed long + * into time_before_eq et al. --okir */ -#define NLM_NEVER (~(unsigned long) 0) +#define NLM_NEVER (0x7FFFFFF) struct nlm_block { struct nlm_block * b_next; /* linked list (all blocks) */ struct nlm_block * b_fnext; /* linked list (per file) */ @@ -161,6 +164,7 @@ u32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *, struct nlm_lock *); u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); +void nlmsvc_grant_reply(struct nlm_cookie *, u32); unsigned long nlmsvc_retry_blocked(void); int nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, int action); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/malloc.h linux.20pre2-ac1/include/linux/malloc.h --- linux.20pre2/include/linux/malloc.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/malloc.h 2002-08-14 14:41:30.000000000 +0100 @@ -1,7 +1,7 @@ #ifndef _LINUX_MALLOC_H #define _LINUX_MALLOC_H -#warning linux/malloc.h is deprecated, use linux/slab.h instead. +#error linux/malloc.h is deprecated, use linux/slab.h instead. #include #endif /* _LINUX_MALLOC_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/mempool.h linux.20pre2-ac1/include/linux/mempool.h --- linux.20pre2/include/linux/mempool.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/mempool.h 2002-08-14 14:41:31.000000000 +0100 @@ -0,0 +1,41 @@ +/* + * memory buffer pool support + */ +#ifndef _LINUX_MEMPOOL_H +#define _LINUX_MEMPOOL_H + +#include +#include + +struct mempool_s; +typedef struct mempool_s mempool_t; + +typedef void * (mempool_alloc_t)(int gfp_mask, void *pool_data); +typedef void (mempool_free_t)(void *element, void *pool_data); + +struct mempool_s { + spinlock_t lock; + int min_nr, curr_nr; + struct list_head elements; + + void *pool_data; + mempool_alloc_t *alloc; + mempool_free_t *free; + wait_queue_head_t wait; +}; +extern mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn, + mempool_free_t *free_fn, void *pool_data); +extern void mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask); +extern void mempool_destroy(mempool_t *pool); +extern void * mempool_alloc(mempool_t *pool, int gfp_mask); +extern void mempool_free(void *element, mempool_t *pool); + +/* + * A mempool_alloc_t and mempool_free_t that get the memory from + * a slab that is passed in through pool_data. + */ +void *mempool_alloc_slab(int gfp_mask, void *pool_data); +void mempool_free_slab(void *element, void *pool_data); + + +#endif /* _LINUX_MEMPOOL_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/miscdevice.h linux.20pre2-ac1/include/linux/miscdevice.h --- linux.20pre2/include/linux/miscdevice.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/miscdevice.h 2002-08-14 14:41:30.000000000 +0100 @@ -3,38 +3,39 @@ #include -#define BUSMOUSE_MINOR 0 -#define PSMOUSE_MINOR 1 -#define MS_BUSMOUSE_MINOR 2 -#define ATIXL_BUSMOUSE_MINOR 3 -#define AMIGAMOUSE_MINOR 4 -#define ATARIMOUSE_MINOR 5 -#define SUN_MOUSE_MINOR 6 -#define APOLLO_MOUSE_MINOR 7 -#define PC110PAD_MINOR 9 -#define ADB_MOUSE_MINOR 10 -#define MK712_MINOR 15 /* MK712 touch screen */ +#define BUSMOUSE_MINOR 0 +#define PSMOUSE_MINOR 1 +#define MS_BUSMOUSE_MINOR 2 +#define ATIXL_BUSMOUSE_MINOR 3 +#define AMIGAMOUSE_MINOR 4 +#define ATARIMOUSE_MINOR 5 +#define SUN_MOUSE_MINOR 6 +#define APOLLO_MOUSE_MINOR 7 +#define PC110PAD_MINOR 9 +#define ADB_MOUSE_MINOR 10 +#define MK712_MINOR 15 /* MK712 touch screen */ +#define SYNTH_MINOR 25 #define WATCHDOG_MINOR 130 /* Watchdog timer */ #define TEMP_MINOR 131 /* Temperature Sensor */ -#define RTC_MINOR 135 +#define RTC_MINOR 135 #define EFI_RTC_MINOR 136 /* EFI Time services */ -#define SUN_OPENPROM_MINOR 139 -#define NVRAM_MINOR 144 -#define I2O_MINOR 166 +#define SUN_OPENPROM_MINOR 139 +#define NVRAM_MINOR 144 +#define I2O_MINOR 166 #define MICROCODE_MINOR 184 -#define MWAVE_MINOR 219 /* ACP/Mwave Modem */ -#define MPT_MINOR 220 -#define MISC_DYNAMIC_MINOR 255 - -#define SGI_GRAPHICS_MINOR 146 -#define SGI_OPENGL_MINOR 147 -#define SGI_GFX_MINOR 148 -#define SGI_STREAMS_MOUSE 149 -#define SGI_STREAMS_KEYBOARD 150 +#define MWAVE_MINOR 219 /* ACP/Mwave Modem */ +#define MPT_MINOR 220 +#define MISC_DYNAMIC_MINOR 255 + +#define SGI_GRAPHICS_MINOR 146 +#define SGI_OPENGL_MINOR 147 +#define SGI_GFX_MINOR 148 +#define SGI_STREAMS_MOUSE 149 +#define SGI_STREAMS_KEYBOARD 150 /* drivers/sgi/char/usema.c */ -#define SGI_USEMACLONE 151 +#define SGI_USEMACLONE 151 -#define TUN_MINOR 200 +#define TUN_MINOR 200 extern int misc_init(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/mman.h linux.20pre2-ac1/include/linux/mman.h --- linux.20pre2/include/linux/mman.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/mman.h 2002-08-06 15:41:52.000000000 +0100 @@ -6,4 +6,8 @@ #define MREMAP_MAYMOVE 1 #define MREMAP_FIXED 2 +extern int vm_enough_memory(long pages); +extern void vm_unacct_memory(long pages); +extern void vm_validate_enough(char *x); + #endif /* _LINUX_MMAN_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/mm.h linux.20pre2-ac1/include/linux/mm.h --- linux.20pre2/include/linux/mm.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/mm.h 2002-08-14 14:41:30.000000000 +0100 @@ -18,9 +18,6 @@ extern unsigned long num_mappedpages; extern void * high_memory; extern int page_cluster; -/* The inactive_clean lists are per zone. */ -extern struct list_head active_list; -extern struct list_head inactive_list; #include #include @@ -104,7 +101,13 @@ #define VM_DONTEXPAND 0x00040000 /* Cannot expand with mremap() */ #define VM_RESERVED 0x00080000 /* Don't unmap it from swap_out */ -#define VM_STACK_FLAGS 0x00000177 +#define VM_ACCOUNT 0x00100000 /* Memory is a vm accounted object */ + +#ifdef ARCH_STACK_GROWSUP +#define VM_STACK_FLAGS (0x00000277|VM_ACCOUNT) +#else +#define VM_STACK_FLAGS (0x00000177|VM_ACCOUNT) +#endif #define VM_READHINTMASK (VM_SEQ_READ | VM_RAND_READ) #define VM_ClearReadHint(v) (v)->vm_flags &= ~VM_READHINTMASK @@ -122,7 +125,6 @@ */ extern pgprot_t protection_map[16]; - /* * These are the virtual MM functions - opening of an area, closing and * unmapping it (needed to keep files on disk up-to-date etc), pointer @@ -134,6 +136,9 @@ struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int unused); }; +/* forward declaration; pte_chain is meant to be internal to rmap.c */ +struct pte_chain; + /* * Each physical page in the system has a struct page associated with * it to keep track of whatever it is we are using the page for at the @@ -151,7 +156,11 @@ */ typedef struct page { struct list_head list; /* ->mapping has some page lists. */ - struct address_space *mapping; /* The inode (or ...) we belong to. */ + struct address_space *mapping; /* The inode (or ...) we belong to. + * protected by PG_locked and the + * pagecache_lock. Hold one to read, + * both to write. + */ unsigned long index; /* Our offset within mapping. */ struct page *next_hash; /* Next page sharing our hash bucket in the pagecache hash table. */ @@ -160,6 +169,10 @@ updated asynchronously */ struct list_head lru; /* Pageout list, eg. active_list; protected by pagemap_lru_lock !! */ + unsigned char age; /* Page aging counter. */ + struct pte_chain * pte_chain; /* Reverse pte mapping pointer. + * protected by PG_chainlock + */ struct page **pprev_hash; /* Complement to *next_hash. */ struct buffer_head * buffers; /* Buffer maps us to a disk block. */ @@ -176,7 +189,7 @@ #if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL) void *virtual; /* Kernel virtual address (NULL if not kmapped, ie. highmem) */ -#endif /* CONFIG_HIGMEM || WANT_PAGE_VIRTUAL */ +#endif /* CONFIG_HIGHMEM || CONFIG_SPARC64 */ } mem_map_t; /* @@ -287,9 +300,9 @@ #define PG_referenced 2 #define PG_uptodate 3 #define PG_dirty 4 -#define PG_unused 5 -#define PG_lru 6 -#define PG_active 7 +#define PG_inactive_clean 5 +#define PG_active 6 +#define PG_inactive_dirty 7 #define PG_slab 8 #define PG_skip 10 #define PG_highmem 11 @@ -297,6 +310,10 @@ #define PG_arch_1 13 #define PG_reserved 14 #define PG_launder 15 /* written out by VM pressure.. */ +#define PG_chainlock 16 /* lock bit for ->pte_chain */ +#define PG_lru 17 +/* Don't you dare to use high bits, they seem to be used for something else! */ + /* Make it prettier to test the above... */ #define UnlockPage(page) unlock_page(page) @@ -316,6 +333,29 @@ #define ClearPageLaunder(page) clear_bit(PG_launder, &(page)->flags) /* + * inlines for acquisition and release of PG_chainlock + */ +static inline void pte_chain_lock(struct page *page) +{ + /* + * Assuming the lock is uncontended, this never enters + * the body of the outer loop. If it is contended, then + * within the inner loop a non-atomic test is used to + * busywait with less bus contention for a good time to + * attempt to acquire the lock bit. + */ + while (test_and_set_bit(PG_chainlock, &page->flags)) { + while (test_bit(PG_chainlock, &page->flags)) + cpu_relax(); + } +} + +static inline void pte_chain_unlock(struct page *page) +{ + clear_bit(PG_chainlock, &page->flags); +} + +/* * The zone field is never updated after free_area_init_core() * sets it, so none of the operations on it need to be atomic. */ @@ -343,7 +383,6 @@ * The same is true for page_address() in arch-dependent code. */ #if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL) - #define set_page_address(page, address) \ do { \ (page)->virtual = (address); \ @@ -357,6 +396,7 @@ * Permanent address of a page. Obviously must never be * called on a highmem page. */ + #if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL) #define page_address(page) ((page)->virtual) @@ -392,10 +432,16 @@ #define PageActive(page) test_bit(PG_active, &(page)->flags) #define SetPageActive(page) set_bit(PG_active, &(page)->flags) #define ClearPageActive(page) clear_bit(PG_active, &(page)->flags) +#define TestandSetPageActive(page) test_and_set_bit(PG_active, &(page)->flags) +#define TestandClearPageActive(page) test_and_clear_bit(PG_active, &(page)->flags) -#define PageLRU(page) test_bit(PG_lru, &(page)->flags) -#define TestSetPageLRU(page) test_and_set_bit(PG_lru, &(page)->flags) -#define TestClearPageLRU(page) test_and_clear_bit(PG_lru, &(page)->flags) +#define PageInactiveDirty(page) test_bit(PG_inactive_dirty, &(page)->flags) +#define SetPageInactiveDirty(page) set_bit(PG_inactive_dirty, &(page)->flags) +#define ClearPageInactiveDirty(page) clear_bit(PG_inactive_dirty, &(page)->flags) + +#define PageInactiveClean(page) test_bit(PG_inactive_clean, &(page)->flags) +#define SetPageInactiveClean(page) set_bit(PG_inactive_clean, &(page)->flags) +#define ClearPageInactiveClean(page) clear_bit(PG_inactive_clean, &(page)->flags) #ifdef CONFIG_HIGHMEM #define PageHighMem(page) test_bit(PG_highmem, &(page)->flags) @@ -406,6 +452,11 @@ #define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags) #define ClearPageReserved(page) clear_bit(PG_reserved, &(page)->flags) +#define PageLRU(page) test_bit(PG_lru, &(page)->flags) +#define SetPageLRU(page) set_bit(PG_lru, &(page)->flags) +#define ClearPageLRU(page) clear_bit(PG_lru, &(page)->flags) + + /* * Error return values for the *_nopage functions */ @@ -460,6 +511,7 @@ #define __free_page(page) __free_pages((page), 0) #define free_page(addr) free_pages((addr),0) +extern void FASTCALL(fixup_freespace(struct zone_struct *, int)); extern void show_free_areas(void); extern void show_free_areas_node(pg_data_t *pgdat); @@ -556,7 +608,7 @@ return ret; } -extern int do_munmap(struct mm_struct *, unsigned long, size_t); +extern int do_munmap(struct mm_struct *, unsigned long, size_t, int acct); extern unsigned long do_brk(unsigned long, unsigned long); @@ -623,34 +675,9 @@ return gfp_mask; } - -/* vma is the first one with address < vma->vm_end, - * and even address < vma->vm_start. Have to extend vma. */ -static inline int expand_stack(struct vm_area_struct * vma, unsigned long address) -{ - unsigned long grow; - /* - * vma->vm_start/vm_end cannot change under us because the caller is required - * to hold the mmap_sem in write mode. We need to get the spinlock only - * before relocating the vma range ourself. - */ - address &= PAGE_MASK; - spin_lock(&vma->vm_mm->page_table_lock); - grow = (vma->vm_start - address) >> PAGE_SHIFT; - if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || - ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) { - spin_unlock(&vma->vm_mm->page_table_lock); - return -ENOMEM; - } - vma->vm_start = address; - vma->vm_pgoff -= grow; - vma->vm_mm->total_vm += grow; - if (vma->vm_flags & VM_LOCKED) - vma->vm_mm->locked_vm += grow; - spin_unlock(&vma->vm_mm->page_table_lock); - return 0; -} +/* Do stack extension */ +extern int expand_stack(struct vm_area_struct * vma, unsigned long address); /* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/mm_inline.h linux.20pre2-ac1/include/linux/mm_inline.h --- linux.20pre2/include/linux/mm_inline.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/mm_inline.h 2002-08-14 14:41:31.000000000 +0100 @@ -0,0 +1,274 @@ +#ifndef _LINUX_MM_INLINE_H +#define _LINUX_MM_INLINE_H + +#include + +/* + * These inline functions tend to need bits and pieces of all the + * other VM include files, meaning they cannot be defined inside + * one of the other VM include files. + * + * The include file mess really needs to be cleaned up... + */ + +static inline void add_page_to_active_list(struct page * page) +{ + struct zone_struct * zone = page_zone(page); + DEBUG_LRU_PAGE(page); + SetPageActive(page); + list_add(&page->lru, &zone->active_list); + zone->active_pages++; + nr_active_pages++; +} + +static inline void add_page_to_inactive_dirty_list(struct page * page) +{ + struct zone_struct * zone = page_zone(page); + DEBUG_LRU_PAGE(page); + SetPageInactiveDirty(page); + list_add(&page->lru, &zone->inactive_dirty_list); + zone->inactive_dirty_pages++; + nr_inactive_dirty_pages++; +} + +static inline void add_page_to_inactive_clean_list(struct page * page) +{ + struct zone_struct * zone = page_zone(page); + DEBUG_LRU_PAGE(page); + SetPageInactiveClean(page); + list_add(&page->lru, &zone->inactive_clean_list); + zone->inactive_clean_pages++; + nr_inactive_clean_pages++; +} + +static inline void del_page_from_active_list(struct page * page) +{ + struct zone_struct * zone = page_zone(page); + list_del(&page->lru); + ClearPageActive(page); + nr_active_pages--; + zone->active_pages--; + DEBUG_LRU_PAGE(page); +} + +static inline void del_page_from_inactive_dirty_list(struct page * page) +{ + struct zone_struct * zone = page_zone(page); + list_del(&page->lru); + ClearPageInactiveDirty(page); + nr_inactive_dirty_pages--; + zone->inactive_dirty_pages--; + DEBUG_LRU_PAGE(page); +} + +static inline void del_page_from_inactive_clean_list(struct page * page) +{ + struct zone_struct * zone = page_zone(page); + list_del(&page->lru); + ClearPageInactiveClean(page); + zone->inactive_clean_pages--; + nr_inactive_clean_pages--; + DEBUG_LRU_PAGE(page); +} + +/* + * Inline functions to control some balancing in the VM. + * + * Note that we do both global and per-zone balancing, with + * most of the balancing done globally. + */ +#define PLENTY_FACTOR 2 +#define ALL_ZONES NULL +#define ANY_ZONE (struct zone_struct *)(~0UL) +#define INACTIVE_FACTOR 5 + +#define VM_MIN 0 +#define VM_LOW 1 +#define VM_HIGH 2 +#define VM_PLENTY 3 +static inline int zone_free_limit(struct zone_struct * zone, int limit) +{ + int free, target, delta; + + /* This is really nasty, but GCC should completely optimise it away. */ + if (limit == VM_MIN) + target = zone->pages_min; + else if (limit == VM_LOW) + target = zone->pages_low; + else if (limit == VM_HIGH) + target = zone->pages_high; + else + target = zone->pages_high * PLENTY_FACTOR; + + free = zone->free_pages + zone->inactive_clean_pages; + delta = target - free; + + return delta; +} + +static inline int free_limit(struct zone_struct * zone, int limit) +{ + int shortage = 0, local; + + if (zone == ALL_ZONES) { + for_each_zone(zone) + shortage += zone_free_limit(zone, limit); + } else if (zone == ANY_ZONE) { + for_each_zone(zone) { + local = zone_free_limit(zone, limit); + shortage += max(local, 0); + } + } else { + shortage = zone_free_limit(zone, limit); + } + + return shortage; +} + +/** + * free_min - test for critically low amount of free pages + * @zone: zone to test, ALL_ZONES to test memory globally + * + * Returns a positive value if we have a serious shortage of free and + * clean pages, zero or negative if there is no serious shortage. + */ +static inline int free_min(struct zone_struct * zone) +{ + return free_limit(zone, VM_MIN); +} + +/** + * free_low - test for low amount of free pages + * @zone: zone to test, ALL_ZONES to test memory globally + * + * Returns a positive value if we have a shortage of free and + * clean pages, zero or negative if there is no shortage. + */ +static inline int free_low(struct zone_struct * zone) +{ + return free_limit(zone, VM_LOW); +} + +/** + * free_high - test if amount of free pages is less than ideal + * @zone: zone to test, ALL_ZONES to test memory globally + * + * Returns a positive value if the number of free and clean + * pages is below kswapd's target, zero or negative if we + * have more than enough free and clean pages. + */ +static inline int free_high(struct zone_struct * zone) +{ + return free_limit(zone, VM_HIGH); +} + +/** + * free_plenty - test if enough pages are freed + * @zone: zone to test, ALL_ZONES to test memory globally + * + * Returns a positive value if the number of free + clean pages + * in a zone is not yet excessive and kswapd is still allowed to + * free pages here, a negative value if kswapd should leave the + * zone alone. + */ +static inline int free_plenty(struct zone_struct * zone) +{ + return free_limit(zone, VM_PLENTY); +} + +/* + * The inactive page target is the free target + 20% of (active + inactive) + * pages. + */ +static inline int zone_inactive_limit(struct zone_struct * zone, int limit) +{ + int inactive, target, inactive_base; + + inactive_base = zone->active_pages + zone->inactive_dirty_pages; + inactive_base /= INACTIVE_FACTOR; + + /* GCC should optimise this away completely. */ + if (limit == VM_MIN) + target = zone->pages_high + inactive_base / 2; + else if (limit == VM_LOW) + target = zone->pages_high + inactive_base; + else + target = zone->pages_high + inactive_base * 2; + + inactive = zone->free_pages + zone->inactive_clean_pages; + inactive += zone->inactive_dirty_pages; + + return target - inactive; +} + +static inline int inactive_limit(struct zone_struct * zone, int limit) +{ + int shortage = 0, local; + + if (zone == ALL_ZONES) { + for_each_zone(zone) + shortage += zone_inactive_limit(zone, limit); + } else if (zone == ANY_ZONE) { + for_each_zone(zone) { + local = zone_inactive_limit(zone, limit); + shortage += max(local, 0); + } + } else { + shortage = zone_inactive_limit(zone, limit); + } + + return shortage; +} + +/** + * inactive_min - test for serious shortage of (free + inactive clean) pages + * @zone: zone to test, ALL_ZONES for global testing + * + * Returns the shortage as a positive number, a negative number + * if we have no serious shortage of (free + inactive clean) pages + */ +static inline int inactive_min(struct zone_struct * zone) +{ + return inactive_limit(zone, VM_MIN); +} + +/** + * inactive_low - test for shortage of (free + inactive clean) pages + * @zone: zone to test, ALL_ZONES for global testing + * + * Returns the shortage as a positive number, a negative number + * if we have no shortage of (free + inactive clean) pages + */ +static inline int inactive_low(struct zone_struct * zone) +{ + return inactive_limit(zone, VM_LOW); +} + +/** + * inactive_high - less than ideal amount of (free + inactive) pages + * @zone: zone to test, ALL_ZONES for global testing + * + * Returns the shortage as a positive number, a negative number + * if we have more than enough (free + inactive) pages + */ +static inline int inactive_high(struct zone_struct * zone) +{ + return inactive_limit(zone, VM_HIGH); +} + +/* + * inactive_target - number of inactive pages we ought to have. + */ +static inline int inactive_target(void) +{ + int target; + + target = nr_active_pages + nr_inactive_dirty_pages + + nr_inactive_clean_pages; + + target /= INACTIVE_FACTOR; + + return target; +} + +#endif /* _LINUX_MM_INLINE_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/mmzone.h linux.20pre2-ac1/include/linux/mmzone.h --- linux.20pre2/include/linux/mmzone.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/mmzone.h 2002-08-14 14:41:29.000000000 +0100 @@ -25,6 +25,9 @@ } free_area_t; struct pglist_data; +struct pte_chain; + +#define MAX_CHUNKS_PER_NODE 8 /* * On machines where it is needed (eg PCs) we divide physical memory @@ -40,19 +43,27 @@ */ spinlock_t lock; unsigned long free_pages; - unsigned long pages_min, pages_low, pages_high; + unsigned long active_pages; + unsigned long inactive_dirty_pages; + unsigned long inactive_clean_pages; + unsigned long pages_min, pages_low, pages_high, pages_plenty; int need_balance; /* * free areas of different sizes */ + struct list_head active_list; + struct list_head inactive_dirty_list; + struct list_head inactive_clean_list; free_area_t free_area[MAX_ORDER]; + spinlock_t pte_chain_freelist_lock; + struct pte_chain *pte_chain_freelist; /* - * wait_table -- the array holding the hash table - * wait_table_size -- the size of the hash table array - * wait_table_shift -- wait_table_size - * == BITS_PER_LONG (1 << wait_table_bits) + * wait_table -- the array holding the hash table + * wait_table_size -- the size of the hash table array + * wait_table_shift -- wait_table_size + * == BITS_PER_LONG (1 << wait_table_bits) * * The purpose of all these is to keep track of the people * waiting for a page to become available and make them @@ -143,9 +154,6 @@ extern int numnodes; extern pg_data_t *pgdat_list; -#define memclass(pgzone, classzone) (((pgzone)->zone_pgdat == (classzone)->zone_pgdat) \ - && ((pgzone) <= (classzone))) - /* * The following two are not meant for general usage. They are here as * prototypes for the discontig memory code. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/nfsd/export.h linux.20pre2-ac1/include/linux/nfsd/export.h --- linux.20pre2/include/linux/nfsd/export.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/nfsd/export.h 2002-08-06 18:24:33.000000000 +0100 @@ -91,8 +91,7 @@ void nfsd_export_init(void); void nfsd_export_shutdown(void); void exp_readlock(void); -int exp_writelock(void); -void exp_unlock(void); +void exp_readunlock(void); struct svc_client * exp_getclient(struct sockaddr_in *sin); void exp_putclient(struct svc_client *clp); struct svc_export * exp_get(struct svc_client *clp, kdev_t dev, ino_t ino); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/parport.h linux.20pre2-ac1/include/linux/parport.h --- linux.20pre2/include/linux/parport.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/parport.h 2002-08-14 14:41:30.000000000 +0100 @@ -544,7 +544,7 @@ extern void inc_parport_count(void); /* If PC hardware is the only type supported, we can optimise a bit. */ -#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !(defined(CONFIG_PARPORT_SUNBPP) || defined(CONFIG_PARPORT_SUNBPP_MODULE)) && !defined(CONFIG_PARPORT_OTHER) +#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !(defined(CONFIG_PARPORT_SUNBPP) || defined(CONFIG_PARPORT_SUNBPP_MODULE)) && !(defined(CONFIG_PARPORT_GSC) || defined(CONFIG_PARPORT_GSC_MODULE)) && !defined(CONFIG_PARPORT_OTHER) #undef PARPORT_NEED_GENERIC_OPS #include diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/pci.h linux.20pre2-ac1/include/linux/pci.h --- linux.20pre2/include/linux/pci.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/pci.h 2002-08-14 14:41:30.000000000 +0100 @@ -493,7 +493,7 @@ void pcibios_init(void); void pcibios_fixup_bus(struct pci_bus *); -int pcibios_enable_device(struct pci_dev *); +int pcibios_enable_device(struct pci_dev *, int mask); char *pcibios_setup (char *str); /* Used only when drivers/pci/setup.c is used */ @@ -559,6 +559,7 @@ int pci_write_config_dword(struct pci_dev *dev, int where, u32 val); int pci_enable_device(struct pci_dev *dev); +int pci_enable_device_bars(struct pci_dev *dev, int mask); void pci_disable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); #define HAVE_PCI_SET_MWI @@ -648,6 +649,7 @@ { return NULL; } static inline void pci_set_master(struct pci_dev *dev) { } +static inline int pci_enable_device_bars(struct pci_dev *dev, int mask) { return -EBUSY; } static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } static inline void pci_disable_device(struct pci_dev *dev) { } static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/pci_ids.h linux.20pre2-ac1/include/linux/pci_ids.h --- linux.20pre2/include/linux/pci_ids.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/pci_ids.h 2002-08-06 17:21:08.000000000 +0100 @@ -477,19 +477,28 @@ #define PCI_DEVICE_ID_SI_635 0x0635 #define PCI_DEVICE_ID_SI_640 0x0640 #define PCI_DEVICE_ID_SI_645 0x0645 +#define PCI_DEVICE_ID_SI_646 0x0646 +#define PCI_DEVICE_ID_SI_648 0x0648 #define PCI_DEVICE_ID_SI_650 0x0650 +#define PCI_DEVICE_ID_SI_651 0x0651 +#define PCI_DEVICE_ID_SI_652 0x0652 #define PCI_DEVICE_ID_SI_730 0x0730 #define PCI_DEVICE_ID_SI_630_VGA 0x6300 #define PCI_DEVICE_ID_SI_730_VGA 0x7300 #define PCI_DEVICE_ID_SI_735 0x0735 #define PCI_DEVICE_ID_SI_740 0x0740 #define PCI_DEVICE_ID_SI_745 0x0745 +#define PCI_DEVICE_ID_SI_746 0x0746 +#define PCI_DEVICE_ID_SI_748 0x0748 #define PCI_DEVICE_ID_SI_750 0x0750 +#define PCI_DEVICE_ID_SI_751 0x0751 +#define PCI_DEVICE_ID_SI_752 0x0752 #define PCI_DEVICE_ID_SI_900 0x0900 #define PCI_DEVICE_ID_SI_5107 0x5107 #define PCI_DEVICE_ID_SI_5300 0x5300 #define PCI_DEVICE_ID_SI_5511 0x5511 #define PCI_DEVICE_ID_SI_5513 0x5513 +#define PCI_DEVICE_ID_SI_5518 0x5518 #define PCI_DEVICE_ID_SI_5571 0x5571 #define PCI_DEVICE_ID_SI_5591 0x5591 #define PCI_DEVICE_ID_SI_5597 0x5597 @@ -1622,6 +1631,7 @@ #define PCI_DEVICE_ID_INTEL_82430 0x0486 #define PCI_DEVICE_ID_INTEL_82434 0x04a3 #define PCI_DEVICE_ID_INTEL_I960 0x0960 +#define PCI_DEVICE_ID_INTEL_I960RM 0x0962 #define PCI_DEVICE_ID_INTEL_82562ET 0x1031 #define PCI_DEVICE_ID_INTEL_82559ER 0x1209 #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 @@ -1678,9 +1688,9 @@ #define PCI_DEVICE_ID_INTEL_82801E_2 0x2452 #define PCI_DEVICE_ID_INTEL_82801E_3 0x2453 #define PCI_DEVICE_ID_INTEL_82801E_9 0x2459 -#define PCI_DEVICE_ID_INTEL_82801E_11 0x245b -#define PCI_DEVICE_ID_INTEL_82801E_13 0x245d -#define PCI_DEVICE_ID_INTEL_82801E_14 0x245e +#define PCI_DEVICE_ID_INTEL_82801E_11 0x245B +#define PCI_DEVICE_ID_INTEL_82801E_14 0x245D +#define PCI_DEVICE_ID_INTEL_82801E_15 0x245E #define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480 #define PCI_DEVICE_ID_INTEL_82801CA_2 0x2482 #define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/pc_keyb.h linux.20pre2-ac1/include/linux/pc_keyb.h --- linux.20pre2/include/linux/pc_keyb.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/pc_keyb.h 2002-08-06 15:41:52.000000000 +0100 @@ -128,3 +128,6 @@ struct fasync_struct *fasync; unsigned char buf[AUX_BUF_SIZE]; }; + +extern void pckbd_blink (char); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/pnpbios.h linux.20pre2-ac1/include/linux/pnpbios.h --- linux.20pre2/include/linux/pnpbios.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/pnpbios.h 2002-08-14 14:41:31.000000000 +0100 @@ -0,0 +1,212 @@ +/* + * Include file for the interface to a PnP BIOS + * + * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de) + * PnP handler parts (c) 1998 Tom Lees + * Minor reorganizations by David Hinds + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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 _LINUX_PNPBIOS_H +#define _LINUX_PNPBIOS_H + +#ifdef __KERNEL__ + +#include +#include + +/* + * Status codes (warnings and errors) + */ +#define PNP_SUCCESS 0x00 +#define PNP_NOT_SET_STATICALLY 0x7f +#define PNP_UNKNOWN_FUNCTION 0x81 +#define PNP_FUNCTION_NOT_SUPPORTED 0x82 +#define PNP_INVALID_HANDLE 0x83 +#define PNP_BAD_PARAMETER 0x84 +#define PNP_SET_FAILED 0x85 +#define PNP_EVENTS_NOT_PENDING 0x86 +#define PNP_SYSTEM_NOT_DOCKED 0x87 +#define PNP_NO_ISA_PNP_CARDS 0x88 +#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89 +#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a +#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b +#define PNP_BUFFER_TOO_SMALL 0x8c +#define PNP_USE_ESCD_SUPPORT 0x8d +#define PNP_MESSAGE_NOT_SUPPORTED 0x8e +#define PNP_HARDWARE_ERROR 0x8f + +#define ESCD_SUCCESS 0x00 +#define ESCD_IO_ERROR_READING 0x55 +#define ESCD_INVALID 0x56 +#define ESCD_BUFFER_TOO_SMALL 0x59 +#define ESCD_NVRAM_TOO_SMALL 0x5a +#define ESCD_FUNCTION_NOT_SUPPORTED 0x81 + +/* + * Events that can be received by "get event" + */ +#define PNPEV_ABOUT_TO_CHANGE_CONFIG 0x0001 +#define PNPEV_DOCK_CHANGED 0x0002 +#define PNPEV_SYSTEM_DEVICE_CHANGED 0x0003 +#define PNPEV_CONFIG_CHANGED_FAILED 0x0004 +#define PNPEV_UNKNOWN_SYSTEM_EVENT 0xffff +/* 0x8000 through 0xfffe are OEM defined */ + +/* + * Messages that should be sent through "send message" + */ +#define PNPMSG_OK 0x00 +#define PNPMSG_ABORT 0x01 +#define PNPMSG_UNDOCK_DEFAULT_ACTION 0x40 +#define PNPMSG_POWER_OFF 0x41 +#define PNPMSG_PNP_OS_ACTIVE 0x42 +#define PNPMSG_PNP_OS_INACTIVE 0x43 +/* 0x8000 through 0xffff are OEM defined */ + +#pragma pack(1) +struct pnp_dev_node_info { + __u16 no_nodes; + __u16 max_node_size; +}; +struct pnp_docking_station_info { + __u32 location_id; + __u32 serial; + __u16 capabilities; +}; +struct pnp_isa_config_struc { + __u8 revision; + __u8 no_csns; + __u16 isa_rd_data_port; + __u16 reserved; +}; +struct escd_info_struc { + __u16 min_escd_write_size; + __u16 escd_size; + __u32 nv_storage_base; +}; +struct pnp_bios_node { + __u16 size; + __u8 handle; + __u32 eisa_id; + __u8 type_code[3]; + __u16 flags; + __u8 data[0]; +}; +#pragma pack() + +struct pnpbios_device_id +{ + char id[8]; + unsigned long driver_data; +}; + +struct pnpbios_driver { + struct list_head node; + char *name; + const struct pnpbios_device_id *id_table; /* NULL if wants all devices */ + int (*probe) (struct pci_dev *dev, const struct pnpbios_device_id *id); /* New device inserted */ + void (*remove) (struct pci_dev *dev); /* Device removed, either due to hotplug remove or module remove */ +}; + +#ifdef CONFIG_PNPBIOS + +/* exported */ +extern int pnpbios_register_driver(struct pnpbios_driver *drv); +extern void pnpbios_unregister_driver(struct pnpbios_driver *drv); + +/* non-exported */ +#define pnpbios_for_each_dev(dev) \ + for(dev = pnpbios_dev_g(pnpbios_devices.next); dev != pnpbios_dev_g(&pnpbios_devices); dev = pnpbios_dev_g(dev->global_list.next)) + + +#define pnpbios_dev_g(n) list_entry(n, struct pci_dev, global_list) + +static __inline struct pnpbios_driver *pnpbios_dev_driver(const struct pci_dev *dev) +{ + return (struct pnpbios_driver *)dev->driver; +} + +extern int pnpbios_dont_use_current_config; +extern void *pnpbios_kmalloc(size_t size, int f); +extern int pnpbios_init (void); +extern int pnpbios_proc_init (void); +extern void pnpbios_proc_exit (void); + +extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data); +extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data); +extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data); +extern int pnp_bios_get_stat_res (char *info); +extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data); +extern int pnp_bios_escd_info (struct escd_info_struc *data); +extern int pnp_bios_read_escd (char *data, u32 nvram_base); +#if needed +extern int pnp_bios_get_event (u16 *message); +extern int pnp_bios_send_message (u16 message); +extern int pnp_bios_set_stat_res (char *info); +extern int pnp_bios_apm_id_table (char *table, u16 *size); +extern int pnp_bios_write_escd (char *data, u32 nvram_base); +#endif + +/* + * a helper function which helps ensure correct pnpbios_driver + * setup and cleanup for commonly-encountered hotplug/modular cases + * + * This MUST stay in a header, as it checks for -DMODULE + */ + +static inline int pnpbios_module_init(struct pnpbios_driver *drv) +{ + int rc = pnpbios_register_driver (drv); + + if (rc > 0) + return 0; + + /* iff CONFIG_HOTPLUG and built into kernel, we should + * leave the driver around for future hotplug events. + * For the module case, a hotplug daemon of some sort + * should load a module in response to an insert event. */ +#if defined(CONFIG_HOTPLUG) && !defined(MODULE) + if (rc == 0) + return 0; +#else + if (rc == 0) + rc = -ENODEV; +#endif + + /* if we get here, we need to clean up pci driver instance + * and return some sort of error */ + pnpbios_unregister_driver (drv); + + return rc; +} + +#else /* CONFIG_PNPBIOS */ + +static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv) +{ + return 0; +} + +static __inline__ void pnpbios_unregister_driver(struct pnpbios_driver *drv) +{ + return; +} + +#endif /* CONFIG_PNPBIOS */ +#endif /* __KERNEL__ */ + +#endif /* _LINUX_PNPBIOS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/proc_fs.h linux.20pre2-ac1/include/linux/proc_fs.h --- linux.20pre2/include/linux/proc_fs.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/proc_fs.h 2002-08-14 14:41:30.000000000 +0100 @@ -123,6 +123,11 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver); /* + * speakup + */ +extern void proc_speakup_init(void); + +/* * proc_devtree.c */ extern void proc_device_tree_init(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/quotacompat.h linux.20pre2-ac1/include/linux/quotacompat.h --- linux.20pre2/include/linux/quotacompat.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/quotacompat.h 2002-08-06 18:24:34.000000000 +0100 @@ -0,0 +1,86 @@ +/* + * Definition of symbols used for backward compatible interface + */ + +#ifndef _LINUX_QUOTACOMPAT_ +#define _LINUX_QUOTACOMPAT_ + +#include +#include + +struct v1c_mem_dqblk { + __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ + __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ + __u32 dqb_curblocks; /* current block count */ + __u32 dqb_ihardlimit; /* maximum # allocated inodes */ + __u32 dqb_isoftlimit; /* preferred inode limit */ + __u32 dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +}; + +struct v1c_dqstats { + __u32 lookups; + __u32 drops; + __u32 reads; + __u32 writes; + __u32 cache_hits; + __u32 allocated_dquots; + __u32 free_dquots; + __u32 syncs; +}; + +struct v2c_mem_dqblk { + unsigned int dqb_ihardlimit; + unsigned int dqb_isoftlimit; + unsigned int dqb_curinodes; + unsigned int dqb_bhardlimit; + unsigned int dqb_bsoftlimit; + qsize_t dqb_curspace; + __kernel_time_t dqb_btime; + __kernel_time_t dqb_itime; +}; + +struct v2c_mem_dqinfo { + unsigned int dqi_bgrace; + unsigned int dqi_igrace; + unsigned int dqi_flags; + unsigned int dqi_blocks; + unsigned int dqi_free_blk; + unsigned int dqi_free_entry; +}; + +struct v2c_dqstats { + __u32 lookups; + __u32 drops; + __u32 reads; + __u32 writes; + __u32 cache_hits; + __u32 allocated_dquots; + __u32 free_dquots; + __u32 syncs; + __u32 version; +}; + +#define Q_COMP_QUOTAON 0x0100 /* enable quotas */ +#define Q_COMP_QUOTAOFF 0x0200 /* disable quotas */ +#define Q_COMP_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ + +#define Q_V1_GETQUOTA 0x0300 /* get limits and usage */ +#define Q_V1_SETQUOTA 0x0400 /* set limits and usage */ +#define Q_V1_SETUSE 0x0500 /* set usage */ +#define Q_V1_SETQLIM 0x0700 /* set limits */ +#define Q_V1_GETSTATS 0x0800 /* get collected stats */ +#define Q_V1_RSQUASH 0x1000 /* set root_squash option */ + +#define Q_V2_SETQLIM 0x0700 /* set limits */ +#define Q_V2_GETINFO 0x0900 /* get info about quotas - graces, flags... */ +#define Q_V2_SETINFO 0x0A00 /* set info about quotas */ +#define Q_V2_SETGRACE 0x0B00 /* set inode and block grace */ +#define Q_V2_SETFLAGS 0x0C00 /* set flags for quota */ +#define Q_V2_GETQUOTA 0x0D00 /* get limits and usage */ +#define Q_V2_SETQUOTA 0x0E00 /* set limits and usage */ +#define Q_V2_SETUSE 0x0F00 /* set usage */ +#define Q_V2_GETSTATS 0x1100 /* get collected stats */ + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/quota.h linux.20pre2-ac1/include/linux/quota.h --- linux.20pre2/include/linux/quota.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/quota.h 2002-08-06 18:24:34.000000000 +0100 @@ -40,30 +40,22 @@ #define _LINUX_QUOTA_ #include +#include -/* - * Convert diskblocks to blocks and the other way around. - */ -#define dbtob(num) (num << BLOCK_SIZE_BITS) -#define btodb(num) (num >> BLOCK_SIZE_BITS) +#define __DQUOT_VERSION__ "dquot_6.5.1" +#define __DQUOT_NUM_VERSION__ 6*10000+5*100+1 -/* - * Convert count of filesystem blocks to diskquota blocks, meant - * for filesystems where i_blksize != BLOCK_SIZE - */ -#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE) +typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */ +typedef __u64 qsize_t; /* Type in which we store sizes */ -/* - * Definitions for disk quotas imposed on the average user - * (big brother finally hits Linux). - * - * The following constants define the amount of time given a user - * before the soft limits are treated as hard limits (usually resulting - * in an allocation failure). The timer is started when the user crosses - * their soft limit, it is reset when they go below their soft limit. - */ -#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ -#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ +/* Size of blocks in which are counted size limits */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) + +/* Conversion routines from and to quota blocks */ +#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10)) +#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) #define MAXQUOTAS 2 #define USRQUOTA 0 /* element used for user quotas */ @@ -78,9 +70,6 @@ "undefined", \ }; -#define QUOTAFILENAME "quota" -#define QUOTAGROUP "staff" - /* * Command definitions for the 'quotactl' system call. * The commands are broken into a main command defined below @@ -91,61 +80,122 @@ #define SUBCMDSHIFT 8 #define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) -#define Q_QUOTAON 0x0100 /* enable quotas */ -#define Q_QUOTAOFF 0x0200 /* disable quotas */ -#define Q_GETQUOTA 0x0300 /* get limits and usage */ -#define Q_SETQUOTA 0x0400 /* set limits and usage */ -#define Q_SETUSE 0x0500 /* set usage */ -#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ -#define Q_SETQLIM 0x0700 /* set limits */ -#define Q_GETSTATS 0x0800 /* get collected stats */ -#define Q_RSQUASH 0x1000 /* set root_squash option */ - -/* - * The following structure defines the format of the disk quota file - * (as it appears on disk) - the file is an array of these structures - * indexed by user or group number. +#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */ +#define Q_QUOTAON 0x800002 /* turn quotas on */ +#define Q_QUOTAOFF 0x800003 /* turn quotas off */ +#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */ +#define Q_GETINFO 0x800005 /* get information about quota files */ +#define Q_SETINFO 0x800006 /* set information about quota files */ +#define Q_GETQUOTA 0x800007 /* get user quota structure */ +#define Q_SETQUOTA 0x800008 /* set user quota structure */ + +/* + * Quota structure used for communication with userspace via quotactl + * Following flags are used to specify which fields are valid */ -struct dqblk { +#define QIF_BLIMITS 1 +#define QIF_SPACE 2 +#define QIF_ILIMITS 4 +#define QIF_INODES 8 +#define QIF_BTIME 16 +#define QIF_ITIME 32 +#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS) +#define QIF_USAGE (QIF_SPACE | QIF_INODES) +#define QIF_TIMES (QIF_BTIME | QIF_ITIME) +#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES) + +struct if_dqblk { + __u64 dqb_bhardlimit; + __u64 dqb_bsoftlimit; + __u64 dqb_curspace; + __u64 dqb_ihardlimit; + __u64 dqb_isoftlimit; + __u64 dqb_curinodes; + __u64 dqb_btime; + __u64 dqb_itime; + __u32 dqb_valid; +}; + +/* + * Structure used for setting quota information about file via quotactl + * Following flags are used to specify which fields are valid + */ +#define IIF_BGRACE 1 +#define IIF_IGRACE 2 +#define IIF_FLAGS 4 +#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) + +struct if_dqinfo { + __u64 dqi_bgrace; + __u64 dqi_igrace; + __u32 dqi_flags; + __u32 dqi_valid; +}; + +#ifdef __KERNEL__ + +#include +#include +#include + +/* + * Data for one user/group kept in memory + */ +struct mem_dqblk { __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ - __u32 dqb_curblocks; /* current block count */ + qsize_t dqb_curspace; /* current used space */ __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ __u32 dqb_isoftlimit; /* preferred inode limit */ __u32 dqb_curinodes; /* current # allocated inodes */ - time_t dqb_btime; /* time limit for excessive disk use */ - time_t dqb_itime; /* time limit for excessive inode use */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive inode use */ }; /* - * Shorthand notation. + * Data for one quotafile kept in memory */ -#define dq_bhardlimit dq_dqb.dqb_bhardlimit -#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit -#define dq_curblocks dq_dqb.dqb_curblocks -#define dq_ihardlimit dq_dqb.dqb_ihardlimit -#define dq_isoftlimit dq_dqb.dqb_isoftlimit -#define dq_curinodes dq_dqb.dqb_curinodes -#define dq_btime dq_dqb.dqb_btime -#define dq_itime dq_dqb.dqb_itime +struct quota_format_type; + +struct mem_dqinfo { + struct quota_format_type *dqi_format; + int dqi_flags; + unsigned int dqi_bgrace; + unsigned int dqi_igrace; + union { + struct v1_mem_dqinfo v1_i; + struct v2_mem_dqinfo v2_i; + } u; +}; + +#define DQF_MASK 0xffff /* Mask for format specific flags */ +#define DQF_INFO_DIRTY 0x10000 /* Is info dirty? */ +#define DQF_ANY_DQUOT_DIRTY 0x20000 /* Is any dquot dirty? */ -#define dqoff(UID) ((loff_t)((UID) * sizeof (struct dqblk))) +extern inline void mark_info_dirty(struct mem_dqinfo *info) +{ + info->dqi_flags |= DQF_INFO_DIRTY; +} + +#define info_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY) + +#define info_any_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY ||\ + (info)->dqi_flags & DQF_ANY_DQUOT_DIRTY) + +#define sb_dqopt(sb) (&(sb)->s_dquot) struct dqstats { - __u32 lookups; - __u32 drops; - __u32 reads; - __u32 writes; - __u32 cache_hits; - __u32 allocated_dquots; - __u32 free_dquots; - __u32 syncs; + int lookups; + int drops; + int reads; + int writes; + int cache_hits; + int allocated_dquots; + int free_dquots; + int syncs; }; -#ifdef __KERNEL__ - -extern int nr_dquots, nr_free_dquots; -extern int dquot_root_squash; +extern struct dqstats dqstats; #define NR_DQHASH 43 /* Just an arbitrary number */ @@ -162,37 +212,113 @@ struct list_head dq_free; /* Free list element */ wait_queue_head_t dq_wait_lock; /* Pointer to waitqueue on dquot lock */ wait_queue_head_t dq_wait_free; /* Pointer to waitqueue for quota to be unused */ - int dq_count; /* Reference count */ + int dq_count; /* Use count */ + int dq_dup_ref; /* Number of duplicated refences */ /* fields after this point are cleared when invalidating */ struct super_block *dq_sb; /* superblock this applies to */ unsigned int dq_id; /* ID this applies to (uid, gid) */ kdev_t dq_dev; /* Device this applies to */ + loff_t dq_off; /* Offset of dquot on disk */ short dq_type; /* Type of quota */ short dq_flags; /* See DQ_* */ unsigned long dq_referenced; /* Number of times this dquot was referenced during its lifetime */ - struct dqblk dq_dqb; /* Diskquota usage */ + struct mem_dqblk dq_dqb; /* Diskquota usage */ }; #define NODQUOT (struct dquot *)NULL -/* - * Flags used for set_dqblk. - */ -#define SET_QUOTA 0x02 -#define SET_USE 0x04 -#define SET_QLIMIT 0x08 - #define QUOTA_OK 0 #define NO_QUOTA 1 +/* Operations which must be implemented by each quota format */ +struct quota_format_ops { + int (*check_quota_file)(struct super_block *sb, int type); /* Detect whether file is in our format */ + int (*read_file_info)(struct super_block *sb, int type); /* Read main info about file - called on quotaon() */ + int (*write_file_info)(struct super_block *sb, int type); /* Write main info about file */ + int (*free_file_info)(struct super_block *sb, int type); /* Called on quotaoff() */ + int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */ + int (*commit_dqblk)(struct dquot *dquot); /* Write (or delete) structure for one user */ +}; + +/* Operations working with dquots */ +struct dquot_operations { + void (*initialize) (struct inode *, int); + void (*drop) (struct inode *); + int (*alloc_space) (struct inode *, qsize_t, int); + int (*alloc_inode) (const struct inode *, unsigned long); + void (*free_space) (struct inode *, qsize_t); + void (*free_inode) (const struct inode *, unsigned long); + int (*transfer) (struct inode *, struct iattr *); +}; + +/* Operations handling requests from userspace */ +struct quotactl_ops { + int (*quota_on)(struct super_block *, int, int, char *); + int (*quota_off)(struct super_block *, int); + int (*quota_sync)(struct super_block *, int); + int (*get_info)(struct super_block *, int, struct if_dqinfo *); + int (*set_info)(struct super_block *, int, struct if_dqinfo *); + int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *); + int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *); + int (*get_xstate)(struct super_block *, struct fs_quota_stat *); + int (*set_xstate)(struct super_block *, unsigned int, int); + int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); + int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); +}; + +struct quota_format_type { + int qf_fmt_id; /* Quota format id */ + struct quota_format_ops *qf_ops; /* Operations of format */ + struct module *qf_owner; /* Module implementing quota format */ + struct quota_format_type *qf_next; +}; + +#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ +#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ + +struct quota_info { + unsigned int flags; /* Flags for diskquotas on this device */ + struct semaphore dqio_sem; /* lock device while I/O in progress */ + struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */ + struct file *files[MAXQUOTAS]; /* fp's to quotafiles */ + struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ + struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ +}; + +/* Inline would be better but we need to dereference super_block which is not defined yet */ +#define mark_dquot_dirty(dquot) do {\ + dquot->dq_flags |= DQ_MOD;\ + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_flags |= DQF_ANY_DQUOT_DIRTY;\ +} while (0) + +#define dquot_dirty(dquot) ((dquot)->dq_flags & DQ_MOD) + +static inline int is_enabled(struct quota_info *dqopt, int type) +{ + switch (type) { + case USRQUOTA: + return dqopt->flags & DQUOT_USR_ENABLED; + case GRPQUOTA: + return dqopt->flags & DQUOT_GRP_ENABLED; + } + return 0; +} + +#define sb_any_quota_enabled(sb) (is_enabled(sb_dqopt(sb), USRQUOTA) | is_enabled(sb_dqopt(sb), GRPQUOTA)) + +#define sb_has_quota_enabled(sb, type) (is_enabled(sb_dqopt(sb), type)) + +int register_quota_format(struct quota_format_type *fmt); +void unregister_quota_format(struct quota_format_type *fmt); + #else # /* nodep */ include __BEGIN_DECLS -long quotactl __P ((int, const char *, int, caddr_t)); +long quotactl __P ((unsigned int, const char *, int, caddr_t)); __END_DECLS #endif /* __KERNEL__ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/quotaio_v1.h linux.20pre2-ac1/include/linux/quotaio_v1.h --- linux.20pre2/include/linux/quotaio_v1.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/quotaio_v1.h 2002-08-06 18:24:34.000000000 +0100 @@ -0,0 +1,33 @@ +#ifndef _LINUX_QUOTAIO_V1_H +#define _LINUX_QUOTAIO_V1_H + +#include + +/* + * The following constants define the amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). The timer is started when the user crosses + * their soft limit, it is reset when they go below their soft limit. + */ +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +/* + * The following structure defines the format of the disk quota file + * (as it appears on disk) - the file is an array of these structures + * indexed by user or group number. + */ +struct v1_disk_dqblk { + __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ + __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ + __u32 dqb_curblocks; /* current block count */ + __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ + __u32 dqb_isoftlimit; /* preferred inode limit */ + __u32 dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive inode use */ +}; + +#define v1_dqoff(UID) ((loff_t)((UID) * sizeof (struct v1_disk_dqblk))) + +#endif /* _LINUX_QUOTAIO_V1_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/quotaio_v2.h linux.20pre2-ac1/include/linux/quotaio_v2.h --- linux.20pre2/include/linux/quotaio_v2.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/quotaio_v2.h 2002-08-06 18:24:34.000000000 +0100 @@ -0,0 +1,79 @@ +/* + * Definitions of structures for vfsv0 quota format + */ + +#ifndef _LINUX_QUOTAIO_V2_H +#define _LINUX_QUOTAIO_V2_H + +#include +#include + +/* + * Definitions of magics and versions of current quota files + */ +#define V2_INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} + +#define V2_INITQVERSIONS {\ + 0, /* USRQUOTA */\ + 0 /* GRPQUOTA */\ +} + +/* + * The following structure defines the format of the disk quota file + * (as it appears on disk) - the file is a radix tree whose leaves point + * to blocks of these structures. + */ +struct v2_disk_dqblk { + __u32 dqb_id; /* id this quota applies to */ + __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ + __u32 dqb_isoftlimit; /* preferred inode limit */ + __u32 dqb_curinodes; /* current # allocated inodes */ + __u32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ + __u32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ + __u64 dqb_curspace; /* current space occupied (in bytes) */ + __u64 dqb_btime; /* time limit for excessive disk use */ + __u64 dqb_itime; /* time limit for excessive inode use */ +}; + +/* + * Here are header structures as written on disk and their in-memory copies + */ +/* First generic header */ +struct v2_disk_dqheader { + __u32 dqh_magic; /* Magic number identifying file */ + __u32 dqh_version; /* File version */ +}; + +/* Header with type and version specific information */ +struct v2_disk_dqinfo { + __u32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ + __u32 dqi_igrace; /* Time before inode soft limit becomes hard limit */ + __u32 dqi_flags; /* Flags for quotafile (DQF_*) */ + __u32 dqi_blocks; /* Number of blocks in file */ + __u32 dqi_free_blk; /* Number of first free block in the list */ + __u32 dqi_free_entry; /* Number of block with at least one free entry */ +}; + +/* + * Structure of header of block with quota structures. It is padded to 16 bytes so + * there will be space for exactly 18 quota-entries in a block + */ +struct v2_disk_dqdbheader { + __u32 dqdh_next_free; /* Number of next block with free entry */ + __u32 dqdh_prev_free; /* Number of previous block with free entry */ + __u16 dqdh_entries; /* Number of valid entries in block */ + __u16 dqdh_pad1; + __u32 dqdh_pad2; +}; + +#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ +#define V2_DQBLKSIZE_BITS 10 +#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */ +#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */ +#define V2_DQTREEDEPTH 4 /* Depth of quota tree */ +#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */ + +#endif /* _LINUX_QUOTAIO_V2_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/quotaops.h linux.20pre2-ac1/include/linux/quotaops.h --- linux.20pre2/include/linux/quotaops.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/quotaops.h 2002-08-14 14:41:30.000000000 +0100 @@ -20,15 +20,16 @@ /* * declaration of quota_function calls in kernel. */ -extern void dquot_initialize(struct inode *inode, short type); +extern void sync_dquots_dev(kdev_t dev, int type); +extern void sync_dquots_sb(struct super_block *sb, int type); + +extern void dquot_initialize(struct inode *inode, int type); extern void dquot_drop(struct inode *inode); -extern int quota_off(struct super_block *sb, short type); -extern int sync_dquots(kdev_t dev, short type); -extern int dquot_alloc_block(struct inode *inode, unsigned long number, char prealloc); +extern int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc); extern int dquot_alloc_inode(const struct inode *inode, unsigned long number); -extern void dquot_free_block(struct inode *inode, unsigned long number); +extern void dquot_free_space(struct inode *inode, qsize_t number); extern void dquot_free_inode(const struct inode *inode, unsigned long number); extern int dquot_transfer(struct inode *inode, struct iattr *iattr); @@ -36,11 +37,15 @@ /* * Operations supported for diskquotas. */ -#define sb_any_quota_enabled(sb) ((sb)->s_dquot.flags & (DQUOT_USR_ENABLED | DQUOT_GRP_ENABLED)) +extern struct dquot_operations dquot_operations; +extern struct quotactl_ops vfs_quotactl_ops; + +#define sb_dquot_ops (&dquot_operations) +#define sb_quotactl_ops (&vfs_quotactl_ops) static __inline__ void DQUOT_INIT(struct inode *inode) { - if (!inode->i_sb) + if (!inode->i_sb) out_of_line_bug(); lock_kernel(); if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) @@ -59,50 +64,50 @@ unlock_kernel(); } -static __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) +static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) { - /* Number of used blocks is updated in alloc_block() */ - if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 1) == NO_QUOTA) { + /* Used space is updated in alloc_space() */ + if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) { unlock_kernel(); return 1; } } else - inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); + inode_add_bytes(inode, nr); unlock_kernel(); return 0; } -static __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr) +static __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) { int ret; - if (!(ret = DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr))) + if (!(ret = DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr))) mark_inode_dirty(inode); return ret; } -static __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) +static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) { - /* Number of used blocks is updated in alloc_block() */ - if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 0) == NO_QUOTA) { + /* Used space is updated in alloc_space() */ + if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) { unlock_kernel(); return 1; } } else - inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); + inode_add_bytes(inode, nr); unlock_kernel(); return 0; } -static __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr) +static __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) { int ret; - if (!(ret = DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr))) + if (!(ret = DQUOT_ALLOC_SPACE_NODIRTY(inode, nr))) mark_inode_dirty(inode); return ret; } @@ -121,19 +126,19 @@ return 0; } -static __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr) +static __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); if (sb_any_quota_enabled(inode->i_sb)) - inode->i_sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize)); + inode->i_sb->dq_op->free_space(inode, nr); else - inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9); + inode_sub_bytes(inode, nr); unlock_kernel(); } -static __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr) +static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) { - DQUOT_FREE_BLOCK_NODIRTY(inode, nr); + DQUOT_FREE_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); } @@ -159,63 +164,85 @@ return 0; } -#define DQUOT_SYNC(dev) sync_dquots(dev, -1) -#define DQUOT_OFF(sb) quota_off(sb, -1) +#define DQUOT_SYNC_DEV(dev) sync_dquots_dev(dev, -1) +#define DQUOT_SYNC_SB(sb) sync_dquots_sb(sb, -1) + +static __inline__ int DQUOT_OFF(struct super_block *sb) +{ + int ret = -ENOSYS; + + lock_kernel(); + if (sb->s_qcop && sb->s_qcop->quota_off) + ret = sb->s_qcop->quota_off(sb, -1); + unlock_kernel(); + return ret; +} #else /* * NO-OP when quota not configured. */ +#define sb_dquot_ops (NULL) +#define sb_quotactl_ops (NULL) #define DQUOT_INIT(inode) do { } while(0) #define DQUOT_DROP(inode) do { } while(0) #define DQUOT_ALLOC_INODE(inode) (0) #define DQUOT_FREE_INODE(inode) do { } while(0) -#define DQUOT_SYNC(dev) do { } while(0) +#define DQUOT_SYNC_DEV(dev) do { } while(0) +#define DQUOT_SYNC_SB(sb) do { } while(0) #define DQUOT_OFF(sb) do { } while(0) #define DQUOT_TRANSFER(inode, iattr) (0) -extern __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) +extern __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); - inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); + inode_add_bytes(inode, nr); unlock_kernel(); return 0; } -extern __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr) +extern __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) { - DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr); + DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); return 0; } -extern __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) +extern __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); - inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); + inode_add_bytes(inode, nr); unlock_kernel(); return 0; } -extern __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr) +extern __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) { - DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr); + DQUOT_ALLOC_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); return 0; } -extern __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr) +extern __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { lock_kernel(); - inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9); + inode_sub_bytes(inode, nr); unlock_kernel(); } -extern __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr) +extern __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) { - DQUOT_FREE_BLOCK_NODIRTY(inode, nr); + DQUOT_FREE_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); } #endif /* CONFIG_QUOTA */ + +#define DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr) DQUOT_PREALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_PREALLOC_BLOCK(inode, nr) DQUOT_PREALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr) DQUOT_ALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_ALLOC_BLOCK(inode, nr) DQUOT_ALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_FREE_BLOCK_NODIRTY(inode, nr) DQUOT_FREE_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) +#define DQUOT_FREE_BLOCK(inode, nr) DQUOT_FREE_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits) + #endif /* _LINUX_QUOTAOPS_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/raid/md_compatible.h linux.20pre2-ac1/include/linux/raid/md_compatible.h --- linux.20pre2/include/linux/raid/md_compatible.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/raid/md_compatible.h 2002-08-14 14:41:30.000000000 +0100 @@ -99,7 +99,6 @@ #define md_test_and_clear_bit test_and_clear_bit /* 018 */ -#define md_atomic_read atomic_read #define md_atomic_set atomic_set /* 019 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/rwsem.h linux.20pre2-ac1/include/linux/rwsem.h --- linux.20pre2/include/linux/rwsem.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/rwsem.h 2002-08-14 14:41:29.000000000 +0100 @@ -2,6 +2,8 @@ * * Written by David Howells (dhowells@redhat.com). * Derived from asm-i386/semaphore.h + * + * Trylock by Brian Watson (Brian.J.Watson@compaq.com). */ #ifndef _LINUX_RWSEM_H @@ -46,6 +48,18 @@ } /* + * trylock for reading -- returns 1 if successful, 0 if contention + */ +static inline int down_read_trylock(struct rw_semaphore *sem) +{ + int ret; + rwsemtrace(sem,"Entering down_read_trylock"); + ret = __down_read_trylock(sem); + rwsemtrace(sem,"Leaving down_read_trylock"); + return ret; +} + +/* * lock for writing */ static inline void down_write(struct rw_semaphore *sem) @@ -56,6 +70,18 @@ } /* + * trylock for writing -- returns 1 if successful, 0 if contention + */ +static inline int down_write_trylock(struct rw_semaphore *sem) +{ + int ret; + rwsemtrace(sem,"Entering down_write_trylock"); + ret = __down_write_trylock(sem); + rwsemtrace(sem,"Leaving down_write_trylock"); + return ret; +} + +/* * release a read lock */ static inline void up_read(struct rw_semaphore *sem) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/rwsem-spinlock.h linux.20pre2-ac1/include/linux/rwsem-spinlock.h --- linux.20pre2/include/linux/rwsem-spinlock.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/rwsem-spinlock.h 2002-08-14 14:41:29.000000000 +0100 @@ -3,6 +3,8 @@ * Copyright (c) 2001 David Howells (dhowells@redhat.com). * - Derived partially from ideas by Andrea Arcangeli * - Derived also from comments by Linus + * + * Trylock by Brian Watson (Brian.J.Watson@compaq.com). */ #ifndef _LINUX_RWSEM_SPINLOCK_H @@ -54,7 +56,9 @@ extern void FASTCALL(init_rwsem(struct rw_semaphore *sem)); extern void FASTCALL(__down_read(struct rw_semaphore *sem)); +extern int FASTCALL(__down_read_trylock(struct rw_semaphore *sem)); extern void FASTCALL(__down_write(struct rw_semaphore *sem)); +extern int FASTCALL(__down_write_trylock(struct rw_semaphore *sem)); extern void FASTCALL(__up_read(struct rw_semaphore *sem)); extern void FASTCALL(__up_write(struct rw_semaphore *sem)); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/sched.h linux.20pre2-ac1/include/linux/sched.h --- linux.20pre2/include/linux/sched.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/sched.h 2002-08-14 14:41:29.000000000 +0100 @@ -73,16 +73,16 @@ #define CT_TO_SECS(x) ((x) / HZ) #define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) -extern int nr_running, nr_threads; +extern int nr_threads; extern int last_pid; +extern unsigned long nr_running(void); +extern unsigned long nr_uninterruptible(void); #include #include #include #include -#ifdef __KERNEL__ #include -#endif #include @@ -119,12 +119,6 @@ #define SCHED_FIFO 1 #define SCHED_RR 2 -/* - * This is an additional bit set when we want to - * yield the CPU for one re-schedule.. - */ -#define SCHED_YIELD 0x10 - struct sched_param { int sched_priority; }; @@ -142,17 +136,23 @@ * a separate lock). */ extern rwlock_t tasklist_lock; -extern spinlock_t runqueue_lock; extern spinlock_t mmlist_lock; +typedef struct task_struct task_t; + extern void sched_init(void); -extern void init_idle(void); +extern void init_idle(task_t *idle, int cpu); +extern int idle_cpu(int cpu); extern void show_state(void); extern void cpu_init (void); extern void trap_init(void); extern void update_process_times(int user); -extern void update_one_process(struct task_struct *p, unsigned long user, +extern void update_one_process(task_t *p, unsigned long user, unsigned long system, int cpu); +extern void scheduler_tick(int user_tick, int system); +extern void migration_init(void); +extern unsigned long cache_decay_ticks; +extern int set_user(uid_t new_ruid, int dumpclear); #define MAX_SCHEDULE_TIMEOUT LONG_MAX extern signed long FASTCALL(schedule_timeout(signed long timeout)); @@ -164,6 +164,36 @@ extern int current_is_keventd(void); /* + * Priority of a process goes from 0..MAX_PRIO-1, valid RT + * priority is 0..MAX_RT_PRIO-1, and SCHED_OTHER tasks are + * in the range MAX_RT_PRIO..MAX_PRIO-1. Priority values + * are inverted: lower p->prio value means higher priority. + * + * The MAX_RT_USER_PRIO value allows the actual maximum + * RT priority to be separate from the value exported to + * user-space. This allows kernel threads to set their + * priority to a value higher than any user task. Note: + * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO. + */ + +#define MAX_USER_RT_PRIO 100 +#define MAX_RT_PRIO MAX_USER_RT_PRIO + +#define MAX_PRIO (MAX_RT_PRIO + 40) + +/* + * The maximum RT priority is configurable. If the resulting + * bitmap is 160-bits , we can use a hand-coded routine which + * is optimal. Otherwise, we fall back on a generic routine for + * finding the first set bit from an arbitrarily-sized bitmap. + */ +#if MAX_PRIO < 160 && MAX_PRIO > 127 +#define sched_find_first_bit(map) _sched_find_first_bit(map) +#else +#define sched_find_first_bit(map) find_first_bit(map, MAX_PRIO) +#endif + +/* * The default fd array needs to be at least BITS_PER_LONG, * as this is the granularity returned by copy_fdset(). */ @@ -229,7 +259,7 @@ unsigned long rss, total_vm, locked_vm; unsigned long def_flags; unsigned long cpu_vm_mask; - unsigned long swap_address; + unsigned long rlimit_rss; unsigned dumpable:1; @@ -248,6 +278,7 @@ mmap_sem: __RWSEM_INITIALIZER(name.mmap_sem), \ page_table_lock: SPIN_LOCK_UNLOCKED, \ mmlist: LIST_HEAD_INIT(name.mmlist), \ + rlimit_rss: RLIM_INFINITY, \ } struct signal_struct { @@ -284,6 +315,8 @@ extern struct user_struct root_user; #define INIT_USER (&root_user) +typedef struct prio_array prio_array_t; + struct task_struct { /* * offsets of these are hardcoded elsewhere - touch with care @@ -301,36 +334,25 @@ int lock_depth; /* Lock depth */ -/* - * offset 32 begins here on 32-bit platforms. We keep - * all fields in a single cacheline that are needed for - * the goodness() loop in schedule(). - */ - long counter; - long nice; - unsigned long policy; - struct mm_struct *mm; - int processor; - /* - * cpus_runnable is ~0 if the process is not running on any - * CPU. It's (1 << cpu) if it's running on a CPU. This mask - * is updated under the runqueue lock. - * - * To determine whether a process might run on a CPU, this - * mask is AND-ed with cpus_allowed. - */ - unsigned long cpus_runnable, cpus_allowed; /* - * (only the 'next' pointer fits into the cacheline, but - * that's just fine.) + * offset 32 begins here on 32-bit platforms. */ - struct list_head run_list; - unsigned long sleep_time; + unsigned int cpu; + int prio, static_prio; + list_t run_list; + prio_array_t *array; + + unsigned long sleep_avg; + unsigned long sleep_timestamp; + + unsigned long policy; + unsigned long cpus_allowed; + unsigned int time_slice; + + task_t *next_task, *prev_task; + + struct mm_struct *mm, *active_mm; - struct task_struct *next_task, *prev_task; - struct mm_struct *active_mm; - struct list_head local_pages; - unsigned int allocation_order, nr_local_pages; /* task state */ struct linux_binfmt *binfmt; @@ -351,12 +373,12 @@ * older sibling, respectively. (p->father can be replaced with * p->p_pptr->pid) */ - struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; + task_t *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; struct list_head thread_group; /* PID hash table linkage. */ - struct task_struct *pidhash_next; - struct task_struct **pidhash_pprev; + task_t *pidhash_next; + task_t **pidhash_pprev; wait_queue_head_t wait_chldexit; /* for wait4() */ struct completion *vfork_done; /* for vfork() */ @@ -454,11 +476,19 @@ */ #define _STK_LIM (8*1024*1024) -#define DEF_COUNTER (10*HZ/100) /* 100 ms time slice */ -#define MAX_COUNTER (20*HZ/100) -#define DEF_NICE (0) +#if CONFIG_SMP +extern void set_cpus_allowed(task_t *p, unsigned long new_mask); +#else +#define set_cpus_allowed(p, new_mask) do { } while (0) +#endif -extern void yield(void); +extern void set_user_nice(task_t *p, long nice); +extern int task_prio(task_t *p); +extern int task_nice(task_t *p); +extern int idle_cpu(int cpu); + +asmlinkage long sys_sched_yield(void); +#define yield() sys_sched_yield() /* * The default (Linux) execution domain. @@ -477,14 +507,14 @@ addr_limit: KERNEL_DS, \ exec_domain: &default_exec_domain, \ lock_depth: -1, \ - counter: DEF_COUNTER, \ - nice: DEF_NICE, \ + prio: MAX_PRIO-20, \ + static_prio: MAX_PRIO-20, \ policy: SCHED_OTHER, \ + cpus_allowed: -1, \ mm: NULL, \ active_mm: &init_mm, \ - cpus_runnable: -1, \ - cpus_allowed: -1, \ run_list: LIST_HEAD_INIT(tsk.run_list), \ + time_slice: HZ, \ next_task: &tsk, \ prev_task: &tsk, \ p_opptr: &tsk, \ @@ -518,24 +548,24 @@ #endif union task_union { - struct task_struct task; + task_t task; unsigned long stack[INIT_TASK_SIZE/sizeof(long)]; }; extern union task_union init_task_union; extern struct mm_struct init_mm; -extern struct task_struct *init_tasks[NR_CPUS]; +extern task_t *init_tasks[NR_CPUS]; /* PID hashing. (shouldnt this be dynamic?) */ #define PIDHASH_SZ (4096 >> 2) -extern struct task_struct *pidhash[PIDHASH_SZ]; +extern task_t *pidhash[PIDHASH_SZ]; #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) -static inline void hash_pid(struct task_struct *p) +static inline void hash_pid(task_t *p) { - struct task_struct **htable = &pidhash[pid_hashfn(p->pid)]; + task_t **htable = &pidhash[pid_hashfn(p->pid)]; if((p->pidhash_next = *htable) != NULL) (*htable)->pidhash_pprev = &p->pidhash_next; @@ -543,16 +573,16 @@ p->pidhash_pprev = htable; } -static inline void unhash_pid(struct task_struct *p) +static inline void unhash_pid(task_t *p) { if(p->pidhash_next) p->pidhash_next->pidhash_pprev = p->pidhash_pprev; *p->pidhash_pprev = p->pidhash_next; } -static inline struct task_struct *find_task_by_pid(int pid) +static inline task_t *find_task_by_pid(int pid) { - struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)]; + task_t *p, **htable = &pidhash[pid_hashfn(pid)]; for(p = *htable; p && p->pid != pid; p = p->pidhash_next) ; @@ -560,19 +590,6 @@ return p; } -#define task_has_cpu(tsk) ((tsk)->cpus_runnable != ~0UL) - -static inline void task_set_cpu(struct task_struct *tsk, unsigned int cpu) -{ - tsk->processor = cpu; - tsk->cpus_runnable = 1UL << cpu; -} - -static inline void task_release_cpu(struct task_struct *tsk) -{ - tsk->cpus_runnable = ~0UL; -} - /* per-UID process charging. */ extern struct user_struct * alloc_uid(uid_t); extern void free_uid(struct user_struct *); @@ -599,47 +616,51 @@ extern void FASTCALL(interruptible_sleep_on(wait_queue_head_t *q)); extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); -extern int FASTCALL(wake_up_process(struct task_struct * tsk)); +extern int FASTCALL(wake_up_process(task_t * tsk)); +extern void FASTCALL(wake_up_forked_process(task_t * tsk)); +extern void FASTCALL(sched_exit(task_t * p)); #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1) #define wake_up_nr(x, nr) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr) #define wake_up_all(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0) -#define wake_up_sync(x) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1) -#define wake_up_sync_nr(x, nr) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr) #define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE, 1) #define wake_up_interruptible_nr(x, nr) __wake_up((x),TASK_INTERRUPTIBLE, nr) #define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE, 0) -#define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, 1) -#define wake_up_interruptible_sync_nr(x, nr) __wake_up_sync((x),TASK_INTERRUPTIBLE, nr) +#ifdef CONFIG_SMP +#define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, 1) +#else +#define wake_up_interruptible_sync(x) __wake_up((x),TASK_INTERRUPTIBLE, 1) +#endif + asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); extern int in_group_p(gid_t); extern int in_egroup_p(gid_t); extern void proc_caches_init(void); -extern void flush_signals(struct task_struct *); -extern void flush_signal_handlers(struct task_struct *); +extern void flush_signals(task_t *); +extern void flush_signal_handlers(task_t *); extern void sig_exit(int, int, struct siginfo *); extern int dequeue_signal(sigset_t *, siginfo_t *); extern void block_all_signals(int (*notifier)(void *priv), void *priv, sigset_t *mask); extern void unblock_all_signals(void); -extern int send_sig_info(int, struct siginfo *, struct task_struct *); -extern int force_sig_info(int, struct siginfo *, struct task_struct *); +extern int send_sig_info(int, struct siginfo *, task_t *); +extern int force_sig_info(int, struct siginfo *, task_t *); extern int kill_pg_info(int, struct siginfo *, pid_t); extern int kill_sl_info(int, struct siginfo *, pid_t); extern int kill_proc_info(int, struct siginfo *, pid_t); -extern void notify_parent(struct task_struct *, int); -extern void do_notify_parent(struct task_struct *, int); -extern void force_sig(int, struct task_struct *); -extern int send_sig(int, struct task_struct *, int); +extern void notify_parent(task_t *, int); +extern void do_notify_parent(task_t *, int); +extern void force_sig(int, task_t *); +extern int send_sig(int, task_t *, int); extern int kill_pg(pid_t, int, int); extern int kill_sl(pid_t, int, int); extern int kill_proc(pid_t, int, int); extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *); extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long); -static inline int signal_pending(struct task_struct *p) +static inline int signal_pending(task_t *p) { return (p->sigpending != 0); } @@ -678,7 +699,7 @@ This is required every time the blocked sigset_t changes. All callers should have t->sigmask_lock. */ -static inline void recalc_sigpending(struct task_struct *t) +static inline void recalc_sigpending(task_t *t) { t->sigpending = has_pending_signals(&t->pending.signal, &t->blocked); } @@ -785,16 +806,17 @@ extern int expand_fdset(struct files_struct *, int nr); extern void free_fdset(fd_set *, int); -extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); +extern int copy_thread(int, unsigned long, unsigned long, unsigned long, task_t *, struct pt_regs *); extern void flush_thread(void); extern void exit_thread(void); -extern void exit_mm(struct task_struct *); -extern void exit_files(struct task_struct *); -extern void exit_sighand(struct task_struct *); +extern void exit_mm(task_t *); +extern void exit_files(task_t *); +extern void exit_sighand(task_t *); extern void reparent_to_init(void); extern void daemonize(void); +extern task_t *child_reaper; extern int do_execve(char *, char **, char **, struct pt_regs *); extern int do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long); @@ -803,6 +825,9 @@ extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); +extern void wait_task_inactive(task_t * p); +extern void kick_if_running(task_t * p); + #define __wait_event(wq, condition) \ do { \ wait_queue_t __wait; \ @@ -884,27 +909,12 @@ for (task = next_thread(current) ; task != current ; task = next_thread(task)) #define next_thread(p) \ - list_entry((p)->thread_group.next, struct task_struct, thread_group) + list_entry((p)->thread_group.next, task_t, thread_group) #define thread_group_leader(p) (p->pid == p->tgid) -static inline void del_from_runqueue(struct task_struct * p) -{ - nr_running--; - p->sleep_time = jiffies; - list_del(&p->run_list); - p->run_list.next = NULL; -} - -static inline int task_on_runqueue(struct task_struct *p) +static inline void unhash_process(task_t *p) { - return (p->run_list.next != NULL); -} - -static inline void unhash_process(struct task_struct *p) -{ - if (task_on_runqueue(p)) - out_of_line_bug(); write_lock_irq(&tasklist_lock); nr_threads--; unhash_pid(p); @@ -914,12 +924,12 @@ } /* Protects ->fs, ->files, ->mm, and synchronises with wait4(). Nests inside tasklist_lock */ -static inline void task_lock(struct task_struct *p) +static inline void task_lock(task_t *p) { spin_lock(&p->alloc_lock); } -static inline void task_unlock(struct task_struct *p) +static inline void task_unlock(task_t *p) { spin_unlock(&p->alloc_lock); } @@ -943,17 +953,31 @@ return res; } -static inline int need_resched(void) +static inline void set_need_resched(void) { - return (unlikely(current->need_resched)); + current->need_resched = 1; } -extern void __cond_resched(void); -static inline void cond_resched(void) +static inline void clear_need_resched(void) { - if (need_resched()) - __cond_resched(); + current->need_resched = 0; +} + +static inline void set_tsk_need_resched(struct task_struct *tsk) +{ + tsk->need_resched = 1; +} + +static inline void clear_tsk_need_resched(struct task_struct *tsk) +{ + tsk->need_resched = 0; +} + +static inline int need_resched(void) +{ + return unlikely(current->need_resched); } #endif /* __KERNEL__ */ + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/serialP.h linux.20pre2-ac1/include/linux/serialP.h --- linux.20pre2/include/linux/serialP.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/serialP.h 2002-08-14 14:41:30.000000000 +0100 @@ -83,6 +83,7 @@ long pgrp; /* pgrp of opening process */ struct circ_buf xmit; spinlock_t xmit_lock; + spinlock_t irq_spinlock; u8 *iomem_base; u16 iomem_reg_shift; int io_type; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/serio.h linux.20pre2-ac1/include/linux/serio.h --- linux.20pre2/include/linux/serio.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/serio.h 2002-08-06 15:41:52.000000000 +0100 @@ -87,6 +87,7 @@ #define SERIO_XT 0x00000000UL #define SERIO_8042 0x01000000UL #define SERIO_RS232 0x02000000UL +#define SERIO_HIL_MLC 0x03000000UL #define SERIO_PROTO 0xFFUL #define SERIO_MSC 0x01 @@ -108,6 +109,7 @@ #define SERIO_STOWAWAY 0x20 #define SERIO_H3600 0x21 #define SERIO_PS2SER 0x22 +#define SERIO_HIL 0x25 #define SERIO_ID 0xff00UL #define SERIO_EXTRA 0xff0000UL diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/smp_balance.h linux.20pre2-ac1/include/linux/smp_balance.h --- linux.20pre2/include/linux/smp_balance.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/smp_balance.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,10 @@ +#ifndef _LINUX_SMP_BALANCE_H +#define _LINUX_SMP_BALANCE_H + +#ifdef ARCH_HAS_SMP_BALANCE +#include +#else +#define arch_load_balance(x,y) 0 +#endif + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/smp.h linux.20pre2-ac1/include/linux/smp.h --- linux.20pre2/include/linux/smp.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/smp.h 2002-08-14 14:41:29.000000000 +0100 @@ -86,6 +86,13 @@ #define cpu_number_map(cpu) 0 #define smp_call_function(func,info,retry,wait) ({ 0; }) #define cpu_online_map 1 - +static inline void smp_send_reschedule(int cpu) { } +static inline void smp_send_reschedule_all(void) { } #endif + +/* + * Common definitions: + */ +#define cpu() smp_processor_id() + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/som.h linux.20pre2-ac1/include/linux/som.h --- linux.20pre2/include/linux/som.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/som.h 2002-08-06 18:24:34.000000000 +0100 @@ -0,0 +1,154 @@ +#ifndef _LINUX_SOM_H +#define _LINUX_SOM_H + +/* File format definition for SOM executables / shared libraries */ + +/* we need struct timespec */ +#include + +#define SOM_PAGESIZE 4096 + +/* this is the SOM header */ +struct som_hdr { + short system_id; /* magic number - system */ + short a_magic; /* magic number - file type */ + unsigned int version_id; /* versiod ID: YYMMDDHH */ + struct timespec file_time; /* system clock */ + unsigned int entry_space; /* space for entry point */ + unsigned int entry_subspace; /* subspace for entry point */ + unsigned int entry_offset; /* offset of entry point */ + unsigned int aux_header_location; /* auxiliary header location */ + unsigned int aux_header_size; /* auxiliary header size */ + unsigned int som_length; /* length of entire SOM */ + unsigned int presumed_dp; /* compiler's DP value */ + unsigned int space_location; /* space dictionary location */ + unsigned int space_total; /* number of space entries */ + unsigned int subspace_location; /* subspace entries location */ + unsigned int subspace_total; /* number of subspace entries */ + unsigned int loader_fixup_location; /* MPE/iX loader fixup */ + unsigned int loader_fixup_total; /* number of fixup records */ + unsigned int space_strings_location; /* (sub)space names */ + unsigned int space_strings_size; /* size of strings area */ + unsigned int init_array_location; /* reserved */ + unsigned int init_array_total; /* reserved */ + unsigned int compiler_location; /* module dictionary */ + unsigned int compiler_total; /* number of modules */ + unsigned int symbol_location; /* symbol dictionary */ + unsigned int symbol_total; /* number of symbols */ + unsigned int fixup_request_location; /* fixup requests */ + unsigned int fixup_request_total; /* number of fixup requests */ + unsigned int symbol_strings_location;/* module & symbol names area */ + unsigned int symbol_strings_size; /* size of strings area */ + unsigned int unloadable_sp_location; /* unloadable spaces location */ + unsigned int unloadable_sp_size; /* size of data */ + unsigned int checksum; +}; + +/* values for system_id */ + +#define SOM_SID_PARISC_1_0 0x020b +#define SOM_SID_PARISC_1_1 0x0210 +#define SOM_SID_PARISC_2_0 0x0214 + +/* values for a_magic */ + +#define SOM_LIB_EXEC 0x0104 +#define SOM_RELOCATABLE 0x0106 +#define SOM_EXEC_NONSHARE 0x0107 +#define SOM_EXEC_SHARE 0x0108 +#define SOM_EXEC_DEMAND 0x010B +#define SOM_LIB_DYN 0x010D +#define SOM_LIB_SHARE 0x010E +#define SOM_LIB_RELOC 0x0619 + +/* values for version_id. Decimal not hex, yes. Grr. */ + +#define SOM_ID_OLD 85082112 +#define SOM_ID_NEW 87102412 + +struct aux_id { + unsigned int mandatory :1; /* the linker must understand this */ + unsigned int copy :1; /* Must be copied by the linker */ + unsigned int append :1; /* Must be merged by the linker */ + unsigned int ignore :1; /* Discard section if unknown */ + unsigned int reserved :12; + unsigned int type :16; /* Header type */ + unsigned int length; /* length of _following_ data */ +}; + +/* The Exec Auxiliary Header. Called The HP-UX Header within HP apparently. */ +struct som_exec_auxhdr { + struct aux_id som_auxhdr; + int exec_tsize; /* Text size in bytes */ + int exec_tmem; /* Address to load text at */ + int exec_tfile; /* Location of text in file */ + int exec_dsize; /* Data size in bytes */ + int exec_dmem; /* Address to load data at */ + int exec_dfile; /* Location of data in file */ + int exec_bsize; /* Uninitialised data (bss) */ + int exec_entry; /* Address to start executing */ + int exec_flags; /* loader flags */ + int exec_bfill; /* initialisation value for bss */ +}; + +/* Oh, the things people do to avoid casts. Shame it'll break with gcc's + * new aliasing rules really. + */ +union name_pt { + char * n_name; + unsigned int n_strx; +}; + +/* The Space Dictionary */ +struct space_dictionary_record { + union name_pt name; /* index to subspace name */ + unsigned int is_loadable :1; /* loadable */ + unsigned int is_defined :1; /* defined within file */ + unsigned int is_private :1; /* not sharable */ + unsigned int has_intermediate_code :1; /* contains intermediate code */ + unsigned int is_tspecific :1; /* thread specific */ + unsigned int reserved :11; /* for future expansion */ + unsigned int sort_key :8; /* for linker */ + unsigned int reserved2 :8; /* for future expansion */ + + int space_number; /* index */ + int subspace_index; /* index into subspace dict */ + unsigned int subspace_quantity; /* number of subspaces */ + int loader_fix_index; /* for loader */ + unsigned int loader_fix_quantity; /* for loader */ + int init_pointer_index; /* data pointer array index */ + unsigned int init_pointer_quantity; /* number of data pointers */ +}; + +/* The Subspace Dictionary */ +struct subspace_dictionary_record { + int space_index; + unsigned int access_control_bits :7; + unsigned int memory_resident :1; + unsigned int dup_common :1; + unsigned int is_common :1; + unsigned int quadrant :2; + unsigned int initially_frozen :1; + unsigned int is_first :1; + unsigned int code_only :1; + unsigned int sort_key :8; + unsigned int replicate_init :1; + unsigned int continuation :1; + unsigned int is_tspecific :1; + unsigned int is_comdat :1; + unsigned int reserved :4; + + int file_loc_init_value; + unsigned int initialization_length; + unsigned int subspace_start; + unsigned int subspace_length; + + unsigned int reserved2 :5; + unsigned int alignment :27; + + union name_pt name; + int fixup_request_index; + unsigned int fixup_request_quantity; +}; + +#endif /* _LINUX_SOM_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/sonypi.h linux.20pre2-ac1/include/linux/sonypi.h --- linux.20pre2/include/linux/sonypi.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/sonypi.h 2002-08-06 18:24:33.000000000 +0100 @@ -75,6 +75,7 @@ #define SONYPI_EVENT_LID_OPENED 37 #define SONYPI_EVENT_BLUETOOTH_ON 38 #define SONYPI_EVENT_BLUETOOTH_OFF 39 +#define SONYPI_EVENT_HELP_PRESSED 40 /* get/set brightness */ #define SONYPI_IOCGBRT _IOR('v', 0, __u8) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/speakup.h linux.20pre2-ac1/include/linux/speakup.h --- linux.20pre2/include/linux/speakup.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/linux/speakup.h 2002-08-13 22:28:55.000000000 +0100 @@ -0,0 +1,221 @@ +#ifndef __SPEAKUP_H +#define __SPEAKUP_H + +#include +struct serial_state; +struct kbd_struct; + +#define QUICK_QUIET 0x00 /* flush buffer and shut up immediately! */ +#define LINE_QUIET 0x01 /* flush buffer up to next NULL/cr and continue */ +#define FULL_QUIET 0x03 /* process commands in buffer and shut up */ +#define SAY_CHAR 0x04 /* say this character */ +#define SAY_PREV_CHAR 0x05 /* say character left of this char */ +#define SAY_NEXT_CHAR 0x06 /* say char right of this char */ +#define SAY_WORD 0x07 /* say this word under reading cursor */ +#define SAY_PREV_WORD 0x08 +#define SAY_NEXT_WORD 0x09 +#define SAY_LINE 0x0a /* say this line */ +#define SAY_PREV_LINE 0x0b /* say line above this line */ +#define SAY_NEXT_LINE 0x0c +#define TOP_EDGE 0x0d /* move to top edge of screen */ +#define BOTTOM_EDGE 0x0e +#define LEFT_EDGE 0x0f +#define RIGHT_EDGE 0x10 +#define SAY_PHONETIC_CHAR 0x11 /* say this character phonetically */ +#define SPELL_WORD 0x12 /* spell this word letter by letter */ +#define SPELL_PHONETIC_WORD 0x13 +#define SAY_SCREEN 0x14 +#define SAY_WINDOW 0x15 +#define SET_SPEED 0x16 +#define SET_PITCH 0x17 +#define SET_PUNCTUATION 0x18 +#define SET_VOICE 0x19 +#define SET_TONE 0x1a +#define SAY_POSITION 0x1b +#define SPEECH_OFF 0x1c +#define SAY_ATTRIBUTES 0x1d +#define SPEAKUP_PARKED 0x1e +#define INS_TOGGLE 0x1f +#define SAY_FROM_TOP 0x20 +#define SAY_TO_BOTTOM 0x21 +#define SAY_FROM_LEFT 0x22 +#define SAY_TO_RIGHT 0x23 +#define SAY_CHAR_NUM 0x24 +#define SPEECH_KILL 0x25 +#define SPEAKUP_CURSORING 0x26 +#define SPEAKUP_CUT 0x27 +#define SPEAKUP_PASTE 0x28 +/* our basic punctuation levels as array indecies */ +#define NONE 0x30 /* no punctuation spoken */ +#define SOME 0x31 /* some punctuation spoken */ +#define MOST 0x32 /* most punctuation spoken */ +#define ALL 0x33 /* you guessed it. */ + +/* let's develop a structure for keeping our goodies in. */ +struct spk_t { + unsigned char reading_attr; + unsigned char old_attr; + char parked; + char shut_up; + char sound; + unsigned long reading_x, cursor_x, old_cursor_x; + unsigned long reading_y, cursor_y, old_cursor_y; + unsigned long reading_pos, cursor_pos, old_cursor_pos; +}; + +/* now some defines to make these easier to use. */ +#define spk_shut_up speakup_console[currcons]->shut_up +#define spk_killed (speakup_console[currcons]->shut_up & 0x40) +#define spk_x speakup_console[currcons]->reading_x +#define spk_cx speakup_console[currcons]->cursor_x +#define spk_o_cx speakup_console[currcons]->old_cursor_x +#define spk_y speakup_console[currcons]->reading_y +#define spk_cy speakup_console[currcons]->cursor_y +#define spk_o_cy speakup_console[currcons]->old_cursor_y +#define spk_pos (speakup_console[currcons]->reading_pos) +#define spk_cp speakup_console[currcons]->cursor_pos +#define spk_o_cp speakup_console[currcons]->old_cursor_pos +#define spk_attr speakup_console[currcons]->reading_attr +#define spk_old_attr speakup_console[currcons]->old_attr +#define spk_parked speakup_console[currcons]->parked +#define spk_sound speakup_console[currcons]->sound + +/* how about some prototypes! */ +extern void speakup_shut_up(unsigned int); +extern void say_attributes(int); +extern void say_curr_char(unsigned int); +extern void say_phonetic_char(unsigned int); +extern void say_prev_char(unsigned int); +extern void say_next_char(unsigned int); +extern void say_curr_word(unsigned int); +extern void say_prev_word(unsigned int); +extern void say_next_word(unsigned int); +extern void spell_word(unsigned int); +extern void say_curr_line(unsigned int); +extern void say_prev_line(unsigned int); +extern void say_next_line(unsigned int); +extern void say_screen(unsigned int); +extern void top_edge(unsigned int); +extern void bottom_edge(unsigned int); +extern void left_edge(unsigned int); +extern void right_edge(unsigned int); +extern void say_position(unsigned int); +extern void say_char_num(unsigned int); +extern void speakup_off(unsigned int); +extern void speakup_kill(unsigned int); +extern void say_from_top(unsigned int); +extern void say_to_bottom(unsigned int); +extern void say_from_left(unsigned int); +extern void say_to_right(unsigned int); +extern void speakup_status(unsigned int); +extern void function_announce(unsigned int); +extern void speakup_open(unsigned int); +extern void speakup_date(unsigned int); +extern void speakup_precheck(unsigned int); +extern void speakup_check(unsigned int); +extern int spkup_write(const char *, int); +extern void speakup_parked(unsigned int); +extern void speakup_cursoring(unsigned int); +extern void speakup_cut(unsigned int, struct tty_struct *); +extern void speakup_paste(struct tty_struct *); +extern void spk_skip(unsigned short); +extern int do_spk_ioctl(int,unsigned char *data,int,void *); +extern int is_alive(void); + +/* Speakup variable structure and definitions */ +#define HARD_DIRECT 0x01 /* a variable that is immediately sent to the + hardware synth */ +#define SOFT_DIRECT 0x02 // as above, but sent to speakup +#define NUMERIC 0x04 /* ASCII-represented numerical value + currently requires USE_RANGE to be set */ +#define USE_RANGE 0x08 // all values in ASCII range from valid are accepted +#define BUILDER 0x10 // variable must be built into the reset string +#define NO_USER 0x20 // variable is not allowed to be set by the user +#define ALLOW_BLANK 0x40 // alias-only flag to allow a blank parameter +#define MULTI_SET 0x80 // ASCII string of chars, each must be one of the valid set +#define END_VARS { NULL, NULL, NULL, 0, NULL } +#define TOGGLE "0,1" + +struct spk_variable { + char *id; // command name + char *param; // value of the parameter to the command + char *build; /* a string, describing how to construct the + string sent to the synth, with the character '_' to be filled in with + the parameter. eg. "\x01_P" will convert to "\x01+30P", if param is + "+30" */ + int flags; // see #defines below + char *valid; /* If the flag USE_RANGE is given, valid is a range + described by "lowval,highval". For example, "0,20" is the range 0-20. + If USE_RANGE is not given, valid is a NULL terminated set of valid + values for param. eg. "aeiou". Wildcard "*" matches anything. */ +}; + +/* speakup_drvcommon.c */ +struct spk_synth { + const char *name; + const char *version; + const char *proc_name; + const char *init; + const char *reinit; + unsigned short delay_time; + unsigned short trigger_time; + unsigned char jiffy_delta; + unsigned short full_time; + struct spk_variable *vars; + char **config; + long config_map; + int (*probe)(void); + void (*catch_up)(unsigned long data); + void (*write)(char c); + int (*is_alive)(void); +}; + +extern struct spk_synth *synth; +extern int synth_request_region(unsigned long, unsigned long); +extern int synth_release_region(unsigned long, unsigned long); +extern unsigned char synth_jiffy_delta; +extern int synth_port_tts; +extern volatile int synth_timer_active; +#if (LINUX_VERSION_CODE < 0x20300) /* is it a 2.2.x kernel? */ +extern struct wait_queue *synth_sleeping_list; +#else /* nope it's 2.3.x */ +extern wait_queue_head_t synth_sleeping_list; +#endif +extern struct timer_list synth_timer; +extern unsigned short synth_delay_time; /* time to schedule handler */ +extern unsigned short synth_trigger_time; +extern unsigned short synth_full_time; +extern char synth_buffering; /* flag to indicate we're buffering */ +extern unsigned char synth_buffer[]; /* guess what this is for! */ +extern unsigned short synth_end_of_buffer; +extern volatile unsigned short synth_queued_bytes, synth_sent_bytes; +extern void initialize_uart(struct serial_state *); +extern void synth_delay(int ms); +extern void synth_stop_timer(void); +extern void synth_buffer_add(char ch); +extern void synth_write(const char *buf, size_t count); + +#ifdef CONFIG_SPEAKUP +extern struct spk_t *speakup_console[]; +extern void speakup_allocate(int); +extern void speakup_bs(int); +extern void speakup_con_write(int, const char *, int); +extern void speakup_con_update(int); +extern void speakup_init(int); +extern void speakup_reset(int, unsigned char); +extern void speakup_control(int, struct kbd_struct *, int); +extern int speakup_diacr(unsigned char,unsigned int); +extern void speakup_savekey(unsigned char); +#else +static inline void speakup_allocate(int currcons) {}; +static inline void speakup_bs(int currcons) {}; +static inline void speakup_con_write(int currcons, const char *str, int len) {}; +static inline void speakup_con_update(int currcons) {}; +static inline void speakup_init(int currcons) {}; +static inline void speakup_reset(int fg_console, unsigned char type) {}; +static inline void speakup_control(int fg_console, struct kbd_struct * kbd, int value) {}; +static inline int speakup_diacr(unsigned char ch, unsigned int fg_console) {return 0;}; +static inline void speakup_savekey(unsigned char ch) {}; +#endif +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/spinlock.h linux.20pre2-ac1/include/linux/spinlock.h --- linux.20pre2/include/linux/spinlock.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/spinlock.h 2002-08-13 22:28:54.000000000 +0100 @@ -68,9 +68,10 @@ /* * Your basic spinlocks, allowing only a single CPU anywhere * - * Most gcc versions have a nasty bug with empty initializers. + * Some older gcc versions had a nasty bug with empty initializers. + * (XXX: could someone please confirm whether egcs 1.1 still has this bug?) */ -#if (__GNUC__ > 2) +#if (__GNUC__ > 2 || __GNUC_MINOR__ > 91) typedef struct { } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { } #else @@ -131,9 +132,10 @@ * irq-safe write-lock, but readers can get non-irqsafe * read-locks. * - * Most gcc versions have a nasty bug with empty initializers. + * Some older gcc versions had a nasty bug with empty initializers. + * (XXX: could someone please confirm whether egcs 1.1 still has this bug?) */ -#if (__GNUC__ > 2) +#if (__GNUC__ > 2 || __GNUC_MINOR__ > 91) typedef struct { } rwlock_t; #define RW_LOCK_UNLOCKED (rwlock_t) { } #else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/swap.h linux.20pre2-ac1/include/linux/swap.h --- linux.20pre2/include/linux/swap.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/swap.h 2002-08-13 22:28:55.000000000 +0100 @@ -86,14 +86,12 @@ extern unsigned int nr_free_pages(void); extern unsigned int nr_free_buffer_pages(void); extern int nr_active_pages; -extern int nr_inactive_pages; -extern atomic_t nr_async_pages; +extern int nr_inactive_dirty_pages; +extern int nr_inactive_clean_pages; extern atomic_t page_cache_size; extern atomic_t buffermem_pages; - extern spinlock_cacheline_t pagecache_lock_cacheline; #define pagecache_lock (pagecache_lock_cacheline.lock) - extern void __remove_inode_page(struct page *); /* Incomplete types for prototype declarations: */ @@ -103,32 +101,50 @@ struct zone_t; +/* linux/mm/rmap.c */ +extern int FASTCALL(page_referenced(struct page *)); +extern void FASTCALL(page_add_rmap(struct page *, pte_t *)); +extern void FASTCALL(page_remove_rmap(struct page *, pte_t *)); +extern int FASTCALL(try_to_unmap(struct page *)); +extern int FASTCALL(page_over_rsslimit(struct page *)); + +/* return values of try_to_unmap */ +#define SWAP_SUCCESS 0 +#define SWAP_AGAIN 1 +#define SWAP_FAIL 2 +#define SWAP_ERROR 3 + /* linux/mm/swap.c */ extern void FASTCALL(lru_cache_add(struct page *)); extern void FASTCALL(__lru_cache_del(struct page *)); extern void FASTCALL(lru_cache_del(struct page *)); extern void FASTCALL(activate_page(struct page *)); +extern void FASTCALL(activate_page_nolock(struct page *)); +extern void FASTCALL(deactivate_page(struct page *)); +extern void FASTCALL(deactivate_page_nolock(struct page *)); +extern void FASTCALL(drop_page(struct page *)); extern void swap_setup(void); /* linux/mm/vmscan.c */ extern wait_queue_head_t kswapd_wait; -extern int FASTCALL(try_to_free_pages(zone_t *, unsigned int, unsigned int)); -extern int FASTCALL(try_to_free_pages_nozone(unsigned int)); +extern struct page * FASTCALL(reclaim_page(zone_t *)); +extern int FASTCALL(try_to_free_pages(unsigned int gfp_mask)); +extern void wakeup_kswapd(unsigned int); +extern void rss_free_pages(unsigned int); /* linux/mm/page_io.c */ extern void rw_swap_page(int, struct page *); extern void rw_swap_page_nolock(int, swp_entry_t, char *); -/* linux/mm/page_alloc.c */ - /* linux/mm/swap_state.c */ #define SWAP_CACHE_INFO #ifdef SWAP_CACHE_INFO extern void show_swap_cache_info(void); #endif extern int add_to_swap_cache(struct page *, swp_entry_t); +extern int add_to_swap(struct page *); extern void __delete_from_swap_cache(struct page *page); extern void delete_from_swap_cache(struct page *page); extern void free_page_and_swap_cache(struct page *page); @@ -166,43 +182,26 @@ extern void FASTCALL(mark_page_accessed(struct page *)); /* + * Page aging defines. These seem to work great in FreeBSD, + * no need to reinvent the wheel. + */ +#define PAGE_AGE_START 5 +#define PAGE_AGE_ADV 3 +#define PAGE_AGE_DECL 1 +#define PAGE_AGE_MAX 64 + +/* * List add/del helper macros. These must be called * with the pagemap_lru_lock held! */ #define DEBUG_LRU_PAGE(page) \ do { \ - if (!PageLRU(page)) \ - BUG(); \ if (PageActive(page)) \ BUG(); \ -} while (0) - -#define add_page_to_active_list(page) \ -do { \ - DEBUG_LRU_PAGE(page); \ - SetPageActive(page); \ - list_add(&(page)->lru, &active_list); \ - nr_active_pages++; \ -} while (0) - -#define add_page_to_inactive_list(page) \ -do { \ - DEBUG_LRU_PAGE(page); \ - list_add(&(page)->lru, &inactive_list); \ - nr_inactive_pages++; \ -} while (0) - -#define del_page_from_active_list(page) \ -do { \ - list_del(&(page)->lru); \ - ClearPageActive(page); \ - nr_active_pages--; \ -} while (0) - -#define del_page_from_inactive_list(page) \ -do { \ - list_del(&(page)->lru); \ - nr_inactive_pages--; \ + if (PageInactiveDirty(page)) \ + BUG(); \ + if (PageInactiveClean(page)) \ + BUG(); \ } while (0) extern spinlock_t swaplock; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/sysctl.h linux.20pre2-ac1/include/linux/sysctl.h --- linux.20pre2/include/linux/sysctl.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/sysctl.h 2002-08-14 14:41:30.000000000 +0100 @@ -66,6 +66,7 @@ CTL_CPU=10 /* CPU stuff (speed scaling, etc) */ }; + /* CTL_BUS names: */ enum { @@ -536,7 +537,7 @@ FS_STATINODE=2, FS_MAXINODE=3, /* int:maximum number of inodes that can be allocated */ FS_NRDQUOT=4, /* int:current number of allocated dquots */ - FS_MAXDQUOT=5, /* int:maximum number of dquots that can be allocated */ + /* was FS_MAXDQUOT */ FS_NRFILE=6, /* int:current number of allocated filedescriptors */ FS_MAXFILE=7, /* int:maximum number of filedescriptors that can be allocated */ FS_DENTRY=8, @@ -547,6 +548,19 @@ FS_LEASES=13, /* int: leases enabled */ FS_DIR_NOTIFY=14, /* int: directory notification enabled */ FS_LEASE_TIME=15, /* int: maximum time to wait for a lease break */ + FS_DQSTATS=16, /* dir: disc quota usage statistics */ +}; + +/* /proc/sys/fs/quota/ */ +enum { + FS_DQ_LOOKUPS = 1, + FS_DQ_DROPS = 2, + FS_DQ_READS = 3, + FS_DQ_WRITES = 4, + FS_DQ_CACHE_HITS = 5, + FS_DQ_ALLOCATED = 6, + FS_DQ_FREE = 7, + FS_DQ_SYNCS = 8, }; /* CTL_DEBUG names: */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/tcp_diag.h linux.20pre2-ac1/include/linux/tcp_diag.h --- linux.20pre2/include/linux/tcp_diag.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/tcp_diag.h 2002-08-06 15:41:52.000000000 +0100 @@ -12,7 +12,7 @@ __u32 tcpdiag_src[4]; __u32 tcpdiag_dst[4]; __u32 tcpdiag_if; - __u32 tcpdiag_cookie[2]; + __u32 tcpdiag_cookie[2]; #define TCPDIAG_NOCOOKIE (~0U) }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/vmalloc.h linux.20pre2-ac1/include/linux/vmalloc.h --- linux.20pre2/include/linux/vmalloc.h 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/include/linux/vmalloc.h 2002-08-14 14:41:30.000000000 +0100 @@ -26,6 +26,7 @@ extern void vmfree_area_pages(unsigned long address, unsigned long size); extern int vmalloc_area_pages(unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot); +extern void *vcalloc(unsigned long nmemb, unsigned long elem_size); /* * Allocate any pages diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/linux/wait.h linux.20pre2-ac1/include/linux/wait.h --- linux.20pre2/include/linux/wait.h 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/include/linux/wait.h 2002-08-14 14:41:29.000000000 +0100 @@ -58,6 +58,7 @@ # define wq_read_unlock read_unlock # define wq_write_lock_irq write_lock_irq # define wq_write_lock_irqsave write_lock_irqsave +# define wq_write_unlock_irq write_unlock_irq # define wq_write_unlock_irqrestore write_unlock_irqrestore # define wq_write_unlock write_unlock #else @@ -70,6 +71,7 @@ # define wq_read_unlock_irqrestore spin_unlock_irqrestore # define wq_write_lock_irq spin_lock_irq # define wq_write_lock_irqsave spin_lock_irqsave +# define wq_write_unlock_irq spin_unlock_irq # define wq_write_unlock_irqrestore spin_unlock_irqrestore # define wq_write_unlock spin_unlock #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/datalink.h linux.20pre2-ac1/include/net/datalink.h --- linux.20pre2/include/net/datalink.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/net/datalink.h 2002-08-06 15:41:52.000000000 +0100 @@ -2,15 +2,24 @@ #define _NET_INET_DATALINK_H_ struct datalink_proto { - unsigned short type_len; - unsigned char type[8]; - const char *string_name; - unsigned short header_length; - int (*rcvfunc)(struct sk_buff *, struct net_device *, - struct packet_type *); - void (*datalink_header)(struct datalink_proto *, struct sk_buff *, - unsigned char *); - struct datalink_proto *next; + unsigned short type_len; + unsigned char type[8]; + const char *string_name; + + union { + struct llc_pinfo *llc; + } ll_pinfo; + + struct llc_sc_info *llc_sc; + struct sock *sock; + + unsigned short header_length; + + int (*rcvfunc)(struct sk_buff *, struct net_device *, + struct packet_type *); + void (*datalink_header)(struct datalink_proto *, struct sk_buff *, + unsigned char *); + struct datalink_proto *next; }; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_actn.h linux.20pre2-ac1/include/net/llc_actn.h --- linux.20pre2/include/net/llc_actn.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_actn.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,48 @@ +#ifndef LLC_ACTN_H +#define LLC_ACTN_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Station component state transition actions */ +#define LLC_STATION_AC_START_ACK_TMR 1 +#define LLC_STATION_AC_SET_RETRY_CNT_0 2 +#define LLC_STATION_AC_INC_RETRY_CNT_BY_1 3 +#define LLC_STATION_AC_SET_XID_R_CNT_0 4 +#define LLC_STATION_AC_INC_XID_R_CNT_BY_1 5 +#define LLC_STATION_AC_SEND_NULL_DSAP_XID_C 6 +#define LLC_STATION_AC_SEND_XID_R 7 +#define LLC_STATION_AC_SEND_TEST_R 8 +#define LLC_STATION_AC_REPORT_STATUS 9 + +/* All station state event action functions look like this */ +typedef int (*llc_station_action_t)(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_start_ack_timer(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_set_retry_cnt_0(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_inc_retry_cnt_by_1(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_set_xid_r_cnt_0(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_inc_xid_r_cnt_by_1(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_send_null_dsap_xid_c(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_send_xid_r(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_send_test_r(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_report_status(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_station_ac_report_status(struct llc_station *station, + struct llc_station_state_ev *ev); +#endif /* LLC_ACTN_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_c_ac.h linux.20pre2-ac1/include/net/llc_c_ac.h --- linux.20pre2/include/net/llc_c_ac.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_c_ac.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,254 @@ +#ifndef LLC_C_AC_H +#define LLC_C_AC_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Connection component state transition actions */ +/* + * Connection state transition actions + * (Fb = F bit; Pb = P bit; Xb = X bit) + */ +#define LLC_CONN_AC_CLR_REMOTE_BUSY 1 +#define LLC_CONN_AC_CONN_IND 2 +#define LLC_CONN_AC_CONN_CONFIRM 3 +#define LLC_CONN_AC_DATA_IND 4 +#define LLC_CONN_AC_DISC_IND 5 +#define LLC_CONN_AC_RESET_IND 6 +#define LLC_CONN_AC_RESET_CONFIRM 7 +#define LLC_CONN_AC_REPORT_STATUS 8 +#define LLC_CONN_AC_CLR_REMOTE_BUSY_IF_Fb_EQ_1 9 +#define LLC_CONN_AC_STOP_REJ_TMR_IF_DATA_FLAG_EQ_2 10 +#define LLC_CONN_AC_SEND_DISC_CMD_Pb_SET_X 11 +#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_Pb 12 +#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_1 13 +#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_F_FLAG 14 +#define LLC_CONN_AC_SEND_FRMR_RSP_Fb_SET_X 15 +#define LLC_CONN_AC_RESEND_FRMR_RSP_Fb_SET_0 16 +#define LLC_CONN_AC_RESEND_FRMR_RSP_Fb_SET_Pb 17 +#define LLC_CONN_AC_SEND_I_CMD_Pb_SET_1 18 +#define LLC_CONN_AC_RESEND_I_CMD_Pb_SET_1 19 +#define LLC_CONN_AC_RESEND_I_CMD_Pb_SET_1_OR_SEND_RR 20 +#define LLC_CONN_AC_SEND_I_XXX_Xb_SET_0 21 +#define LLC_CONN_AC_RESEND_I_XXX_Xb_SET_0 22 +#define LLC_CONN_AC_RESEND_I_XXX_Xb_SET_0_OR_SEND_RR 23 +#define LLC_CONN_AC_RESEND_I_RSP_Fb_SET_1 24 +#define LLC_CONN_AC_SEND_REJ_CMD_Pb_SET_1 25 +#define LLC_CONN_AC_SEND_REJ_RSP_Fb_SET_1 26 +#define LLC_CONN_AC_SEND_REJ_XXX_Xb_SET_0 27 +#define LLC_CONN_AC_SEND_RNR_CMD_Pb_SET_1 28 +#define LLC_CONN_AC_SEND_RNR_RSP_Fb_SET_1 29 +#define LLC_CONN_AC_SEND_RNR_XXX_Xb_SET_0 30 +#define LLC_CONN_AC_SET_REMOTE_BUSY 31 +#define LLC_CONN_AC_OPTIONAL_SEND_RNR_XXX_Xb_SET_0 32 +#define LLC_CONN_AC_SEND_RR_CMD_Pb_SET_1 33 +#define LLC_CONN_AC_SEND_ACK_CMD_Pb_SET_1 34 +#define LLC_CONN_AC_SEND_RR_RSP_Fb_SET_1 35 +#define LLC_CONN_AC_SEND_ACK_RSP_Fb_SET_1 36 +#define LLC_CONN_AC_SEND_RR_XXX_Xb_SET_0 37 +#define LLC_CONN_AC_SEND_ACK_XXX_Xb_SET_0 38 +#define LLC_CONN_AC_SEND_SABME_CMD_Pb_SET_X 39 +#define LLC_CONN_AC_SEND_UA_RSP_Fb_SET_Pb 40 +#define LLC_CONN_AC_SEND_UA_RSP_Fb_SET_F_FLAG 41 +#define LLC_CONN_AC_S_FLAG_SET_0 42 +#define LLC_CONN_AC_S_FLAG_SET_1 43 +#define LLC_CONN_AC_START_P_TMR 44 +#define LLC_CONN_AC_START_ACK_TMR 45 +#define LLC_CONN_AC_START_REJ_TMR 46 +#define LLC_CONN_AC_START_ACK_TMR_IF_NOT_RUNNING 47 +#define LLC_CONN_AC_STOP_ACK_TMR 48 +#define LLC_CONN_AC_STOP_P_TMR 49 +#define LLC_CONN_AC_STOP_REJ_TMR 50 +#define LLC_CONN_AC_STOP_ALL_TMRS 51 +#define LLC_CONN_AC_STOP_OTHER_TMRS 52 +#define LLC_CONN_AC_UPDATE_Nr_RECEIVED 53 +#define LLC_CONN_AC_UPDATE_P_FLAG 54 +#define LLC_CONN_AC_DATA_FLAG_SET_2 55 +#define LLC_CONN_AC_DATA_FLAG_SET_0 56 +#define LLC_CONN_AC_DATA_FLAG_SET_1 57 +#define LLC_CONN_AC_DATA_FLAG_SET_1_IF_DATA_FLAG_EQ_0 58 +#define LLC_CONN_AC_P_FLAG_SET_0 59 +#define LLC_CONN_AC_P_FLAG_SET_P 60 +#define LLC_CONN_AC_REMOTE_BUSY_SET_0 61 +#define LLC_CONN_AC_RETRY_CNT_SET_0 62 +#define LLC_CONN_AC_RETRY_CNT_INC_BY_1 63 +#define LLC_CONN_AC_Vr_SET_0 64 +#define LLC_CONN_AC_Vr_INC_BY_1 65 +#define LLC_CONN_AC_Vs_SET_0 66 +#define LLC_CONN_AC_Vs_SET_Nr 67 +#define LLC_CONN_AC_F_FLAG_SET_P 68 +#define LLC_CONN_AC_STOP_SENDACK_TMR 70 +#define LLC_CONN_AC_START_SENDACK_TMR_IF_NOT_RUNNING 71 + +typedef int (*llc_conn_action_t)(struct sock *sk, struct llc_conn_state_ev *ev); + +extern int llc_conn_ac_clear_remote_busy(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_conn_ind(struct sock *sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_conn_confirm(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_data_ind(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_disc_ind(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_rst_ind(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_rst_confirm(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_report_status(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_disc_cmd_p_set_x(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_dm_rsp_f_set_p(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_dm_rsp_f_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_i_cmd_p_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_i_cmd_p_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_resend_i_cmd_p_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_resend_i_cmd_p_set_1_or_send_rr(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_i_xxx_x_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_resend_i_xxx_x_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_resend_i_rsp_f_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rej_cmd_p_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rej_rsp_f_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rej_xxx_x_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_remote_busy(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rr_cmd_p_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_ack_cmd_p_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rr_rsp_f_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_ack_rsp_f_set_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rr_xxx_x_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_ack_xxx_x_set_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_ua_rsp_f_set_p(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_s_flag_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_s_flag_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_start_p_timer(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_start_ack_timer(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_start_rej_timer(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_start_ack_tmr_if_not_running(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_stop_ack_timer(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_stop_p_timer(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_stop_rej_timer(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_stop_all_timers(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_stop_other_timers(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_upd_nr_received(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_inc_tx_win_size(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_dec_tx_win_size(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_upd_p_flag(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_data_flag_2(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_data_flag_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_data_flag_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_p_flag_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_p_flag_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_remote_busy_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_retry_cnt_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_cause_flag_0(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_cause_flag_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_inc_retry_cnt_by_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_vr_0(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_inc_vr_by_1(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_vs_0(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_vs_nr(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_rst_vs(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_upd_vs(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_set_f_flag_p(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_disc(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_reset(struct sock* sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ac_disc_confirm(struct sock* sk, struct llc_conn_state_ev *ev); +extern u8 llc_circular_between(u8 a, u8 b, u8 c); +extern int llc_conn_ac_send_ack_if_needed(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_inc_npta_value(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_adjust_npta_by_rr(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_adjust_npta_by_rnr(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_rst_sendack_flag(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ac_send_i_as_ack(struct sock* sk, + struct llc_conn_state_ev *ev); +#endif /* LLC_C_AC_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_c_ev.h linux.20pre2-ac1/include/net/llc_c_ev.h --- linux.20pre2/include/net/llc_c_ev.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_c_ev.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,323 @@ +#ifndef LLC_C_EV_H +#define LLC_C_EV_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Connection component state transition event qualifiers */ +/* Types of events (possible values in 'ev->type') */ +#define LLC_CONN_EV_TYPE_SIMPLE 1 +#define LLC_CONN_EV_TYPE_CONDITION 2 +#define LLC_CONN_EV_TYPE_PRIM 3 +#define LLC_CONN_EV_TYPE_PDU 4 /* command/response PDU */ +#define LLC_CONN_EV_TYPE_ACK_TMR 5 +#define LLC_CONN_EV_TYPE_P_TMR 6 +#define LLC_CONN_EV_TYPE_REJ_TMR 7 +#define LLC_CONN_EV_TYPE_BUSY_TMR 8 +#define LLC_CONN_EV_TYPE_RPT_STATUS 9 +#define LLC_CONN_EV_TYPE_SENDACK_TMR 10 + +#define NBR_CONN_EV 5 +/* Connection events which cause state transitions when fully qualified */ + +#define LLC_CONN_EV_CONN_REQ 1 +#define LLC_CONN_EV_CONN_RESP 2 +#define LLC_CONN_EV_DATA_REQ 3 +#define LLC_CONN_EV_DISC_REQ 4 +#define LLC_CONN_EV_RESET_REQ 5 +#define LLC_CONN_EV_RESET_RESP 6 +#define LLC_CONN_EV_LOCAL_BUSY_DETECTED 7 +#define LLC_CONN_EV_LOCAL_BUSY_CLEARED 8 +#define LLC_CONN_EV_RX_BAD_PDU 9 +#define LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X 10 +#define LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X 11 +#define LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X 12 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X 13 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_UNEXPD_Ns 14 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_INVAL_Ns 15 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X 16 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_UNEXPD_Ns 17 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_INVAL_Ns 18 +#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_X 19 +#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X 20 +#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_X 21 +#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_X 22 +#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_X 23 +#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_X 24 +#define LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X 25 +#define LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X 26 +#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_X 27 +#define LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_X 28 +#define LLC_CONN_EV_RX_XXX_YYY 29 +#define LLC_CONN_EV_RX_ZZZ_CMD_Pbit_SET_X_INVAL_Nr 30 +#define LLC_CONN_EV_RX_ZZZ_RSP_Fbit_SET_X_INVAL_Nr 31 +#define LLC_CONN_EV_P_TMR_EXP 32 +#define LLC_CONN_EV_ACK_TMR_EXP 33 +#define LLC_CONN_EV_REJ_TMR_EXP 34 +#define LLC_CONN_EV_BUSY_TMR_EXP 35 +#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_1 36 +#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_0 37 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns 38 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns 39 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns 40 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns 41 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 42 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 43 +#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 44 +#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 45 +#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 46 +#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 47 +#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 48 +#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 49 +#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 50 +#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 51 +#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 52 +#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 53 +#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 54 +#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 55 +#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 56 +#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 57 +#define LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_1 58 +#define LLC_CONN_EV_TX_BUFF_FULL 59 + +#define LLC_CONN_EV_INIT_P_F_CYCLE 100 +/* + * Connection event qualifiers; for some events a certain combination of + * these qualifiers must be TRUE before event recognized valid for state; + * these constants act as indexes into the Event Qualifier function + * table + */ +#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_1 1 +#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_0 2 +#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_2 3 +#define LLC_CONN_EV_QFY_P_FLAG_EQ_1 4 +#define LLC_CONN_EV_QFY_P_FLAG_EQ_0 5 +#define LLC_CONN_EV_QFY_P_FLAG_EQ_Fbit 6 +#define LLC_CONN_EV_QFY_REMOTE_BUSY_EQ_0 7 +#define LLC_CONN_EV_QFY_RETRY_CNT_LT_N2 8 +#define LLC_CONN_EV_QFY_RETRY_CNT_GTE_N2 9 +#define LLC_CONN_EV_QFY_S_FLAG_EQ_1 10 +#define LLC_CONN_EV_QFY_S_FLAG_EQ_0 11 +#define LLC_CONN_EV_QFY_INIT_P_F_CYCLE 12 + +/* Event data interface; what is sent in an event package */ +/* Event LLC_CONN_EV_TYPE_SIMPLE interface */ +struct llc_conn_ev_simple_if { + u8 ev; +}; + +/* Event LLC_CONN_EV_TYPE_PRIM interface */ +struct llc_conn_ev_prim_if { + u8 prim; /* connect, disconnect, reset, ... */ + u8 type; /* request, indicate, response, conf */ + struct llc_prim_if_block *data; +}; + +/* Event LLC_CONN_EV_TYPE_PDU interface */ +struct llc_conn_ev_pdu_if { + u8 ev; + u8 reason; + struct sk_buff *skb; +}; + +/* Event interface for timer-generated events */ +struct llc_conn_ev_tmr_if { + struct sock *sk; + u32 component_handle; + void *timer_specific; +}; + +struct llc_conn_ev_rpt_sts_if { + u8 status; +}; + +union llc_conn_ev_if { + struct llc_conn_ev_simple_if a; /* 'a' for simple, easy ... */ + struct llc_conn_ev_prim_if prim; + struct llc_conn_ev_pdu_if pdu; + struct llc_conn_ev_tmr_if tmr; + struct llc_conn_ev_rpt_sts_if rsts; /* report status */ +}; + +struct llc_conn_state_ev { + u8 type; + u8 status; + u8 flag; + struct llc_prim_if_block *ind_prim; + struct llc_prim_if_block *cfm_prim; + union llc_conn_ev_if data; +}; + +typedef int (*llc_conn_ev_t)(struct sock *sk, struct llc_conn_state_ev *ev); +typedef int (*llc_conn_ev_qfyr_t)(struct sock *sk, + struct llc_conn_state_ev *ev); + +extern int llc_conn_ev_conn_req(struct sock *sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ev_conn_resp(struct sock *sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ev_data_req(struct sock *sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ev_disc_req(struct sock *sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rst_req(struct sock *sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rst_resp(struct sock *sk, struct llc_conn_state_ev *ev); +extern int llc_conn_ev_local_busy_detected(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_local_busy_cleared(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_bad_pdu(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_xxx_yyy(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_p_tmr_exp(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_ack_tmr_exp(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rej_tmr_exp(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_busy_tmr_exp(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_any_tmr_exp(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_sendack_tmr_exp(struct sock *sk, + struct llc_conn_state_ev *ev); +/* NOT_USED functions and their variations */ +extern int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_xxx_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_rx_any_frame(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_tx_buffer_full(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_init_p_f_cycle(struct sock *sk, + struct llc_conn_state_ev *ev); + +/* Available connection action qualifiers */ +extern int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_init_p_f_cycle(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_conn(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_disc(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_failed(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_impossible(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_received(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk, + struct llc_conn_state_ev *ev); +extern int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk, + struct llc_conn_state_ev *ev); +#endif /* LLC_C_EV_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_conn.h linux.20pre2-ac1/include/net/llc_conn.h --- linux.20pre2/include/net/llc_conn.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_conn.h 2002-08-14 14:41:31.000000000 +0100 @@ -0,0 +1,155 @@ +#ifndef LLC_CONN_H +#define LLC_CONN_H +/* + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include + +#undef DEBUG_LLC_CONN_ALLOC + +struct llc_timer { + struct timer_list timer; + u8 running; /* timer is running or no */ + u16 expire; /* timer expire time */ +}; + +struct llc_opt { + struct list_head node; /* entry in sap->sk_list.list */ + struct sock *sk; /* sock that has this llc_opt */ + void *handler; /* for upper layers usage */ + u8 state; /* state of connection */ + struct llc_sap *sap; /* pointer to parent SAP */ + struct llc_addr laddr; /* lsap/mac pair */ + struct llc_addr daddr; /* dsap/mac pair */ + struct net_device *dev; /* device to send to remote */ + u8 retry_count; /* number of retries */ + u8 ack_must_be_send; + u8 first_pdu_Ns; + u8 npta; + struct llc_timer ack_timer; + struct llc_timer pf_cycle_timer; + struct llc_timer rej_sent_timer; + struct llc_timer busy_state_timer; /* ind busy clr at remote LLC */ + u8 vS; /* seq# next in-seq I-PDU tx'd*/ + u8 vR; /* seq# next in-seq I-PDU rx'd*/ + u32 n2; /* max nbr re-tx's for timeout*/ + u32 n1; /* max nbr octets in I PDU */ + u8 k; /* tx window size; max = 127 */ + u8 rw; /* rx window size; max = 127 */ + u8 p_flag; /* state flags */ + u8 f_flag; + u8 s_flag; + u8 data_flag; + u8 remote_busy_flag; + u8 cause_flag; + struct sk_buff_head pdu_unack_q; /* PUDs sent/waiting ack */ + u16 link; /* network layer link number */ + u8 X; /* a temporary variable */ + u8 ack_pf; /* this flag indicates what is + the P-bit of acknowledge */ + u8 failed_data_req; /* recognize that already exist a + failed llc_data_req_handler + (tx_buffer_full or unacceptable + state */ + u8 dec_step; + u8 inc_cntr; + u8 dec_cntr; + u8 connect_step; + u8 last_nr; /* NR of last pdu recieved */ + u32 rx_pdu_hdr; /* used for saving header of last pdu + received and caused sending FRMR. + Used for resending FRMR */ +#ifdef DEBUG_LLC_CONN_ALLOC + char *f_alloc, /* function that allocated this connection */ + *f_free; /* function that freed this connection */ + int l_alloc, /* line that allocated this connection */ + l_free; /* line that freed this connection */ +#endif +}; + +#define llc_sk(__sk) ((struct llc_opt *)(__sk)->protinfo.destruct_hook) + +struct llc_conn_state_ev; + +extern struct sock *__llc_sock_alloc(void); +extern void __llc_sock_free(struct sock *sk, u8 free); + +#ifdef DEBUG_LLC_CONN_ALLOC +#define dump_stack() printk(KERN_INFO "call trace: %p, %p, %p\n", \ + __builtin_return_address(0), \ + __builtin_return_address(1), \ + __builtin_return_address(2)); +#define llc_sock_alloc() ({ \ + struct sock *__sk = __llc_sock_alloc(); \ + if (__sk) { \ + llc_sk(__sk)->f_alloc = __FUNCTION__; \ + llc_sk(__sk)->l_alloc = __LINE__; \ + } \ + __sk;}) +#define __llc_sock_assert(__sk) \ + if (llc_sk(__sk)->f_free) { \ + printk(KERN_ERR \ + "%p conn (alloc'd @ %s(%d)) " \ + "already freed @ %s(%d) " \ + "being used again @ %s(%d)\n", \ + llc_sk(__sk), \ + llc_sk(__sk)->f_alloc, llc_sk(__sk)->l_alloc, \ + llc_sk(__sk)->f_free, llc_sk(__sk)->l_free, \ + __FUNCTION__, __LINE__); \ + dump_stack(); +#define llc_sock_free(__sk) \ +{ \ + __llc_sock_assert(__sk) \ + } else { \ + __llc_sock_free(__sk, 0); \ + llc_sk(__sk)->f_free = __FUNCTION__; \ + llc_sk(__sk)->l_free = __LINE__; \ + } \ +} +#define llc_sock_assert(__sk) \ +{ \ + __llc_sock_assert(__sk); \ + return; } \ +} +#define llc_sock_assert_ret(__sk, __ret) \ +{ \ + __llc_sock_assert(__sk); \ + return __ret; } \ +} +#else /* DEBUG_LLC_CONN_ALLOC */ +#define llc_sock_alloc() __llc_sock_alloc() +#define llc_sock_free(__sk) __llc_sock_free(__sk, 1) +#define llc_sock_assert(__sk) +#define llc_sock_assert_ret(__sk) +#endif /* DEBUG_LLC_CONN_ALLOC */ + +extern void llc_sock_reset(struct sock *sk); +extern int llc_sock_init(struct sock *sk); + +/* Access to a connection */ +extern struct llc_conn_state_ev *llc_conn_alloc_ev(struct sock *sk); +extern int llc_conn_send_ev(struct sock *sk, struct llc_conn_state_ev *ev); +extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); +extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb, + struct llc_conn_state_ev *ev); +extern void llc_conn_free_ev(struct llc_conn_state_ev *ev); +extern void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, + u8 first_p_bit); +extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, + u8 first_f_bit); +extern int llc_conn_remove_acked_pdus(struct sock *conn, u8 nr, + u16 *how_many_unacked); +extern struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, + struct llc_addr *laddr); +extern u8 llc_data_accept_state(u8 state); +extern void llc_build_offset_table(void); +#endif /* LLC_CONN_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_c_st.h linux.20pre2-ac1/include/net/llc_c_st.h --- linux.20pre2/include/net/llc_c_st.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_c_st.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,48 @@ +#ifndef LLC_C_ST_H +#define LLC_C_ST_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Connection component state management */ +/* connection states */ +#define LLC_CONN_OUT_OF_SVC 0 /* prior to allocation */ + +#define LLC_CONN_STATE_ADM 1 /* disc, initial state */ +#define LLC_CONN_STATE_SETUP 2 /* disconnected state */ +#define LLC_CONN_STATE_NORMAL 3 /* connected state */ +#define LLC_CONN_STATE_BUSY 4 /* connected state */ +#define LLC_CONN_STATE_REJ 5 /* connected state */ +#define LLC_CONN_STATE_AWAIT 6 /* connected state */ +#define LLC_CONN_STATE_AWAIT_BUSY 7 /* connected state */ +#define LLC_CONN_STATE_AWAIT_REJ 8 /* connected state */ +#define LLC_CONN_STATE_D_CONN 9 /* disconnected state */ +#define LLC_CONN_STATE_RESET 10 /* disconnected state */ +#define LLC_CONN_STATE_ERROR 11 /* disconnected state */ +#define LLC_CONN_STATE_TEMP 12 /* disconnected state */ + +#define NBR_CONN_STATES 12 /* size of state table */ +#define NO_STATE_CHANGE 100 + +/* Connection state table structure */ +struct llc_conn_state_trans { + llc_conn_ev_t ev; + u8 next_state; + llc_conn_ev_qfyr_t *ev_qualifiers; + llc_conn_action_t *ev_actions; +}; + +struct llc_conn_state { + u8 current_state; + struct llc_conn_state_trans **transitions; +}; + +extern struct llc_conn_state llc_conn_state_table[]; +#endif /* LLC_C_ST_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_evnt.h linux.20pre2-ac1/include/net/llc_evnt.h --- linux.20pre2/include/net/llc_evnt.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_evnt.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,93 @@ +#ifndef LLC_EVNT_H +#define LLC_EVNT_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Station component state transition events */ +/* Types of events (possible values in 'ev->type') */ +#define LLC_STATION_EV_TYPE_SIMPLE 1 +#define LLC_STATION_EV_TYPE_CONDITION 2 +#define LLC_STATION_EV_TYPE_PRIM 3 +#define LLC_STATION_EV_TYPE_PDU 4 /* command/response PDU */ +#define LLC_STATION_EV_TYPE_ACK_TMR 5 +#define LLC_STATION_EV_TYPE_RPT_STATUS 6 + +/* Events */ +#define LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK 1 +#define LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK 2 +#define LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY 3 +#define LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY 4 +#define LLC_STATION_EV_RX_NULL_DSAP_XID_C 5 +#define LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ 6 +#define LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ 7 +#define LLC_STATION_EV_RX_NULL_DSAP_TEST_C 8 +#define LLC_STATION_EV_DISABLE_REQ 9 + +/* Interfaces for various types of supported events */ +struct llc_stat_ev_simple_if { + u8 ev; +}; + +struct llc_stat_ev_prim_if { + u8 prim; /* connect, disconnect, reset, ... */ + u8 type; /* request, indicate, response, confirm */ +}; + +struct llc_stat_ev_pdu_if { + u8 reason; + struct sk_buff *skb; +}; + +struct llc_stat_ev_tmr_if { + void *timer_specific; +}; + +struct llc_stat_ev_rpt_sts_if { + u8 status; +}; + +union llc_stat_ev_if { + struct llc_stat_ev_simple_if a; /* 'a' for simple, easy ... */ + struct llc_stat_ev_prim_if prim; + struct llc_stat_ev_pdu_if pdu; + struct llc_stat_ev_tmr_if tmr; + struct llc_stat_ev_rpt_sts_if rsts; /* report status */ +}; + +struct llc_station_state_ev { + u8 type; + union llc_stat_ev_if data; + struct list_head node; /* node in station->ev_q.list */ +}; + +typedef int (*llc_station_ev_t)(struct llc_station *station, + struct llc_station_state_ev *ev); + +extern int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct llc_station * + station, + struct llc_station_state_ev *ev); +extern int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station, + struct llc_station_state_ev *ev); +extern int llc_stat_ev_disable_req(struct llc_station *station, + struct llc_station_state_ev *ev); +#endif /* LLC_EVNT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_if.h linux.20pre2-ac1/include/net/llc_if.h --- linux.20pre2/include/net/llc_if.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_if.h 2002-08-13 22:28:56.000000000 +0100 @@ -0,0 +1,155 @@ +#ifndef LLC_IF_H +#define LLC_IF_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Defines LLC interface to network layer */ +/* Available primitives */ +#include + +#define LLC_DATAUNIT_PRIM 0 +#define LLC_CONN_PRIM 1 +#define LLC_DATA_PRIM 2 +#define LLC_DISC_PRIM 3 +#define LLC_RESET_PRIM 4 +#define LLC_FLOWCONTROL_PRIM 5 +#define LLC_DISABLE_PRIM 6 +#define LLC_XID_PRIM 7 +#define LLC_TEST_PRIM 8 +#define LLC_SAP_ACTIVATION 9 +#define LLC_SAP_DEACTIVATION 10 + +#define LLC_NBR_PRIMITIVES 11 + +#define LLC_IND 1 +#define LLC_CONFIRM 2 + +/* Primitive type */ +#define LLC_PRIM_TYPE_REQ 1 +#define LLC_PRIM_TYPE_IND 2 +#define LLC_PRIM_TYPE_RESP 3 +#define LLC_PRIM_TYPE_CONFIRM 4 + +/* Reset reasons, remote entity or local LLC */ +#define LLC_RESET_REASON_REMOTE 1 +#define LLC_RESET_REASON_LOCAL 2 + +/* Disconnect reasons */ +#define LLC_DISC_REASON_RX_DM_RSP_PDU 0 +#define LLC_DISC_REASON_RX_DISC_CMD_PDU 1 +#define LLC_DISC_REASON_ACK_TMR_EXP 2 + +/* Confirm reasons */ +#define LLC_STATUS_CONN 0 /* connect confirm & reset confirm */ +#define LLC_STATUS_DISC 1 /* connect confirm & reset confirm */ +#define LLC_STATUS_FAILED 2 /* connect confirm & reset confirm */ +#define LLC_STATUS_IMPOSSIBLE 3 /* connect confirm */ +#define LLC_STATUS_RECEIVED 4 /* data conn */ +#define LLC_STATUS_REMOTE_BUSY 5 /* data conn */ +#define LLC_STATUS_REFUSE 6 /* data conn */ +#define LLC_STATUS_CONFLICT 7 /* disconnect conn */ +#define LLC_STATUS_RESET_DONE 8 /* */ + +/* Structures and types */ +/* SAP/MAC Address pair */ +struct llc_addr { + u8 lsap; + u8 mac[IFHWADDRLEN]; +}; + +/* Primitive-specific data */ +struct llc_prim_conn { + struct llc_addr saddr; /* used by request only */ + struct llc_addr daddr; /* used by request only */ + u8 status; /* reason for failure */ + u8 pri; /* service_class */ + struct net_device *dev; + struct sock *sk; /* returned from REQUEST */ + void *handler; /* upper layer use, + stored in llc_opt->handler */ + u16 link; + struct sk_buff *skb; /* received SABME */ +}; + +struct llc_prim_disc { + struct sock *sk; + u16 link; + u8 reason; /* not used by request */ +}; + +struct llc_prim_reset { + struct sock *sk; + u16 link; + u8 reason; /* used only by indicate */ +}; + +struct llc_prim_flow_ctrl { + struct sock *sk; + u16 link; + u32 amount; +}; + +struct llc_prim_data { + struct sock *sk; + u16 link; + u8 pri; + struct sk_buff *skb; /* pointer to frame */ + u8 status; /* reason */ +}; + + /* Sending data in conection-less mode */ +struct llc_prim_unit_data { + struct llc_addr saddr; + struct llc_addr daddr; + u8 pri; + struct sk_buff *skb; /* pointer to frame */ + u8 lfb; /* largest frame bit (TR) */ +}; + +struct llc_prim_xid { + struct llc_addr saddr; + struct llc_addr daddr; + u8 pri; + struct sk_buff *skb; +}; + +struct llc_prim_test { + struct llc_addr saddr; + struct llc_addr daddr; + u8 pri; + struct sk_buff *skb; /* pointer to frame */ +}; + +union llc_u_prim_data { + struct llc_prim_conn conn; + struct llc_prim_disc disc; + struct llc_prim_reset res; + struct llc_prim_flow_ctrl fc; + struct llc_prim_data data; /* data */ + struct llc_prim_unit_data udata; /* unit data */ + struct llc_prim_xid xid; + struct llc_prim_test test; +}; + +struct llc_sap; + +/* Information block passed with all called primitives */ +struct llc_prim_if_block { + struct llc_sap *sap; + u8 prim; + union llc_u_prim_data *data; +}; +typedef int (*llc_prim_call_t)(struct llc_prim_if_block *prim_if); + +extern struct llc_sap *llc_sap_open(llc_prim_call_t network_indicate, + llc_prim_call_t network_confirm, u8 lsap); +extern void llc_sap_close(struct llc_sap *sap); +#endif /* LLC_IF_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_mac.h linux.20pre2-ac1/include/net/llc_mac.h --- linux.20pre2/include/net/llc_mac.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_mac.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,23 @@ +#ifndef LLC_MAC_H +#define LLC_MAC_H +/* + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Defines MAC-layer interface to LLC layer */ +extern int mac_send_pdu(struct sk_buff *skb); +extern int mac_indicate(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt); +extern struct net_device *mac_dev_peer(struct net_device *current_dev, + int type, u8 *mac); +extern int llc_pdu_router(struct llc_sap *sap, struct sock *sk, + struct sk_buff *skb, u8 type); +extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da); +#endif /* LLC_MAC_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_main.h linux.20pre2-ac1/include/net/llc_main.h --- linux.20pre2/include/net/llc_main.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_main.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,68 @@ +#ifndef LLC_MAIN_H +#define LLC_MAIN_H +/* + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#define LLC_EVENT 1 +#define LLC_PACKET 2 +#define LLC_TYPE_1 1 +#define LLC_TYPE_2 2 +#define LLC_P_TIME 2 +#define LLC_ACK_TIME 3 +#define LLC_REJ_TIME 3 +#define LLC_BUSY_TIME 3 +#define LLC_SENDACK_TIME 50 +#define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ +#define LLC_DEST_SAP 1 /* Type 1 goes here */ +#define LLC_DEST_CONN 2 /* Type 2 goes here */ + +/* LLC Layer global default parameters */ + +#define LLC_GLOBAL_DEFAULT_MAX_NBR_SAPS 4 +#define LLC_GLOBAL_DEFAULT_MAX_NBR_CONNS 64 + +extern struct llc_prim_if_block llc_ind_prim, llc_cfm_prim; + +/* LLC station component (SAP and connection resource manager) */ +/* Station component; one per adapter */ +struct llc_station { + u8 state; /* state of station */ + u8 xid_r_count; /* XID response PDU counter */ + struct timer_list ack_timer; + u8 ack_tmr_running; /* 1 or 0 */ + u8 retry_count; + u8 maximum_retry; + u8 mac_sa[6]; /* MAC source address */ + struct { + spinlock_t lock; + struct list_head list; + } sap_list; /* list of related SAPs */ + struct { + spinlock_t lock; + struct list_head list; + } ev_q; /* events entering state mach. */ + struct sk_buff_head mac_pdu_q; /* PDUs ready to send to MAC */ +}; +struct llc_station_state_ev; + +extern struct llc_sap *llc_sap_alloc(void); +extern void llc_sap_save(struct llc_sap *sap); +extern void llc_free_sap(struct llc_sap *sap); +extern struct llc_sap *llc_sap_find(u8 lsap); +extern struct llc_station *llc_station_get(void); +extern struct llc_station_state_ev * + llc_station_alloc_ev(struct llc_station *station); +extern void llc_station_send_ev(struct llc_station *station, + struct llc_station_state_ev *ev); +extern void llc_station_send_pdu(struct llc_station *station, + struct sk_buff *skb); +extern struct sk_buff *llc_alloc_frame(void); +#endif /* LLC_MAIN_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_pdu.h linux.20pre2-ac1/include/net/llc_pdu.h --- linux.20pre2/include/net/llc_pdu.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_pdu.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,255 @@ +#ifndef LLC_PDU_H +#define LLC_PDU_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* LLC PDU structure */ +/* Lengths of frame formats */ +#define LLC_PDU_LEN_I 4 /* header and 2 control bytes */ +#define LLC_PDU_LEN_S 4 +#define LLC_PDU_LEN_U 3 /* header and 1 control byte */ +/* Known SAP addresses */ +#define LLC_GLOBAL_SAP 0xFF +#define LLC_NULL_SAP 0x00 /* not network-layer visible */ +#define LLC_MGMT_INDIV 0x02 /* station LLC mgmt indiv addr */ +#define LLC_MGMT_GRP 0x03 /* station LLC mgmt group addr */ +#define LLC_RDE_SAP 0xA6 /* route ... */ + +/* SAP field bit masks */ +#define LLC_ISO_RESERVED_SAP 0x02 +#define LLC_SAP_GROUP_DSAP 0x01 +#define LLC_SAP_RESP_SSAP 0x01 + +/* Group/individual DSAP indicator is DSAP field */ +#define LLC_PDU_GROUP_DSAP_MASK 0x01 +#define LLC_PDU_IS_GROUP_DSAP(pdu) \ + ((pdu->dsap & LLC_PDU_GROUP_DSAP_MASK) ? 0 : 1) +#define LLC_PDU_IS_INDIV_DSAP(pdu) \ + (!(pdu->dsap & LLC_PDU_GROUP_DSAP_MASK) ? 0 : 1) + +/* Command/response PDU indicator in SSAP field */ +#define LLC_PDU_CMD_RSP_MASK 0x01 +#define LLC_PDU_CMD 0 +#define LLC_PDU_RSP 1 +#define LLC_PDU_IS_CMD(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 1 : 0) +#define LLC_PDU_IS_RSP(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 0 : 1) + +/* Get PDU type from 2 lowest-order bits of control field first byte */ +#define LLC_PDU_TYPE_I_MASK 0x01 /* 16-bit control field */ +#define LLC_PDU_TYPE_S_MASK 0x03 +#define LLC_PDU_TYPE_U_MASK 0x03 /* 8-bit control field */ +#define LLC_PDU_TYPE_MASK 0x03 + +#define LLC_PDU_TYPE_I 0 /* first bit */ +#define LLC_PDU_TYPE_S 1 /* first two bits */ +#define LLC_PDU_TYPE_U 3 /* first two bits */ + +#define LLC_PDU_TYPE_IS_I(pdu) \ + ((!(pdu->ctrl_1 & LLC_PDU_TYPE_I_MASK)) ? 0 : 1) + +#define LLC_PDU_TYPE_IS_U(pdu) \ + (((pdu->ctrl_1 & LLC_PDU_TYPE_U_MASK) == LLC_PDU_TYPE_U) ? 0 : 1) + +#define LLC_PDU_TYPE_IS_S(pdu) \ + (((pdu->ctrl_1 & LLC_PDU_TYPE_S_MASK) == LLC_PDU_TYPE_S) ? 0 : 1) + +/* U-format PDU control field masks */ +#define LLC_U_PF_BIT_MASK 0x10 /* P/F bit mask */ +#define LLC_U_PF_IS_1(pdu) ((pdu->ctrl_1 & LLC_U_PF_BIT_MASK) ? 0 : 1) +#define LLC_U_PF_IS_0(pdu) ((!(pdu->ctrl_1 & LLC_U_PF_BIT_MASK)) ? 0 : 1) + +#define LLC_U_PDU_CMD_MASK 0xEC /* cmd/rsp mask */ +#define LLC_U_PDU_CMD(pdu) (pdu->ctrl_1 & LLC_U_PDU_CMD_MASK) +#define LLC_U_PDU_RSP(pdu) (pdu->ctrl_1 & LLC_U_PDU_CMD_MASK) + +#define LLC_1_PDU_CMD_UI 0x00 /* Type 1 cmds/rsps */ +#define LLC_1_PDU_CMD_XID 0xAC +#define LLC_1_PDU_CMD_TEST 0xE0 + +#define LLC_2_PDU_CMD_SABME 0x6C /* Type 2 cmds/rsps */ +#define LLC_2_PDU_CMD_DISC 0x40 +#define LLC_2_PDU_RSP_UA 0x60 +#define LLC_2_PDU_RSP_DM 0x0C +#define LLC_2_PDU_RSP_FRMR 0x84 + +/* Type 1 operations */ + +/* XID information field bit masks */ + +/* LLC format identifier (byte 1) */ +#define LLC_XID_FMT_ID 0x81 /* first byte must be this */ + +/* LLC types/classes identifier (byte 2) */ +#define LLC_XID_CLASS_ZEROS_MASK 0xE0 /* these must be zeros */ +#define LLC_XID_CLASS_MASK 0x1F /* AND with byte to get below */ + +#define LLC_XID_NULL_CLASS_1 0x01 /* if NULL LSAP...use these */ +#define LLC_XID_NULL_CLASS_2 0x03 +#define LLC_XID_NULL_CLASS_3 0x05 +#define LLC_XID_NULL_CLASS_4 0x07 + +#define LLC_XID_NNULL_TYPE_1 0x01 /* if non-NULL LSAP...use these */ +#define LLC_XID_NNULL_TYPE_2 0x02 +#define LLC_XID_NNULL_TYPE_3 0x04 +#define LLC_XID_NNULL_TYPE_1_2 0x03 +#define LLC_XID_NNULL_TYPE_1_3 0x05 +#define LLC_XID_NNULL_TYPE_2_3 0x06 +#define LLC_XID_NNULL_ALL 0x07 + +/* Sender Receive Window (byte 3) */ +#define LLC_XID_RW_MASK 0xFE /* AND with value to get below */ + +#define LLC_XID_MIN_RW 0x02 /* lowest-order bit always zero */ + +/* Type 2 operations */ + +#define LLC_2_SEQ_NBR_MODULO ((u8) 128) + +/* I-PDU masks ('ctrl' is I-PDU control word) */ +#define LLC_I_GET_NS(pdu) (u8)((pdu->ctrl_1 & 0xFE) >> 1) +#define LLC_I_GET_NR(pdu) (u8)((pdu->ctrl_2 & 0xFE) >> 1) + +#define LLC_I_PF_BIT_MASK 0x01 + +#define LLC_I_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_I_PF_BIT_MASK)) ? 0 : 1) +#define LLC_I_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_I_PF_BIT_MASK) ? 0 : 1) + +/* S-PDU supervisory commands and responses */ + +#define LLC_S_PDU_CMD_MASK 0x0C +#define LLC_S_PDU_CMD(pdu) (pdu->ctrl_1 & LLC_S_PDU_CMD_MASK) +#define LLC_S_PDU_RSP(pdu) (pdu->ctrl_1 & LLC_S_PDU_CMD_MASK) + +#define LLC_2_PDU_CMD_RR 0x00 /* rx ready cmd */ +#define LLC_2_PDU_RSP_RR 0x00 /* rx ready rsp */ +#define LLC_2_PDU_CMD_REJ 0x08 /* reject PDU cmd */ +#define LLC_2_PDU_RSP_REJ 0x08 /* reject PDU rsp */ +#define LLC_2_PDU_CMD_RNR 0x04 /* rx not ready cmd */ +#define LLC_2_PDU_RSP_RNR 0x04 /* rx not ready rsp */ + +#define LLC_S_PF_BIT_MASK 0x01 +#define LLC_S_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_S_PF_BIT_MASK)) ? 0 : 1) +#define LLC_S_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_S_PF_BIT_MASK) ? 0 : 1) + +#define PDU_SUPV_GET_Nr(pdu) ((pdu->ctrl_2 & 0xFE) >> 1) +#define PDU_GET_NEXT_Vr(sn) (++sn & ~LLC_2_SEQ_NBR_MODULO) + +/* FRMR information field macros */ + +#define FRMR_INFO_LENGTH 5 /* 5 bytes of information */ + +/* + * info is pointer to FRMR info field structure; 'rej_ctrl' is byte pointer + * (if U-PDU) or word pointer to rejected PDU control field + */ +#define FRMR_INFO_SET_REJ_CNTRL(info,rej_ctrl) \ + info->rej_pdu_ctrl = ((*((u8 *) rej_ctrl) & \ + LLC_PDU_TYPE_U) != LLC_PDU_TYPE_U ? \ + (u16)*((u16 *) rej_ctrl) : \ + (((u16) *((u8 *) rej_ctrl)) & 0x00FF)) + +/* + * Info is pointer to FRMR info field structure; 'vs' is a byte containing + * send state variable value in low-order 7 bits (insure the lowest-order + * bit remains zero (0)) + */ +#define FRMR_INFO_SET_Vs(info,vs) (info->curr_ssv = (((u8) vs) << 1)) +#define FRMR_INFO_SET_Vr(info,vr) (info->curr_rsv = (((u8) vr) << 1)) + +/* + * Info is pointer to FRMR info field structure; 'cr' is a byte containing + * the C/R bit value in the low-order bit + */ +#define FRMR_INFO_SET_C_R_BIT(info, cr) (info->curr_rsv |= (((u8) cr) & 0x01)) + +/* + * In the remaining five macros, 'info' is pointer to FRMR info field + * structure; 'ind' is a byte containing the bit value to set in the + * lowest-order bit) + */ +#define FRMR_INFO_SET_INVALID_PDU_CTRL_IND(info, ind) \ + (info->ind_bits = ((info->ind_bits & 0xFE) | (((u8) ind) & 0x01))) + +#define FRMR_INFO_SET_INVALID_PDU_INFO_IND(info, ind) \ + (info->ind_bits = ( (info->ind_bits & 0xFD) | (((u8) ind) & 0x02))) + +#define FRMR_INFO_SET_PDU_INFO_2LONG_IND(info, ind) \ + (info->ind_bits = ( (info->ind_bits & 0xFB) | (((u8) ind) & 0x04))) + +#define FRMR_INFO_SET_PDU_INVALID_Nr_IND(info, ind) \ + (info->ind_bits = ( (info->ind_bits & 0xF7) | (((u8) ind) & 0x08))) + +#define FRMR_INFO_SET_PDU_INVALID_Ns_IND(info, ind) \ + (info->ind_bits = ( (info->ind_bits & 0xEF) | (((u8) ind) & 0x10))) + +/* Sequence-numbered PDU format (4 bytes in length) */ +typedef struct llc_pdu_sn { + u8 dsap; + u8 ssap; + u8 ctrl_1; + u8 ctrl_2; +} llc_pdu_sn_t; + +/* Un-numbered PDU format (3 bytes in length) */ +typedef struct llc_pdu_un { + u8 dsap; + u8 ssap; + u8 ctrl_1; +} llc_pdu_un_t; + +/* LLC Type 1 XID command/response information fields format */ +typedef struct llc_xid_info { + u8 fmt_id; /* always 0x18 for LLC */ + u8 type; /* different if NULL/non-NULL LSAP */ + u8 rw; /* sender receive window */ +} llc_xid_info_t; + +/* LLC Type 2 FRMR response information field format */ +typedef struct llc_frmr_info { + u16 rej_pdu_ctrl; /* bits 1-8 if U-PDU */ + u8 curr_ssv; /* current send state variable val */ + u8 curr_rsv; /* current receive state variable */ + u8 ind_bits; /* indicator bits set with macro */ +} llc_frmr_info_t; + +extern void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 type); +extern void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value); +extern int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit); +extern int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit); +extern int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa); +extern int llc_pdu_decode_da(struct sk_buff *skb, u8 *ds); +extern int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap); +extern int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap); +extern int llc_decode_pdu_type(struct sk_buff *skb, u8 *destination); +extern void llc_pdu_header_init(struct sk_buff *skb, u8 pdu_type, u8 ssap, + u8 dsap, u8 cr); +extern int llc_pdu_init_as_ui_cmd(struct sk_buff *skb); +extern int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, + u8 rx_window); +extern int llc_pdu_init_as_test_cmd(struct sk_buff *skb); +extern int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit); +extern int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr); +extern int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit); +extern int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit); +extern int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, + u8 rx_window); +extern int llc_pdu_init_as_test_rsp(struct sk_buff *skb, + struct sk_buff *ev_skb); +extern int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, llc_pdu_sn_t *prev_pdu, + u8 f_bit, u8 vs, u8 vr, u8 vzyxw); +extern int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit); +#endif /* LLC_PDU_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_s_ac.h linux.20pre2-ac1/include/net/llc_s_ac.h --- linux.20pre2/include/net/llc_s_ac.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_s_ac.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,47 @@ +#ifndef LLC_S_AC_H +#define LLC_S_AC_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* SAP component actions */ +#define SAP_ACT_UNITDATA_IND 1 +#define SAP_ACT_SEND_UI 2 +#define SAP_ACT_SEND_XID_C 3 +#define SAP_ACT_SEND_XID_R 4 +#define SAP_ACT_SEND_TEST_C 5 +#define SAP_ACT_SEND_TEST_R 6 +#define SAP_ACT_REPORT_STATUS 7 +#define SAP_ACT_XID_IND 8 +#define SAP_ACT_TEST_IND 9 + +/* All action functions must look like this */ +typedef int (*llc_sap_action_t)(struct llc_sap *sap, + struct llc_sap_state_ev *ev); + +extern int llc_sap_action_unitdata_ind(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_action_send_ui(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_action_send_xid_c(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_action_send_xid_r(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_action_send_test_c(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_action_send_test_r(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_action_report_status(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_action_xid_ind(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_action_test_ind(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +#endif /* LLC_S_AC_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_sap.h linux.20pre2-ac1/include/net/llc_sap.h --- linux.20pre2/include/net/llc_sap.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_sap.h 2002-08-14 14:41:31.000000000 +0100 @@ -0,0 +1,42 @@ +#ifndef LLC_SAP_H +#define LLC_SAP_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +/* Defines the SAP component */ +struct llc_sap { + u8 state; + struct llc_station *parent_station; + u8 p_bit; /* only lowest-order bit used */ + u8 f_bit; /* only lowest-order bit used */ + llc_prim_call_t req; /* provided by LLC layer */ + llc_prim_call_t resp; /* provided by LLC layer */ + llc_prim_call_t ind; /* provided by network layer */ + llc_prim_call_t conf; /* provided by network layer */ + struct llc_addr laddr; /* SAP value in this 'lsap' */ + struct list_head node; /* entry in station sap_list */ + struct { + spinlock_t lock; + struct list_head list; + } sk_list; /* LLC sockets this one manages */ + struct sk_buff_head mac_pdu_q; /* PDUs ready to send to MAC */ +}; +struct llc_sap_state_ev; + +extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk); +extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk); +extern void llc_sap_send_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev); +extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb, + struct llc_sap_state_ev *ev); +extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb); +extern struct llc_sap_state_ev *llc_sap_alloc_ev(struct llc_sap *sap); +#endif /* LLC_SAP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_s_ev.h linux.20pre2-ac1/include/net/llc_s_ev.h --- linux.20pre2/include/net/llc_s_ev.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_s_ev.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,101 @@ +#ifndef LLC_S_EV_H +#define LLC_S_EV_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Defines SAP component events */ +/* Types of events (possible values in 'ev->type') */ +#define LLC_SAP_EV_TYPE_SIMPLE 1 +#define LLC_SAP_EV_TYPE_CONDITION 2 +#define LLC_SAP_EV_TYPE_PRIM 3 +#define LLC_SAP_EV_TYPE_PDU 4 /* command/response PDU */ +#define LLC_SAP_EV_TYPE_ACK_TMR 5 +#define LLC_SAP_EV_TYPE_RPT_STATUS 6 + +#define LLC_SAP_EV_ACTIVATION_REQ 1 +#define LLC_SAP_EV_RX_UI 2 +#define LLC_SAP_EV_UNITDATA_REQ 3 +#define LLC_SAP_EV_XID_REQ 4 +#define LLC_SAP_EV_RX_XID_C 5 +#define LLC_SAP_EV_RX_XID_R 6 +#define LLC_SAP_EV_TEST_REQ 7 +#define LLC_SAP_EV_RX_TEST_C 8 +#define LLC_SAP_EV_RX_TEST_R 9 +#define LLC_SAP_EV_DEACTIVATION_REQ 10 + +/* Interfaces for various types of supported events */ +struct llc_sap_ev_simple_if { + u8 ev; +}; + +struct llc_prim_if_block; + +struct llc_sap_ev_prim_if { + u8 prim; /* connect, disconnect, reset, ... */ + u8 type; /* request, indicate, response, conf */ + struct llc_prim_if_block *data; +}; + +struct llc_sap_ev_pdu_if { + u8 ev; + u8 reason; + struct sk_buff *skb; +}; + +struct llc_sap_ev_tmr_if { + void *timer_specific; +}; + +struct llc_sap_ev_rpt_sts_if { + u8 status; +}; + +union llc_sap_ev_if { + struct llc_sap_ev_simple_if a; /* 'a' for simple, easy ... */ + struct llc_sap_ev_prim_if prim; + struct llc_sap_ev_pdu_if pdu; + struct llc_sap_ev_tmr_if tmr; + struct llc_sap_ev_rpt_sts_if rsts; /* report status */ +}; + +struct llc_prim_if_block; + +struct llc_sap_state_ev { + u8 type; + u8 ind_cfm_flag; + struct llc_prim_if_block *prim; + union llc_sap_ev_if data; +}; + +struct llc_sap; + +typedef int (*llc_sap_ev_t)(struct llc_sap *sap, struct llc_sap_state_ev *ev); + +extern int llc_sap_ev_activation_req(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_ev_rx_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev); +extern int llc_sap_ev_unitdata_req(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_ev_xid_req(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_ev_rx_xid_c(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_ev_rx_xid_r(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_ev_test_req(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_ev_rx_test_c(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_ev_rx_test_r(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +extern int llc_sap_ev_deactivation_req(struct llc_sap *sap, + struct llc_sap_state_ev *ev); +#endif /* LLC_S_EV_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_s_st.h linux.20pre2-ac1/include/net/llc_s_st.h --- linux.20pre2/include/net/llc_s_st.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_s_st.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,34 @@ +#ifndef LLC_S_ST_H +#define LLC_S_ST_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Defines SAP component states */ + +#define LLC_SAP_STATE_INACTIVE 1 +#define LLC_SAP_STATE_ACTIVE 2 +#define LLC_NBR_SAP_STATES 2 /* size of state table */ +/* structures and types */ +/* SAP state table structure */ +struct llc_sap_state_trans { + llc_sap_ev_t ev; + u8 next_state; + llc_sap_action_t *ev_actions; +}; + +struct llc_sap_state { + u8 curr_state; + struct llc_sap_state_trans **transitions; +}; + +/* only access to SAP state table */ +extern struct llc_sap_state llc_sap_state_table[LLC_NBR_SAP_STATES]; +#endif /* LLC_S_ST_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/llc_stat.h linux.20pre2-ac1/include/net/llc_stat.h --- linux.20pre2/include/net/llc_stat.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/include/net/llc_stat.h 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,35 @@ +#ifndef LLC_STAT_H +#define LLC_STAT_H +/* + * Copyright (c) 1997 by Procom Technology,Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +/* Station component state table */ +/* Station component states */ +#define LLC_STATION_STATE_DOWN 1 /* initial state */ +#define LLC_STATION_STATE_DUP_ADDR_CHK 2 +#define LLC_STATION_STATE_UP 3 + +#define LLC_NBR_STATION_STATES 3 /* size of state table */ + +/* Station component state table structure */ +struct llc_station_state_trans { + llc_station_ev_t ev; + u8 next_state; + llc_station_action_t *ev_actions; +}; + +struct llc_station_state { + u8 curr_state; + struct llc_station_state_trans **transitions; +}; + +extern struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES]; +#endif /* LLC_STAT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/net/p8022.h linux.20pre2-ac1/include/net/p8022.h --- linux.20pre2/include/net/p8022.h 2002-08-13 13:58:17.000000000 +0100 +++ linux.20pre2-ac1/include/net/p8022.h 2002-08-06 15:41:52.000000000 +0100 @@ -1,7 +1,9 @@ #ifndef _NET_P8022_H #define _NET_P8022_H - -extern struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *)); +extern struct datalink_proto *register_8022_client(unsigned char type, + int (*rcvfunc) + (struct sk_buff *, + struct net_device *, + struct packet_type *)); extern void unregister_8022_client(unsigned char type); - #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/scsi/scsi.h linux.20pre2-ac1/include/scsi/scsi.h --- linux.20pre2/include/scsi/scsi.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/scsi/scsi.h 2002-08-06 15:41:52.000000000 +0100 @@ -89,6 +89,8 @@ #define SEND_VOLUME_TAG 0xb6 #define WRITE_LONG_2 0xea +#define SCSI_RETRY_10(c) ((c) == READ_6 || (c) == WRITE_6 || (c) == SEEK_6) + /* * Status codes */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/scsi/sg.h linux.20pre2-ac1/include/scsi/sg.h --- linux.20pre2/include/scsi/sg.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/scsi/sg.h 2002-08-06 15:41:52.000000000 +0100 @@ -11,9 +11,12 @@ Version 2 and 3 extensions to driver: * Copyright (C) 1998 - 2002 Douglas Gilbert - Version: 3.1.23 (20020318) + Version: 3.1.24 (20020505) This version is for 2.4 series kernels. + Changes since 3.1.23 (20020318) + - off by one fix for last scatter gather element + - zero buffer obtained for non-root users Changes since 3.1.22 (20011208) - change EACCES to EPERM when O_RDONLY is insufficient - suppress newlines in host string ( /proc/scsi/sg/host_strs output) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/include/video/fbcon.h linux.20pre2-ac1/include/video/fbcon.h --- linux.20pre2/include/video/fbcon.h 2002-08-13 13:58:18.000000000 +0100 +++ linux.20pre2-ac1/include/video/fbcon.h 2002-08-06 15:41:52.000000000 +0100 @@ -206,7 +206,8 @@ #define fb_writel sbus_writel #define fb_memset sbus_memset_io -#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) +#elif defined(__i386__) || defined(__alpha__) || \ + defined(__x86_64__) || defined(__hppa__) #define fb_readb __raw_readb #define fb_readw __raw_readw diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/init/do_mounts.c linux.20pre2-ac1/init/do_mounts.c --- linux.20pre2/init/do_mounts.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/init/do_mounts.c 2002-08-07 14:05:32.000000000 +0100 @@ -163,7 +163,6 @@ { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) }, { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) }, #endif -#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE) { "ida/c0d0p",0x4800 }, { "ida/c0d1p",0x4810 }, { "ida/c0d2p",0x4820 }, @@ -180,8 +179,6 @@ { "ida/c0d13p",0x48D0 }, { "ida/c0d14p",0x48E0 }, { "ida/c0d15p",0x48F0 }, -#endif -#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE) { "cciss/c0d0p",0x6800 }, { "cciss/c0d1p",0x6810 }, { "cciss/c0d2p",0x6820 }, @@ -198,7 +195,6 @@ { "cciss/c0d13p",0x68D0 }, { "cciss/c0d14p",0x68E0 }, { "cciss/c0d15p",0x68F0 }, -#endif { "ataraid/d0p",0x7200 }, { "ataraid/d1p",0x7210 }, { "ataraid/d2p",0x7220 }, @@ -215,6 +211,24 @@ { "ataraid/d13p",0x72D0 }, { "ataraid/d14p",0x72E0 }, { "ataraid/d15p",0x72F0 }, + { "rd/c0d0p",0x3000 }, + { "rd/c0d0p1",0x3001 }, + { "rd/c0d0p2",0x3002 }, + { "rd/c0d0p3",0x3003 }, + { "rd/c0d0p4",0x3004 }, + { "rd/c0d0p5",0x3005 }, + { "rd/c0d0p6",0x3006 }, + { "rd/c0d0p7",0x3007 }, + { "rd/c0d0p8",0x3008 }, + { "rd/c0d1p",0x3008 }, + { "rd/c0d1p1",0x3009 }, + { "rd/c0d1p2",0x300a }, + { "rd/c0d1p3",0x300b }, + { "rd/c0d1p4",0x300c }, + { "rd/c0d1p5",0x300d }, + { "rd/c0d1p6",0x300e }, + { "rd/c0d1p7",0x300f }, + { "rd/c0d1p8",0x3010 }, { "nftla", 0x5d00 }, { "nftlb", 0x5d10 }, { "nftlc", 0x5d20 }, @@ -776,10 +790,8 @@ pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) { - while (pid != wait(&i)) { - current->policy |= SCHED_YIELD; - schedule(); - } + while (pid != wait(&i)) + yield(); } sys_mount("..", ".", NULL, MS_MOVE, NULL); @@ -862,6 +874,8 @@ mount_devfs_fs (); } +#ifdef CONFIG_BLK_DEV_RAM + #ifdef BUILD_CRAMDISK /* @@ -1008,3 +1022,5 @@ } #endif /* BUILD_CRAMDISK */ + +#endif /* CONFIG_BLK_DEV_RAM */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/init/main.c linux.20pre2-ac1/init/main.c --- linux.20pre2/init/main.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/init/main.c 2002-08-06 15:41:51.000000000 +0100 @@ -60,6 +60,10 @@ #include #endif +#ifdef CONFIG_PNPBIOS +#include +#endif + #ifdef CONFIG_IRDA extern int irda_proto_init(void); extern int irda_device_init(void); @@ -100,12 +104,19 @@ #ifdef CONFIG_TC extern void tc_init(void); #endif +#ifdef CONFIG_SPEAKUP +extern void speakup_register_devsynth(void); /* had to move this out of console_init() */ +#endif extern void ecard_init(void); #if defined(CONFIG_SYSVIPC) extern void ipc_init(void); #endif + +#ifdef CONFIG_PARISC +extern void parisc_init(void); +#endif /* * Boot command-line arguments @@ -288,8 +299,6 @@ extern void setup_arch(char **); extern void cpu_idle(void); -unsigned long wait_init_idle; - #ifndef CONFIG_SMP #ifdef CONFIG_X86_LOCAL_APIC @@ -298,34 +307,24 @@ APIC_init_uniprocessor(); } #else -#define smp_init() do { } while (0) +#define smp_init() do { } while (0) #endif #else - /* Called by boot processor to activate the rest. */ static void __init smp_init(void) { /* Get other processors into their bootup holding patterns. */ smp_boot_cpus(); - wait_init_idle = cpu_online_map; - clear_bit(current->processor, &wait_init_idle); /* Don't wait on me! */ smp_threads_ready=1; smp_commence(); - - /* Wait for the other cpus to set up their idle processes */ - printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle); - while (wait_init_idle) { - cpu_relax(); - barrier(); - } - printk("All processors have done init_idle\n"); } #endif + /* * We need to finalize in a non-__init function or else race conditions * between the root thread and the init thread may cause start_kernel to @@ -337,9 +336,8 @@ { kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); unlock_kernel(); - current->need_resched = 1; - cpu_idle(); -} + cpu_idle(); +} /* * Activate the first processor. @@ -420,18 +418,25 @@ #ifdef CONFIG_PROC_FS proc_root_init(); #endif +#ifdef CONFIG_PARISC + parisc_init(); +#endif #if defined(CONFIG_SYSVIPC) ipc_init(); #endif check_bugs(); + printk("POSIX conformance testing by UNIFIX\n"); - /* - * We count on the initial thread going ok - * Like idlers init is an unlocked kernel thread, which will - * make syscalls (and thus be locked). + init_idle(current, smp_processor_id()); + /* + * We count on the initial thread going ok + * Like idlers init is an unlocked kernel thread, which will + * make syscalls (and thus be locked). */ smp_init(); + + /* Do the rest non-__init'ed, we're now alive */ rest_init(); } @@ -460,6 +465,10 @@ */ static void __init do_basic_setup(void) { + /* Start the per-CPU migration threads */ +#if CONFIG_SMP + migration_init(); +#endif /* * Tell the world that we're going to be the grim @@ -519,9 +528,15 @@ #ifdef CONFIG_ISAPNP isapnp_init(); #endif +#ifdef CONFIG_PNPBIOS + pnpbios_init(); +#endif #ifdef CONFIG_TC tc_init(); #endif +#ifdef CONFIG_SPEAKUP + speakup_register_devsynth(); /* registers the misc device /dev/synth */ +#endif /* Networking initialization needs a process context */ sock_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/ipc/shm.c linux.20pre2-ac1/ipc/shm.c --- linux.20pre2/ipc/shm.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/ipc/shm.c 2002-08-06 15:42:06.000000000 +0100 @@ -680,7 +680,7 @@ shmdnext = shmd->vm_next; if (shmd->vm_ops == &shm_vm_ops && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) { - do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start); + do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start, 1); retval = 0; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/ipc/util.c linux.20pre2-ac1/ipc/util.c --- linux.20pre2/ipc/util.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/ipc/util.c 2002-08-06 17:22:19.000000000 +0100 @@ -312,7 +312,7 @@ out->seq = in->seq; } -#ifndef __ia64__ +#if !defined(__ia64__) && !defined(__hppa__) /** * ipc_parse_version - IPC call version diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/ipc/util.h linux.20pre2-ac1/ipc/util.h --- linux.20pre2/ipc/util.h 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/ipc/util.h 2002-08-06 15:42:06.000000000 +0100 @@ -99,8 +99,8 @@ void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); -#ifdef __ia64__ - /* On IA-64, we always use the "64-bit version" of the IPC structures. */ +#if defined(__ia64__) || defined(__hppa__) + /* On IA-64 and PA-RISC, we always use the "64-bit version" of the IPC structures. */ # define ipc_parse_version(cmd) IPC_64 #else int ipc_parse_version (int *cmd); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/acct.c linux.20pre2-ac1/kernel/acct.c --- linux.20pre2/kernel/acct.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/acct.c 2002-08-06 15:41:51.000000000 +0100 @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -299,8 +300,10 @@ ac.ac_etime = encode_comp_t(jiffies - current->start_time); ac.ac_utime = encode_comp_t(current->times.tms_utime); ac.ac_stime = encode_comp_t(current->times.tms_stime); - ac.ac_uid = current->uid; - ac.ac_gid = current->gid; + ac.ac_uid = fs_high2lowuid(current->uid); + ac.ac_gid = fs_high2lowgid(current->gid); + ac.ac_uid32 = current->uid; + ac.ac_gid32 = current->gid; ac.ac_tty = (current->tty) ? kdev_t_to_nr(current->tty->device) : 0; ac.ac_flag = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/capability.c linux.20pre2-ac1/kernel/capability.c --- linux.20pre2/kernel/capability.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/capability.c 2002-08-06 15:41:51.000000000 +0100 @@ -8,6 +8,8 @@ #include #include +unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ + kernel_cap_t cap_bset = CAP_INIT_EFF_SET; /* Note: never hold tasklist_lock while spinning for this one */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/cpufreq.c linux.20pre2-ac1/kernel/cpufreq.c --- linux.20pre2/kernel/cpufreq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/kernel/cpufreq.c 2002-08-06 15:41:51.000000000 +0100 @@ -0,0 +1,609 @@ +/* + * linux/kernel/cpufreq.c + * + * Copyright (C) 2001 Russell King + * (C) 2002 Dominik Brodowski + * + * $Id: cpufreq.c,v 1.29 2002/06/28 16:43:17 db Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * CPU speed changing core functionality. We provide the following + * services to the system: + * - notifier lists to inform other code of the freq change both + * before and after the freq change. + * - the ability to change the freq speed + * + * ** You'll need to add CTL_CPU = 10 to include/linux/sysctl.h if + * it's not already present. + * + * When this appears in the kernel, the sysctl enums will move to + * include/linux/sysctl.h + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include /* requires system.h */ + + +/* + * This list is for kernel code that needs to handle + * changes to devices when the CPU clock speed changes. + */ +static struct notifier_block *cpufreq_notifier_list; +static DECLARE_MUTEX (cpufreq_notifier_sem); + +/* + * This is internal information about the actual transition + * driver. + */ +static struct cpufreq_driver cpufreq_driver; +static DECLARE_MUTEX (cpufreq_driver_sem); + +/* + * Some data for the CPUFreq core - loops_per_jiffy / frequency values at boot + */ +static unsigned long cpufreq_ref_loops; +static unsigned int cpufreq_ref_freq; + + + +/** + * scale - "old * mult / div" calculation for large values (32-bit-arch safe) + * @old: old value + * @div: divisor + * @mult: multiplier + * + * Needed for loops_per_jiffy calculation. We do it this way to + * avoid math overflow on 32-bit machines. Maybe we should make + * this architecture dependent? If you have a better way of doing + * this, please replace! + * + * new = old * mult / div + */ +static unsigned long scale(unsigned long old, u_int div, u_int mult) +{ + unsigned long low_part, high_part; + + high_part = old / div; + low_part = (old % div) / 100; + high_part *= mult; + low_part = low_part * mult / div; + + return high_part + low_part * 100; +} + + +/** + * cpufreq_setup - cpufreq command line parameter parsing + * + * cpufreq command line parameter. Use: + * cpufreq=59000-221000 + * to set the CPU frequency to 59 to 221MHz. + */ +static int __init cpufreq_setup(char *str) +{ + unsigned int min, max; + + min = 0; + max = simple_strtoul(str, &str, 0); + if (*str == '-') { + min = max; + max = simple_strtoul(str + 1, NULL, 0); + } + + down(&cpufreq_driver_sem); + cpufreq_driver.freq.max = max; + cpufreq_driver.freq.min = min; + up(&cpufreq_driver_sem); + + return 1; +} +__setup("cpufreq=", cpufreq_setup); + + +/** + * adjust_jiffies - adjust the system "loops_per_jiffy" + * + * This function alters the system "loops_per_jiffy" for the clock + * speed change. We ignore CPUFREQ_DRIVER.MINMAX here. + */ +static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) +{ + if ((val == CPUFREQ_PRECHANGE && ci->cur < ci->new) || + (val == CPUFREQ_POSTCHANGE && ci->cur > ci->new)) + loops_per_jiffy = scale(cpufreq_ref_loops, cpufreq_ref_freq, + ci->new); +} + + + +/********************************************************************* + * NOTIFIER LIST INTERFACE * + *********************************************************************/ + + +/** + * cpufreq_register_notifier - register a driver with cpufreq + * @nb: notifier function to register + * + * Add a driver to the list of drivers that which to be notified about + * CPU clock rate changes. The driver will be called three times on + * clock change. + * + * This function may sleep, and has the same return conditions as + * notifier_chain_register. + */ +int cpufreq_register_notifier(struct notifier_block *nb) +{ + int ret; + + down(&cpufreq_notifier_sem); + ret = notifier_chain_register(&cpufreq_notifier_list, nb); + up(&cpufreq_notifier_sem); + + return ret; +} +EXPORT_SYMBOL(cpufreq_register_notifier); + + +/** + * cpufreq_unregister_notifier - unregister a driver with cpufreq + * @nb: notifier block to be unregistered + * + * Remove a driver from the CPU frequency notifier lists. + * + * This function may sleep, and has the same return conditions as + * notifier_chain_unregister. + */ +int cpufreq_unregister_notifier(struct notifier_block *nb) +{ + int ret; + + down(&cpufreq_notifier_sem); + ret = notifier_chain_unregister(&cpufreq_notifier_list, nb); + up(&cpufreq_notifier_sem); + + return ret; +} +EXPORT_SYMBOL(cpufreq_unregister_notifier); + + + +/********************************************************************* + * GET / SET PROCESSOR SPEED * + *********************************************************************/ + +/** + * cpu_setfreq - change the CPU clock frequency. + * @freq: frequency (in kHz) at which we should run. + * + * Set the CPU clock frequency, informing all registered users of + * the change. We bound the frequency according to the cpufreq + * command line parameter, information obtained from the cpufreq + * driver, and the parameters the registered users will allow. + * + * This function must be called from process context. + * + * We return 0 if successful, -EINVAL if no CPUFreq architecture + * driver is registered, and -ENXIO if the driver is invalid. + */ +int cpufreq_set(unsigned int freq) +{ + struct cpufreq_freqs cpufreq; + int ret; + + if (in_interrupt()) + panic("cpufreq_set() called from interrupt context!"); + + down(&cpufreq_driver_sem); + down(&cpufreq_notifier_sem); + + if (!cpufreq_driver.initialised) { + ret = -EINVAL; + goto out; + } + + ret = -ENXIO; + if (!cpufreq_driver.setspeed || !cpufreq_driver.validate) + goto out; + + /* + * Don't allow the CPU to be clocked over the limit. + */ + cpufreq.min = cpufreq_driver.freq.min; + cpufreq.max = cpufreq_driver.freq.max; + cpufreq.cur = cpufreq_driver.freq.cur; + cpufreq.new = freq; + + /* + * Find out what the registered devices will currently tolerate, + * and limit the requested clock rate to these values. Drivers + * must not rely on the 'new' value - it is only a guide. + */ + notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_MINMAX, &cpufreq); + + if (freq < cpufreq.min) + freq = cpufreq.min; + if (freq > cpufreq.max) + freq = cpufreq.max; + + /* + * Ask the CPU specific code to validate the speed. If the speed + * is not acceptable, make it acceptable. Current policy is to + * round the frequency down to the value the processor actually + * supports. + */ + freq = cpufreq_driver.validate(freq); + + if (cpufreq_driver.freq.cur != freq) { + cpufreq.cur = cpufreq_driver.freq.cur; + cpufreq.new = freq; + + notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_PRECHANGE, + &cpufreq); + + adjust_jiffies(CPUFREQ_PRECHANGE, &cpufreq); + + /* + * Actually set the CPU frequency. + */ + + cpufreq_driver.setspeed(freq); + + cpufreq_driver.freq.cur = freq; + adjust_jiffies(CPUFREQ_POSTCHANGE, &cpufreq); + + notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_POSTCHANGE, + &cpufreq); + + ret = 0; + } + + out: + up(&cpufreq_notifier_sem); + up(&cpufreq_driver_sem); + + return ret; +} +EXPORT_SYMBOL_GPL(cpufreq_set); + + +/** + * cpufreq_setmax - set the CPUs to maximum frequency + * + * Sets the CPUs to maximum frequency. + */ +int cpufreq_setmax(void) +{ + return cpufreq_set(cpufreq_driver.freq.max); +} +EXPORT_SYMBOL_GPL(cpufreq_setmax); + + +/** + * cpufreq_get - get the CPU frequency in kHz (zero means failure) + * + * Returns the CPU frequency in kHz or zero on failure. + */ +unsigned int cpufreq_get(void) +{ + if (!cpufreq_driver.initialised) + return 0; + return cpufreq_driver.freq.cur; +} +EXPORT_SYMBOL(cpufreq_get); + + +#ifdef CONFIG_PM +/** + * cpufreq_restore - restore the CPU clock frequency after resume + * + * Restore the CPU clock frequency so that our idea of the current + * frequency reflects the actual hardware. + */ +int cpufreq_restore(void) +{ + int ret; + + if (in_interrupt()) + panic("cpufreq_restore() called from interrupt context!"); + + down(&cpufreq_driver_sem); + if (!cpufreq_driver.initialised) { + up(&cpufreq_driver_sem); + return -EINVAL; + } + ret = -ENXIO; + if (cpufreq_driver.setspeed) { + cpufreq_driver.setspeed(cpufreq_driver.freq.cur); + ret = 0; + } + + up(&cpufreq_driver_sem); + + return ret; +} +EXPORT_SYMBOL_GPL(cpufreq_restore); +#endif + + + +/********************************************************************* + * SYSCTL INTERFACE * + *********************************************************************/ + +#ifdef CONFIG_SYSCTL + +struct ctl_table_header *cpufreq_sysctl_table; + +static int +cpufreq_procctl(ctl_table *ctl, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + char buf[16], *p; + int len, left = *lenp; + + if (!left || (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + if (write) { + unsigned int freq; + + len = left; + if (left > sizeof(buf)) + left = sizeof(buf); + if (copy_from_user(buf, buffer, left)) + return -EFAULT; + buf[sizeof(buf) - 1] = '\0'; + + freq = simple_strtoul(buf, &p, 0); + cpufreq_set(freq); + } else { + len = sprintf(buf, "%d\n", cpufreq_get()); + if (len > left) + len = left; + if (copy_to_user(buffer, buf, len)) + return -EFAULT; + } + + *lenp = len; + filp->f_pos += len; + return 0; +} + +static int +cpufreq_sysctl(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + + if (oldval && oldlenp) { + size_t oldlen; + + if (get_user(oldlen, oldlenp)) + return -EFAULT; + + if (oldlen != sizeof(unsigned int)) + return -EINVAL; + + if (put_user(cpufreq_get(), (unsigned int *)oldval) || + put_user(sizeof(unsigned int), oldlenp)) + return -EFAULT; + } + if (newval && newlen) { + unsigned int freq; + + if (newlen != sizeof(unsigned int)) + return -EINVAL; + + if (get_user(freq, (unsigned int *)newval)) + return -EFAULT; + + cpufreq_set(freq); + } + return 1; +} + +enum { + CPU_NR_FREQ_MAX = 1, + CPU_NR_FREQ_MIN = 2, + CPU_NR_FREQ = 3 +}; + +static ctl_table ctl_cpu_vars[4] = { + { + ctl_name: CPU_NR_FREQ_MAX, + procname: "speed-max", + data: &cpufreq_driver.freq.max, + maxlen: sizeof(cpufreq_driver.freq.max), + mode: 0444, + proc_handler: proc_dointvec, + }, + { + ctl_name: CPU_NR_FREQ_MIN, + procname: "speed-min", + data: &cpufreq_driver.freq.min, + maxlen: sizeof(cpufreq_driver.freq.min), + mode: 0444, + proc_handler: proc_dointvec, + }, + { + ctl_name: CPU_NR_FREQ, + procname: "speed", + mode: 0644, + proc_handler: cpufreq_procctl, + strategy: cpufreq_sysctl, + }, + { + ctl_name: 0, + } +}; + +enum { + CPU_NR = 1, +}; + +static ctl_table ctl_cpu_nr[2] = { + { + ctl_name: CPU_NR, +#ifndef CONFIG_SMP + procname: "0", +#else + procname: "all", +#endif + mode: 0555, + child: ctl_cpu_vars, + }, + { + ctl_name: 0, + } +}; + +static ctl_table ctl_cpu[2] = { + { + ctl_name: CTL_CPU, + procname: "cpu", + mode: 0555, + child: ctl_cpu_nr, + }, + { + ctl_name: 0, + } +}; + +static inline void cpufreq_sysctl_register(void) +{ + cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0); +} +static inline void cpufreq_sysctl_unregister(void) +{ + unregister_sysctl_table(cpufreq_sysctl_table); +} + +#else +#define cpufreq_sysctl_register() +#define cpufreq_sysctl_unregister() +#endif + + + + +/********************************************************************* + * REGISTER / UNREGISTER CPUFREQ DRIVER * + *********************************************************************/ + + +/** + * cpufreq_register - register a CPU Frequency driver + * @driver_data: A struct cpufreq_driver containing the values submitted by the CPU Frequency driver. + * + * driver_data should contain the following elements: + * freq.min is the minimum frequency the CPU / the CPUs can be set to + * (optional), freq.max is the maximum frequency (optional), freq.cur + * is the current frequency, validate points to a function returning + * the closest available CPU frequency, and setspeed points to a + * function performing the actual transition. + * + * All other variables are currently ignored. + * + * + * Registers a CPU Frequency driver to this core code. This code + * returns zero on success, -EBUSY when another driver got here first + * (and isn't unregistered in the meantime). + * + */ +int cpufreq_register(struct cpufreq_driver driver_data) +{ + if (cpufreq_driver.initialised) + return -EBUSY; + + down(&cpufreq_driver_sem); + + /* + * If the user doesn't tell us the maximum frequency, + * or if it is invalid, use the values determined + * by the cpufreq-arch-specific initialization functions. + * The validatespeed code is responsible for limiting + * this further. + */ + + if (driver_data.freq.max && + (!cpufreq_driver.freq.max || + (cpufreq_driver.freq.max > driver_data.freq.max))) + cpufreq_driver.freq.max = driver_data.freq.max; + if (driver_data.freq.min && + (!cpufreq_driver.freq.min || + (cpufreq_driver.freq.min < driver_data.freq.min))) + cpufreq_driver.freq.min = driver_data.freq.min; + + if (!cpufreq_driver.freq.max) + cpufreq_driver.freq.max = driver_data.freq.cur; + + cpufreq_driver.freq.cur = driver_data.freq.cur; + cpufreq_driver.validate = driver_data.validate; + cpufreq_driver.setspeed = driver_data.setspeed; + + printk(KERN_INFO "CPU clock: %d.%03d MHz (%d.%03d-%d.%03d MHz)\n", + cpufreq_driver.freq.cur / 1000, cpufreq_driver.freq.cur % 1000, + cpufreq_driver.freq.min / 1000, cpufreq_driver.freq.min % 1000, + cpufreq_driver.freq.max / 1000, cpufreq_driver.freq.max % 1000); + + cpufreq_ref_loops = loops_per_jiffy; + cpufreq_ref_freq = cpufreq_driver.freq.cur; + cpufreq_driver.initialised = 1; + + cpufreq_sysctl_register(); + + up(&cpufreq_driver_sem); + + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_register); + + +/** + * cpufreq_unregister: + * + * Unregister the current CPUFreq driver. Only call this if you have + * the right to do so, i.e. if you have succeeded in initialising before! + * Returns zero if successful, and -EINVAL if the cpufreq_driver is + * currently not initialised. + */ +int cpufreq_unregister(void) +{ + down(&cpufreq_driver_sem); + + if (!cpufreq_driver.initialised) { + up(&cpufreq_driver_sem); + return -EINVAL; + } + + cpufreq_driver.validate = NULL; + cpufreq_driver.setspeed = NULL; + cpufreq_driver.initialised = 0; + + cpufreq_sysctl_unregister(); + + up(&cpufreq_driver_sem); + + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_unregister); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/exit.c linux.20pre2-ac1/kernel/exit.c --- linux.20pre2/kernel/exit.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/exit.c 2002-08-06 15:41:51.000000000 +0100 @@ -28,49 +28,22 @@ static void release_task(struct task_struct * p) { - if (p != current) { + if (p == current) + BUG(); #ifdef CONFIG_SMP - /* - * Wait to make sure the process isn't on the - * runqueue (active on some other CPU still) - */ - for (;;) { - task_lock(p); - if (!task_has_cpu(p)) - break; - task_unlock(p); - do { - cpu_relax(); - barrier(); - } while (task_has_cpu(p)); - } - task_unlock(p); + wait_task_inactive(p); #endif - atomic_dec(&p->user->processes); - free_uid(p->user); - unhash_process(p); - - release_thread(p); - current->cmin_flt += p->min_flt + p->cmin_flt; - current->cmaj_flt += p->maj_flt + p->cmaj_flt; - current->cnswap += p->nswap + p->cnswap; - /* - * Potentially available timeslices are retrieved - * here - this way the parent does not get penalized - * for creating too many processes. - * - * (this cannot be used to artificially 'generate' - * timeslices, because any timeslice recovered here - * was given away by the parent in the first place.) - */ - current->counter += p->counter; - if (current->counter >= MAX_COUNTER) - current->counter = MAX_COUNTER; - p->pid = 0; - free_task_struct(p); - } else { - printk("task releasing itself\n"); - } + atomic_dec(&p->user->processes); + free_uid(p->user); + unhash_process(p); + + release_thread(p); + current->cmin_flt += p->min_flt + p->cmin_flt; + current->cmaj_flt += p->maj_flt + p->cmaj_flt; + current->cnswap += p->nswap + p->cnswap; + sched_exit(p); + p->pid = 0; + free_task_struct(p); } /* @@ -150,6 +123,79 @@ return retval; } +/** + * reparent_to_init() - Reparent the calling kernel thread to the init task. + * + * If a kernel thread is launched as a result of a system call, or if + * it ever exits, it should generally reparent itself to init so that + * it is correctly cleaned up on exit. + * + * The various task state such as scheduling policy and priority may have + * been inherited from a user process, so we reset them to sane values here. + * + * NOTE that reparent_to_init() gives the caller full capabilities. + */ +void reparent_to_init(void) +{ + write_lock_irq(&tasklist_lock); + + /* Reparent to init */ + REMOVE_LINKS(current); + current->p_pptr = child_reaper; + current->p_opptr = child_reaper; + SET_LINKS(current); + + /* Set the exit signal to SIGCHLD so we signal init on exit */ + current->exit_signal = SIGCHLD; + + current->ptrace = 0; + if ((current->policy == SCHED_OTHER) && (task_nice(current) < 0)) + set_user_nice(current, 0); + /* cpus_allowed? */ + /* rt_priority? */ + /* signals? */ + current->cap_effective = CAP_INIT_EFF_SET; + current->cap_inheritable = CAP_INIT_INH_SET; + current->cap_permitted = CAP_FULL_SET; + current->keep_capabilities = 0; + memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim))); + current->user = INIT_USER; + + write_unlock_irq(&tasklist_lock); +} + +/* + * Put all the gunge required to become a kernel thread without + * attached user resources in one place where it belongs. + */ + +void daemonize(void) +{ + struct fs_struct *fs; + + + /* + * If we were started as result of loading a module, close all of the + * user space pages. We don't need them, and if we didn't close them + * they would be locked into memory. + */ + exit_mm(current); + + current->session = 1; + current->pgrp = 1; + current->tty = NULL; + + /* Become as one with the init task */ + + exit_fs(current); /* current->fs->count--; */ + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); + exit_files(current); + current->files = init_task.files; + atomic_inc(¤t->files->count); +} + /* * When we die, we re-parent all our children. * Try to give them to another thread in our thread diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/fork.c linux.20pre2-ac1/kernel/fork.c --- linux.20pre2/kernel/fork.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/kernel/fork.c 2002-08-13 14:53:59.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,6 @@ /* The idle threads do not count.. */ int nr_threads; -int nr_running; int max_threads; unsigned long total_forks; /* Handle normal Linux uptimes. */ @@ -38,6 +38,8 @@ struct task_struct *pidhash[PIDHASH_SZ]; +rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ + void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -143,6 +145,7 @@ { struct vm_area_struct * mpnt, *tmp, **pprev; int retval; + unsigned long charge = 0; flush_cache_mm(current->mm); mm->locked_vm = 0; @@ -151,7 +154,6 @@ mm->map_count = 0; mm->rss = 0; mm->cpu_vm_mask = 0; - mm->swap_address = 0; pprev = &mm->mmap; /* @@ -171,6 +173,15 @@ retval = -ENOMEM; if(mpnt->vm_flags & VM_DONTCOPY) continue; + + /* FIXME: shared writable map accounting should be one off */ + if(mpnt->vm_flags & VM_ACCOUNT) + { + unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + if(!vm_enough_memory(len)) + goto fail_nomem; + charge += len; + } tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!tmp) goto fail_nomem; @@ -214,10 +225,12 @@ } retval = 0; build_mmap_rb(mm); - -fail_nomem: +out: flush_tlb_mm(current->mm); return retval; +fail_nomem: + vm_unacct_memory(charge); + goto out; } spinlock_t mmlist_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; @@ -275,9 +288,6 @@ void mmput(struct mm_struct *mm) { if (atomic_dec_and_lock(&mm->mm_users, &mmlist_lock)) { - extern struct mm_struct *swap_mm; - if (swap_mm == mm) - swap_mm = list_entry(mm->mmlist.next, struct mm_struct, mmlist); list_del(&mm->mmlist); mmlist_nr--; spin_unlock(&mmlist_lock); @@ -578,6 +588,7 @@ struct pt_regs *regs, unsigned long stack_size) { int retval; + unsigned long flags; struct task_struct *p; struct completion vfork; @@ -638,8 +649,7 @@ if (p->pid == 0 && current->pid != 0) goto bad_fork_cleanup; - p->run_list.next = NULL; - p->run_list.prev = NULL; + INIT_LIST_HEAD(&p->run_list); p->p_cptr = NULL; init_waitqueue_head(&p->wait_chldexit); @@ -665,19 +675,18 @@ #ifdef CONFIG_SMP { int i; - p->cpus_runnable = ~0UL; - p->processor = current->processor; + /* ?? should we just memset this ?? */ for(i = 0; i < smp_num_cpus; i++) - p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + p->per_cpu_utime[cpu_logical_map(i)] = + p->per_cpu_stime[cpu_logical_map(i)] = 0; spin_lock_init(&p->sigmask_lock); } #endif + p->array = NULL; p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; - INIT_LIST_HEAD(&p->local_pages); - retval = -ENOMEM; /* copy all the process information */ if (copy_files(clone_flags, p)) @@ -706,15 +715,27 @@ p->pdeath_signal = 0; /* - * "share" dynamic priority between parent and child, thus the - * total amount of dynamic priorities in the system doesn't change, - * more scheduling fairness. This is only important in the first - * timeslice, on the long run the scheduling behaviour is unchanged. - */ - p->counter = (current->counter + 1) >> 1; - current->counter >>= 1; - if (!current->counter) - current->need_resched = 1; + * Share the timeslice between parent and child, thus the + * total amount of pending timeslices in the system doesnt change, + * resulting in more scheduling fairness. + */ + __save_flags(flags); + __cli(); + if (!current->time_slice) + BUG(); + p->time_slice = (current->time_slice + 1) >> 1; + current->time_slice >>= 1; + if (!current->time_slice) { + /* + * This case is rare, it happens when the parent has only + * a single jiffy left from its timeslice. Taking the + * runqueue lock is not a problem. + */ + current->time_slice = 1; + scheduler_tick(0,0); + } + p->sleep_timestamp = jiffies; + __restore_flags(flags); /* * Ok, add it to the run-queues and make it @@ -750,11 +771,16 @@ if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); - - wake_up_process(p); /* do this last */ + wake_up_forked_process(p); /* do this last */ ++total_forks; if (clone_flags & CLONE_VFORK) wait_for_completion(&vfork); + else + /* + * Let the child process run first, to avoid most of the + * COW overhead when the child exec()s afterwards. + */ + current->need_resched = 1; fork_out: return retval; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/kmod.c linux.20pre2-ac1/kernel/kmod.c --- linux.20pre2/kernel/kmod.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/kmod.c 2002-08-06 15:41:51.000000000 +0100 @@ -119,15 +119,8 @@ if (curtask->files->fd[i]) close(i); } - /* Drop the "current user" thing */ - { - struct user_struct *user = curtask->user; - curtask->user = INIT_USER; - atomic_inc(&INIT_USER->__count); - atomic_inc(&INIT_USER->processes); - atomic_dec(&user->processes); - free_uid(user); - } + /* Become root */ + set_user(0, 0); /* Give kmod all effective privileges.. */ curtask->euid = curtask->fsuid = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/ksyms.c linux.20pre2-ac1/kernel/ksyms.c --- linux.20pre2/kernel/ksyms.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/kernel/ksyms.c 2002-08-14 16:20:28.000000000 +0100 @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -109,6 +110,7 @@ EXPORT_SYMBOL(kfree); EXPORT_SYMBOL(vfree); EXPORT_SYMBOL(__vmalloc); +EXPORT_SYMBOL(vcalloc); EXPORT_SYMBOL(vmalloc_to_page); EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(remap_page_range); @@ -323,6 +325,7 @@ EXPORT_SYMBOL(refile_buffer); EXPORT_SYMBOL(max_sectors); EXPORT_SYMBOL(max_readahead); +EXPORT_SYMBOL(blkdev_varyio); /* tty routines */ EXPORT_SYMBOL(tty_hangup); @@ -442,7 +445,9 @@ /* process management */ EXPORT_SYMBOL(complete_and_exit); EXPORT_SYMBOL(__wake_up); -EXPORT_SYMBOL(__wake_up_sync); +#if CONFIG_SMP +EXPORT_SYMBOL_GPL(__wake_up_sync); /* internal use only */ +#endif EXPORT_SYMBOL(wake_up_process); EXPORT_SYMBOL(sleep_on); EXPORT_SYMBOL(sleep_on_timeout); @@ -450,8 +455,13 @@ EXPORT_SYMBOL(interruptible_sleep_on_timeout); EXPORT_SYMBOL(schedule); EXPORT_SYMBOL(schedule_timeout); -EXPORT_SYMBOL(yield); -EXPORT_SYMBOL(__cond_resched); +EXPORT_SYMBOL(sys_sched_yield); +EXPORT_SYMBOL(set_user_nice); +EXPORT_SYMBOL(task_nice); +EXPORT_SYMBOL_GPL(idle_cpu); +#ifdef CONFIG_SMP +EXPORT_SYMBOL_GPL(set_cpus_allowed); +#endif EXPORT_SYMBOL(jiffies); EXPORT_SYMBOL(xtime); EXPORT_SYMBOL(do_gettimeofday); @@ -463,6 +473,7 @@ EXPORT_SYMBOL(kstat); EXPORT_SYMBOL(nr_running); +EXPORT_SYMBOL(nr_context_switches); /* misc */ EXPORT_SYMBOL(panic); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/Makefile linux.20pre2-ac1/kernel/Makefile --- linux.20pre2/kernel/Makefile 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/Makefile 2002-08-11 21:27:21.000000000 +0100 @@ -9,7 +9,7 @@ O_TARGET := kernel.o -export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o +export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o cpufreq.o obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ @@ -19,6 +19,8 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_IKCONFIG) += configs.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is @@ -26,7 +28,21 @@ # me. I suspect most platforms don't need this, but until we know that for sure # I turn this off for IA-64 only. Andreas Schwab says it's also needed on m68k # to get a correct value for the wait-channel (WCHAN in ps). --davidm +# +# Some gcc's are building so that O(1) scheduler is triple faulting if we +# build -O2. (Turns out to be a CPU issue. Update your microcode if you hit it) +# CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer endif include $(TOPDIR)/Rules.make + +configs.o: $(TOPDIR)/scripts/mkconfigs configs.c + $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DEXPORT_SYMTAB -c -o configs.o configs.c + +$(TOPDIR)/scripts/mkconfigs: $(TOPDIR)/scripts/mkconfigs.c + $(HOSTCC) $(HOSTCFLAGS) -o $(TOPDIR)/scripts/mkconfigs $(TOPDIR)/scripts/mkconfigs.c + +configs.c: $(TOPDIR)/.config $(TOPDIR)/scripts/mkconfigs + $(TOPDIR)/scripts/mkconfigs $(TOPDIR)/.config configs.c + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/module.c linux.20pre2-ac1/kernel/module.c --- linux.20pre2/kernel/module.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/module.c 2002-08-06 15:41:51.000000000 +0100 @@ -303,7 +303,7 @@ error = namelen; goto err0; } - if (size < sizeof(struct module)+namelen) { + if (size < sizeof(struct module)+namelen+1) { error = -EINVAL; goto err1; } @@ -482,10 +482,10 @@ error = n_namelen; goto err2; } - if (namelen != n_namelen || strcmp(n_name, mod_tmp.name) != 0) { + if (namelen != n_namelen || strcmp(n_name, name_tmp) != 0) { printk(KERN_ERR "init_module: changed module name to " "`%s' from `%s'\n", - n_name, mod_tmp.name); + n_name, name_tmp); goto err3; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/panic.c linux.20pre2-ac1/kernel/panic.c --- linux.20pre2/kernel/panic.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/panic.c 2002-08-06 15:41:51.000000000 +0100 @@ -16,6 +16,8 @@ #include #include #include +#include +#include asmlinkage void sys_sync(void); /* it's really int */ @@ -28,9 +30,155 @@ panic_timeout = simple_strtoul(str, NULL, 0); return 1; } - __setup("panic=", panic_setup); + +#if (defined(__i386__) && defined(CONFIG_VT)) || defined(CONFIG_PC_KEYB) +#define do_blink(x) pckbd_blink(x) +#else +#define do_blink(x) 0 +#endif + +#ifdef CONFIG_PANIC_MORSE + +static int blink_setting = 1; + +static const unsigned char morsetable[] = { + 0122, 0, 0310, 0, 0, 0163, /* "#$%&' */ + 055, 0155, 0, 0, 0163, 0141, 0152, 0051, /* ()*+,-./ */ + 077, 076, 074, 070, 060, 040, 041, 043, 047, 057, /* 0-9 */ + 0107, 0125, 0, 0061, 0, 0114, 0, /* :;<=>?@ */ + 006, 021, 025, 011, 002, 024, 013, 020, 004, /* A-I */ + 036, 015, 022, 007, 005, 017, 026, 033, 012, /* J-R */ + 010, 003, 014, 030, 016, 031, 035, 023, /* S-Z */ + 0, 0, 0, 0, 0154 /* [\]^_ */ +}; + +__inline__ unsigned char tomorse(char c) { + if (c >= 'a' && c <= 'z') + c = c - 'a' + 'A'; + if (c >= '"' && c <= '_') { + return morsetable[c - '"']; + } else + return 0; +} + + +#define DITLEN (HZ / 5) +#define DAHLEN 3 * DITLEN +#define SPACELEN 7 * DITLEN + +#define FREQ 844 + +/* Tell the user who may be running in X and not see the console that we have + panic'ed. This is to distingush panics from "real" lockups. + Could in theory send the panic message as morse, but that is left as an + exercise for the reader. + And now it's done! LED and speaker morse code by Andrew Rodland + , with improvements based on suggestions from + linux@horizon.com and a host of others. +*/ + +void panic_blink(char *buf) +{ + static unsigned long next_jiffie = 0; + static char * bufpos = 0; + static unsigned char morse = 0; + static char state = 1; + + if (!blink_setting) + return; + + if (!buf) + buf="Panic lost?"; + + + if (bufpos && time_after (next_jiffie, jiffies)) { + return; /* Waiting for something. */ + } + + if (state) { /* Coming off of a blink. */ + if (blink_setting & 0x01) + do_blink(0); + + state = 0; + + if(morse > 1) { /* Not done yet, just a one-dit pause. */ + next_jiffie = jiffies + DITLEN; + } else { /* Get a new char, and figure out how much space. */ + + if(!bufpos) + bufpos = (char *)buf; /* First time through */ + + if(!*bufpos) { + bufpos = (char *)buf; /* Repeating */ + next_jiffie = jiffies + SPACELEN; + } else { + /* Inter-letter space */ + next_jiffie = jiffies + DAHLEN; + } + + if (! (morse = tomorse(*bufpos) )) { + next_jiffie = jiffies + SPACELEN; + state = 1; /* And get us back here */ + } + bufpos ++; + } + } else { /* Starting a new blink. We have valid code in morse. */ + int len; + + len = (morse & 001) ? DAHLEN : DITLEN; + + if (blink_setting & 0x02) + kd_mksound(FREQ, len); + + next_jiffie = jiffies + len; + + if (blink_setting & 0x01) + do_blink(1); + state = 1; + morse >>= 1; + } +} + +#else /* CONFIG_PANIC_MORSE */ + +static int blink_setting = HZ / 2; /* Over here, it's jiffies between blinks. */ + +/* This is the "original" 2.4-ac panic_blink, rewritten to use my + * sorta-arch-independent do_blink stuff. + */ +void panic_blink(char *buf) { + static char state = 0; + static unsigned long next_jiffie = 0; + + if (!blink_setting) + return; + + if (jiffies >= next_jiffie) { + state ^= 1; + do_blink(state); + next_jiffie = jiffies + blink_setting; + } + + return; +} + +#endif /* CONFIG_PANIC_MORSE */ + +static int __init panicblink_setup(char *str) +{ + int par; + if (get_option(&str,&par)) + blink_setting = par; + return 1; +} + +/* panicblink=0 disables the blinking as it caused problems with some console + switches. */ +__setup("panicblink=", panicblink_setup); + + /** * panic - halt the system * @fmt: The text string to print @@ -96,10 +244,7 @@ #endif sti(); for(;;) { -#if defined(__i386__) && defined(CONFIG_VT) - extern void panic_blink(void); - panic_blink(); -#endif + panic_blink(buf); CHECK_EMERGENCY_SYNC } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/printk.c linux.20pre2-ac1/kernel/printk.c --- linux.20pre2/kernel/printk.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/printk.c 2002-08-07 14:37:11.000000000 +0100 @@ -26,6 +26,7 @@ #include #include /* For in_interrupt() */ #include +#include #include @@ -529,6 +530,7 @@ if (must_wake_klogd && !oops_in_progress) wake_up_interruptible(&log_wait); } +EXPORT_SYMBOL(release_console_sem); /** console_conditional_schedule - yield the CPU if required * @@ -556,7 +558,14 @@ { struct console *c; - acquire_console_sem(); + /* + * Try to get the console semaphore. If someone else owns it + * we have to return without unblanking because console_unblank + * may be called in interrupt context. + */ + if (down_trylock(&console_sem) != 0) + return; + console_may_schedule = 0; for (c = console_drivers; c != NULL; c = c->next) if ((c->flags & CON_ENABLED) && c->unblank) c->unblank(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/ptrace.c linux.20pre2-ac1/kernel/ptrace.c --- linux.20pre2/kernel/ptrace.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/ptrace.c 2002-08-06 15:41:51.000000000 +0100 @@ -31,20 +31,7 @@ if (child->state != TASK_STOPPED) return -ESRCH; #ifdef CONFIG_SMP - /* Make sure the child gets off its CPU.. */ - for (;;) { - task_lock(child); - if (!task_has_cpu(child)) - break; - task_unlock(child); - do { - if (child->state != TASK_STOPPED) - return -ESRCH; - barrier(); - cpu_relax(); - } while (task_has_cpu(child)); - } - task_unlock(child); + wait_task_inactive(child); #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/sched.c linux.20pre2-ac1/kernel/sched.c --- linux.20pre2/kernel/sched.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/kernel/sched.c 2002-08-06 15:41:51.000000000 +0100 @@ -1,344 +1,344 @@ /* - * linux/kernel/sched.c + * kernel/sched.c * * Kernel scheduler and related syscalls * - * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1991-2002 Linus Torvalds * * 1996-12-23 Modified by Dave Grothe to fix bugs in semaphores and * make semaphores SMP safe * 1998-11-19 Implemented schedule_timeout() and related stuff * by Andrea Arcangeli - * 1998-12-28 Implemented better SMP scheduling by Ingo Molnar + * 2002-01-04 New ultra-scalable O(1) scheduler by Ingo Molnar: + * hybrid priority-list and round-robin design with + * an array-switch method of distributing timeslices + * and per-CPU runqueues. Additional code by Davide + * Libenzi, Robert Love, and Rusty Russell. */ -/* - * 'sched.c' is the main kernel file. It contains scheduling primitives - * (sleep_on, wakeup, schedule etc) as well as a number of simple system - * call functions (type getpid()), which just extract a field from - * current-task - */ - -#include #include +#include #include +#include +#include #include -#include +#include #include -#include #include -#include -#include - -#include -#include - -extern void timer_bh(void); -extern void tqueue_bh(void); -extern void immediate_bh(void); +#include /* - * scheduler variables + * Convert user-nice values [ -20 ... 0 ... 19 ] + * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], + * and back. */ +#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20) +#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) +#define TASK_NICE(p) PRIO_TO_NICE((p)->static_prio) -unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ - -extern void mem_use(void); +/* + * 'User priority' is the nice value converted to something we + * can work with better when scaling various scheduler parameters, + * it's a [ 0 ... 39 ] range. + */ +#define USER_PRIO(p) ((p)-MAX_RT_PRIO) +#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio) +#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) /* - * Scheduling quanta. - * - * NOTE! The unix "nice" value influences how long a process - * gets. The nice value ranges from -20 to +19, where a -20 - * is a "high-priority" task, and a "+10" is a low-priority - * task. + * These are the 'tuning knobs' of the scheduler: * - * We want the time-slice to be around 50ms or so, so this - * calculation depends on the value of HZ. + * Minimum timeslice is 10 msecs, default timeslice is 150 msecs, + * maximum timeslice is 300 msecs. Timeslices get refilled after + * they expire. */ -#if HZ < 200 -#define TICK_SCALE(x) ((x) >> 2) -#elif HZ < 400 -#define TICK_SCALE(x) ((x) >> 1) -#elif HZ < 800 -#define TICK_SCALE(x) (x) -#elif HZ < 1600 -#define TICK_SCALE(x) ((x) << 1) -#else -#define TICK_SCALE(x) ((x) << 2) -#endif - -#define NICE_TO_TICKS(nice) (TICK_SCALE(20-(nice))+1) - +#define MIN_TIMESLICE ( 10 * HZ / 1000) +#define MAX_TIMESLICE (300 * HZ / 1000) +#define CHILD_PENALTY 95 +#define PARENT_PENALTY 100 +#define EXIT_WEIGHT 3 +#define PRIO_BONUS_RATIO 25 +#define INTERACTIVE_DELTA 2 +#define MAX_SLEEP_AVG (2*HZ) +#define STARVATION_LIMIT (2*HZ) /* - * Init task must be ok at boot for the ix86 as we will check its signals - * via the SMP irq return path. + * If a task is 'interactive' then we reinsert it in the active + * array after it has expired its current timeslice. (it will not + * continue to run immediately, it will still roundrobin with + * other interactive tasks.) + * + * This part scales the interactivity limit depending on niceness. + * + * We scale it linearly, offset by the INTERACTIVE_DELTA delta. + * Here are a few examples of different nice levels: + * + * TASK_INTERACTIVE(-20): [1,1,1,1,1,1,1,1,1,0,0] + * TASK_INTERACTIVE(-10): [1,1,1,1,1,1,1,0,0,0,0] + * TASK_INTERACTIVE( 0): [1,1,1,1,0,0,0,0,0,0,0] + * TASK_INTERACTIVE( 10): [1,1,0,0,0,0,0,0,0,0,0] + * TASK_INTERACTIVE( 19): [0,0,0,0,0,0,0,0,0,0,0] + * + * (the X axis represents the possible -5 ... 0 ... +5 dynamic + * priority range a task can explore, a value of '1' means the + * task is rated interactive.) + * + * Ie. nice +19 tasks can never get 'interactive' enough to be + * reinserted into the active array. And only heavily CPU-hog nice -20 + * tasks will be expired. Default nice 0 tasks are somewhere between, + * it takes some effort for them to get interactive, but it's not + * too hard. */ - -struct task_struct * init_tasks[NR_CPUS] = {&init_task, }; + +#define SCALE(v1,v1_max,v2_max) \ + (v1) * (v2_max) / (v1_max) + +#define DELTA(p) \ + (SCALE(TASK_NICE(p), 40, MAX_USER_PRIO*PRIO_BONUS_RATIO/100) + \ + INTERACTIVE_DELTA) + +#define TASK_INTERACTIVE(p) \ + ((p)->prio <= (p)->static_prio - DELTA(p)) /* - * The tasklist_lock protects the linked list of processes. + * TASK_TIMESLICE scales user-nice values [ -20 ... 19 ] + * to time slice values. * - * The runqueue_lock locks the parts that actually access - * and change the run-queues, and have to be interrupt-safe. - * - * If both locks are to be concurrently held, the runqueue_lock - * nests inside the tasklist_lock. - * - * task->alloc_lock nests inside tasklist_lock. + * The higher a process's priority, the bigger timeslices + * it gets during one round of execution. But even the lowest + * priority process gets MIN_TIMESLICE worth of execution time. */ -spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* inner */ -rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ -static LIST_HEAD(runqueue_head); +#define TASK_TIMESLICE(p) (MIN_TIMESLICE + \ + ((MAX_TIMESLICE - MIN_TIMESLICE) * (MAX_PRIO-1-(p)->static_prio)/39)) /* - * We align per-CPU scheduling data on cacheline boundaries, - * to prevent cacheline ping-pong. + * These are the runqueue data structures: */ -static union { - struct schedule_data { - struct task_struct * curr; - cycles_t last_schedule; - } schedule_data; - char __pad [SMP_CACHE_BYTES]; -} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}}; -#define cpu_curr(cpu) aligned_data[(cpu)].schedule_data.curr -#define last_schedule(cpu) aligned_data[(cpu)].schedule_data.last_schedule +#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long)) -struct kernel_stat kstat; -extern struct task_struct *child_reaper; +typedef struct runqueue runqueue_t; -#ifdef CONFIG_SMP +struct prio_array { + int nr_active; + unsigned long bitmap[BITMAP_SIZE]; + list_t queue[MAX_PRIO]; +}; -#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)]) -#define can_schedule(p,cpu) \ - ((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu)) - -#else - -#define idle_task(cpu) (&init_task) -#define can_schedule(p,cpu) (1) +/* + * This is the main, per-CPU runqueue data structure. + * + * Locking rule: those places that want to lock multiple runqueues + * (such as the load balancing or the process migration code), lock + * acquire operations must be ordered by ascending &runqueue. + */ +struct runqueue { + spinlock_t lock; + unsigned long nr_running, nr_switches, expired_timestamp; + signed long nr_uninterruptible; + task_t *curr, *idle; + prio_array_t *active, *expired, arrays[2]; + int prev_nr_running[NR_CPUS]; + task_t *migration_thread; + list_t migration_queue; +} ____cacheline_aligned; + +static struct runqueue runqueues[NR_CPUS] __cacheline_aligned; + +#define cpu_rq(cpu) (runqueues + (cpu)) +#define this_rq() cpu_rq(smp_processor_id()) +#define task_rq(p) cpu_rq((p)->cpu) +#define cpu_curr(cpu) (cpu_rq(cpu)->curr) +#define rt_task(p) ((p)->prio < MAX_RT_PRIO) +/* + * Default context-switch locking: + */ +#ifndef prepare_arch_schedule +# define prepare_arch_schedule(prev) do { } while(0) +# define finish_arch_schedule(prev) do { } while(0) +# define prepare_arch_switch(rq) do { } while(0) +# define finish_arch_switch(rq) spin_unlock_irq(&(rq)->lock) #endif -void scheduling_functions_start_here(void) { } /* - * This is the function that decides how desirable a process is.. - * You can weigh different processes against each other depending - * on what CPU they've run on lately etc to try to handle cache - * and TLB miss penalties. - * - * Return values: - * -1000: never select this - * 0: out of time, recalculate counters (but it might still be - * selected) - * +ve: "goodness" value (the larger, the better) - * +1000: realtime process, select this. + * task_rq_lock - lock the runqueue a given task resides on and disable + * interrupts. Note the ordering: we can safely lookup the task_rq without + * explicitly disabling preemption. */ - -static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm) +static inline runqueue_t *task_rq_lock(task_t *p, unsigned long *flags) { - int weight; - - /* - * select the current process after every other - * runnable process, but before the idle thread. - * Also, dont trigger a counter recalculation. - */ - weight = -1; - if (p->policy & SCHED_YIELD) - goto out; + struct runqueue *rq; - /* - * Non-RT process - normal case first. - */ - if (p->policy == SCHED_OTHER) { - /* - * Give the process a first-approximation goodness value - * according to the number of clock-ticks it has left. - * - * Don't do any other calculations if the time slice is - * over.. - */ - weight = p->counter; - if (!weight) - goto out; - -#ifdef CONFIG_SMP - /* Give a largish advantage to the same processor... */ - /* (this is equivalent to penalizing other processors) */ - if (p->processor == this_cpu) - weight += PROC_CHANGE_PENALTY; -#endif - - /* .. and a slight advantage to the current MM */ - if (p->mm == this_mm || !p->mm) - weight += 1; - weight += 20 - p->nice; - goto out; +repeat_lock_task: + local_irq_save(*flags); + rq = task_rq(p); + spin_lock(&rq->lock); + if (unlikely(rq != task_rq(p))) { + spin_unlock_irqrestore(&rq->lock, *flags); + goto repeat_lock_task; } + return rq; +} - /* - * Realtime process, select the first one on the - * runqueue (taking priorities within processes - * into account). - */ - weight = 1000 + p->rt_priority; -out: - return weight; +static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags) +{ + spin_unlock_irqrestore(&rq->lock, *flags); } /* - * the 'goodness value' of replacing a process on a given CPU. - * positive value means 'replace', zero or negative means 'dont'. + * rq_lock - lock a given runqueue and disable interrupts. */ -static inline int preemption_goodness(struct task_struct * prev, struct task_struct * p, int cpu) +static inline runqueue_t *this_rq_lock(void) +{ + runqueue_t *rq; + + local_irq_disable(); + rq = this_rq(); + spin_lock(&rq->lock); + + return rq; +} + +static inline void rq_unlock(runqueue_t *rq) { - return goodness(p, cpu, prev->active_mm) - goodness(prev, cpu, prev->active_mm); + spin_unlock(&rq->lock); + local_irq_enable(); } /* - * This is ugly, but reschedule_idle() is very timing-critical. - * We are called with the runqueue spinlock held and we must - * not claim the tasklist_lock. + * Adding/removing a task to/from a priority array: */ -static FASTCALL(void reschedule_idle(struct task_struct * p)); +static inline void dequeue_task(struct task_struct *p, prio_array_t *array) +{ + array->nr_active--; + list_del(&p->run_list); + if (list_empty(array->queue + p->prio)) + __clear_bit(p->prio, array->bitmap); +} -static void reschedule_idle(struct task_struct * p) +static inline void enqueue_task(struct task_struct *p, prio_array_t *array) { -#ifdef CONFIG_SMP - int this_cpu = smp_processor_id(); - struct task_struct *tsk, *target_tsk; - int cpu, best_cpu, i, max_prio; - cycles_t oldest_idle; - - /* - * shortcut if the woken up task's last CPU is - * idle now. - */ - best_cpu = p->processor; - if (can_schedule(p, best_cpu)) { - tsk = idle_task(best_cpu); - if (cpu_curr(best_cpu) == tsk) { - int need_resched; -send_now_idle: - /* - * If need_resched == -1 then we can skip sending - * the IPI altogether, tsk->need_resched is - * actively watched by the idle thread. - */ - need_resched = tsk->need_resched; - tsk->need_resched = 1; - if ((best_cpu != this_cpu) && !need_resched) - smp_send_reschedule(best_cpu); - return; - } - } + list_add_tail(&p->run_list, array->queue + p->prio); + __set_bit(p->prio, array->bitmap); + array->nr_active++; + p->array = array; +} + +static inline int effective_prio(task_t *p) +{ + int bonus, prio; /* - * We know that the preferred CPU has a cache-affine current - * process, lets try to find a new idle CPU for the woken-up - * process. Select the least recently active idle CPU. (that - * one will have the least active cache context.) Also find - * the executing process which has the least priority. - */ - oldest_idle = (cycles_t) -1; - target_tsk = NULL; - max_prio = 0; + * Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG] + * into the -5 ... 0 ... +5 bonus/penalty range. + * + * We use 25% of the full 0...39 priority range so that: + * + * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs. + * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks. + * + * Both properties are important to certain workloads. + */ + bonus = MAX_USER_PRIO*PRIO_BONUS_RATIO*p->sleep_avg/MAX_SLEEP_AVG/100 - + MAX_USER_PRIO*PRIO_BONUS_RATIO/100/2; - for (i = 0; i < smp_num_cpus; i++) { - cpu = cpu_logical_map(i); - if (!can_schedule(p, cpu)) - continue; - tsk = cpu_curr(cpu); + prio = p->static_prio - bonus; + if (prio < MAX_RT_PRIO) + prio = MAX_RT_PRIO; + if (prio > MAX_PRIO-1) + prio = MAX_PRIO-1; + return prio; +} + +static inline void activate_task(task_t *p, runqueue_t *rq) +{ + unsigned long sleep_time = jiffies - p->sleep_timestamp; + prio_array_t *array = rq->active; + + if (!rt_task(p) && sleep_time) { /* - * We use the first available idle CPU. This creates - * a priority list between idle CPUs, but this is not - * a problem. + * This code gives a bonus to interactive tasks. We update + * an 'average sleep time' value here, based on + * sleep_timestamp. The more time a task spends sleeping, + * the higher the average gets - and the higher the priority + * boost gets as well. */ - if (tsk == idle_task(cpu)) { -#if defined(__i386__) && defined(CONFIG_SMP) - /* - * Check if two siblings are idle in the same - * physical package. Use them if found. - */ - if (smp_num_siblings == 2) { - if (cpu_curr(cpu_sibling_map[cpu]) == - idle_task(cpu_sibling_map[cpu])) { - oldest_idle = last_schedule(cpu); - target_tsk = tsk; - break; - } - - } -#endif - if (last_schedule(cpu) < oldest_idle) { - oldest_idle = last_schedule(cpu); - target_tsk = tsk; - } - } else { - if (oldest_idle == -1ULL) { - int prio = preemption_goodness(tsk, p, cpu); - - if (prio > max_prio) { - max_prio = prio; - target_tsk = tsk; - } - } - } + p->sleep_avg += sleep_time; + if (p->sleep_avg > MAX_SLEEP_AVG) + p->sleep_avg = MAX_SLEEP_AVG; + p->prio = effective_prio(p); } - tsk = target_tsk; - if (tsk) { - if (oldest_idle != -1ULL) { - best_cpu = tsk->processor; - goto send_now_idle; - } - tsk->need_resched = 1; - if (tsk->processor != this_cpu) - smp_send_reschedule(tsk->processor); - } - return; - + enqueue_task(p, array); + rq->nr_running++; +} -#else /* UP */ - int this_cpu = smp_processor_id(); - struct task_struct *tsk; - - tsk = cpu_curr(this_cpu); - if (preemption_goodness(tsk, p, this_cpu) > 0) - tsk->need_resched = 1; +static inline void deactivate_task(struct task_struct *p, runqueue_t *rq) +{ + rq->nr_running--; + if (p->state == TASK_UNINTERRUPTIBLE) + rq->nr_uninterruptible++; + dequeue_task(p, p->array); + p->array = NULL; +} + +static inline void resched_task(task_t *p) +{ +#ifdef CONFIG_SMP + int need_resched; + + need_resched = p->need_resched; + wmb(); + set_tsk_need_resched(p); + if (!need_resched && (p->cpu != smp_processor_id())) + smp_send_reschedule(p->cpu); +#else + set_tsk_need_resched(p); #endif } +#ifdef CONFIG_SMP + /* - * Careful! - * - * This has to add the process to the _beginning_ of the - * run-queue, not the end. See the comment about "This is - * subtle" in the scheduler proper.. + * Wait for a process to unschedule. This is used by the exit() and + * ptrace() code. */ -static inline void add_to_runqueue(struct task_struct * p) +void wait_task_inactive(task_t * p) { - list_add(&p->run_list, &runqueue_head); - nr_running++; -} + unsigned long flags; + runqueue_t *rq; -static inline void move_last_runqueue(struct task_struct * p) -{ - list_del(&p->run_list); - list_add_tail(&p->run_list, &runqueue_head); +repeat: + rq = task_rq(p); + if (unlikely(rq->curr == p)) { + cpu_relax(); + goto repeat; + } + rq = task_rq_lock(p, &flags); + if (unlikely(rq->curr == p)) { + task_rq_unlock(rq, &flags); + goto repeat; + } + task_rq_unlock(rq, &flags); } -static inline void move_first_runqueue(struct task_struct * p) +/* + * Kick the remote CPU if the task is running currently, + * this code is used by the signal code to signal tasks + * which are in user-mode as quickly as possible. + * + * (Note that we do this lockless - if the task does anything + * while the message is in flight then it will notice the + * sigpending condition anyway.) + */ +void kick_if_running(task_t * p) { - list_del(&p->run_list); - list_add(&p->run_list, &runqueue_head); + if (p == task_rq(p)->curr) + resched_task(p); } +#endif /* * Wake up a process. Put it on the run-queue if it's not @@ -348,415 +348,605 @@ * "current->state = TASK_RUNNING" to mark yourself runnable * without the overhead of this. */ -static inline int try_to_wake_up(struct task_struct * p, int synchronous) +static int try_to_wake_up(task_t * p, int sync) { unsigned long flags; int success = 0; + long old_state; + runqueue_t *rq; - /* - * We want the common case fall through straight, thus the goto. - */ - spin_lock_irqsave(&runqueue_lock, flags); +repeat_lock_task: + rq = task_rq_lock(p, &flags); + old_state = p->state; + if (!p->array) { + /* + * Fast-migrate the task if it's not running or runnable + * currently. Do not violate hard affinity. + */ + if (unlikely(sync && (rq->curr != p) && + (p->cpu != smp_processor_id()) && + (p->cpus_allowed & (1UL << smp_processor_id())))) { + + p->cpu = smp_processor_id(); + task_rq_unlock(rq, &flags); + goto repeat_lock_task; + } + if (old_state == TASK_UNINTERRUPTIBLE) + rq->nr_uninterruptible--; + activate_task(p, rq); + /* + * If sync is set, a resched_task() is a NOOP + */ + if (p->prio < rq->curr->prio) + resched_task(rq->curr); + success = 1; + } p->state = TASK_RUNNING; - if (task_on_runqueue(p)) - goto out; - add_to_runqueue(p); - if (!synchronous || !(p->cpus_allowed & (1 << smp_processor_id()))) - reschedule_idle(p); - success = 1; -out: - spin_unlock_irqrestore(&runqueue_lock, flags); + task_rq_unlock(rq, &flags); + return success; } -inline int wake_up_process(struct task_struct * p) +int wake_up_process(task_t * p) { return try_to_wake_up(p, 0); } -static void process_timeout(unsigned long __data) +void wake_up_forked_process(task_t * p) { - struct task_struct * p = (struct task_struct *) __data; + runqueue_t *rq = this_rq_lock(); + + p->state = TASK_RUNNING; + if (!rt_task(p)) { + /* + * We decrease the sleep average of forking parents + * and children as well, to keep max-interactive tasks + * from forking tasks that are max-interactive. + */ + current->sleep_avg = current->sleep_avg * PARENT_PENALTY / 100; + p->sleep_avg = p->sleep_avg * CHILD_PENALTY / 100; + p->prio = effective_prio(p); + } + p->cpu = smp_processor_id(); + activate_task(p, rq); - wake_up_process(p); + rq_unlock(rq); } -/** - * schedule_timeout - sleep until timeout - * @timeout: timeout value in jiffies - * - * Make the current task sleep until @timeout jiffies have - * elapsed. The routine will return immediately unless - * the current task state has been set (see set_current_state()). - * - * You can set the task state as follows - - * - * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to - * pass before the routine returns. The routine will return 0 - * - * %TASK_INTERRUPTIBLE - the routine may return early if a signal is - * delivered to the current task. In this case the remaining time - * in jiffies will be returned, or 0 if the timer expired in time - * - * The current task state is guaranteed to be TASK_RUNNING when this - * routine returns. - * - * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule - * the CPU away without a bound on the timeout. In this case the return - * value will be %MAX_SCHEDULE_TIMEOUT. - * - * In all cases the return value is guaranteed to be non-negative. +/* + * Potentially available exiting-child timeslices are + * retrieved here - this way the parent does not get + * penalized for creating too many processes. + * + * (this cannot be used to 'generate' timeslices + * artificially, because any timeslice recovered here + * was given away by the parent in the first place.) */ -signed long schedule_timeout(signed long timeout) +void sched_exit(task_t * p) { - struct timer_list timer; - unsigned long expire; + __cli(); + current->time_slice += p->time_slice; + if (unlikely(current->time_slice > MAX_TIMESLICE)) + current->time_slice = MAX_TIMESLICE; + __sti(); + /* + * If the child was a (relative-) CPU hog then decrease + * the sleep_avg of the parent as well. + */ + if (p->sleep_avg < current->sleep_avg) + current->sleep_avg = (current->sleep_avg * EXIT_WEIGHT + + p->sleep_avg) / (EXIT_WEIGHT + 1); +} - switch (timeout) - { - case MAX_SCHEDULE_TIMEOUT: - /* - * These two special cases are useful to be comfortable - * in the caller. Nothing more. We could take - * MAX_SCHEDULE_TIMEOUT from one of the negative value - * but I' d like to return a valid offset (>=0) to allow - * the caller to do everything it want with the retval. - */ - schedule(); - goto out; - default: - /* - * Another bit of PARANOID. Note that the retval will be - * 0 since no piece of kernel is supposed to do a check - * for a negative retval of schedule_timeout() (since it - * should never happens anyway). You just have the printk() - * that will tell you if something is gone wrong and where. - */ - if (timeout < 0) - { - printk(KERN_ERR "schedule_timeout: wrong timeout " - "value %lx from %p\n", timeout, - __builtin_return_address(0)); - current->state = TASK_RUNNING; - goto out; - } - } +#if CONFIG_SMP +asmlinkage void schedule_tail(task_t *prev) +{ + finish_arch_switch(this_rq()); + finish_arch_schedule(prev); +} +#endif - expire = timeout + jiffies; +static inline task_t * context_switch(task_t *prev, task_t *next) +{ + struct mm_struct *mm = next->mm; + struct mm_struct *oldmm = prev->active_mm; - init_timer(&timer); - timer.expires = expire; - timer.data = (unsigned long) current; - timer.function = process_timeout; + if (unlikely(!mm)) { + next->active_mm = oldmm; + atomic_inc(&oldmm->mm_count); + enter_lazy_tlb(oldmm, next, smp_processor_id()); + } else + switch_mm(oldmm, mm, next, smp_processor_id()); - add_timer(&timer); - schedule(); - del_timer_sync(&timer); + if (unlikely(!prev->mm)) { + prev->active_mm = NULL; + mmdrop(oldmm); + } - timeout = expire - jiffies; + /* Here we just switch the register state and the stack. */ + switch_to(prev, next, prev); - out: - return timeout < 0 ? 0 : timeout; + return prev; } -/* - * schedule_tail() is getting called from the fork return path. This - * cleans up all remaining scheduler things, without impacting the - * common case. - */ -static inline void __schedule_tail(struct task_struct *prev) +unsigned long nr_running(void) { -#ifdef CONFIG_SMP - int policy; + unsigned long i, sum = 0; - /* - * prev->policy can be written from here only before `prev' - * can be scheduled (before setting prev->cpus_runnable to ~0UL). - * Of course it must also be read before allowing prev - * to be rescheduled, but since the write depends on the read - * to complete, wmb() is enough. (the spin_lock() acquired - * before setting cpus_runnable is not enough because the spin_lock() - * common code semantics allows code outside the critical section - * to enter inside the critical section) - */ - policy = prev->policy; - prev->policy = policy & ~SCHED_YIELD; - wmb(); + for (i = 0; i < smp_num_cpus; i++) + sum += cpu_rq(cpu_logical_map(i))->nr_running; - /* - * fast path falls through. We have to clear cpus_runnable before - * checking prev->state to avoid a wakeup race. Protect against - * the task exiting early. - */ - task_lock(prev); - task_release_cpu(prev); - mb(); - if (prev->state == TASK_RUNNING) - goto needs_resched; + return sum; +} -out_unlock: - task_unlock(prev); /* Synchronise here with release_task() if prev is TASK_ZOMBIE */ - return; +unsigned long nr_uninterruptible(void) +{ + unsigned long i, sum = 0; - /* - * Slow path - we 'push' the previous process and - * reschedule_idle() will attempt to find a new - * processor for it. (but it might preempt the - * current process as well.) We must take the runqueue - * lock and re-check prev->state to be correct. It might - * still happen that this process has a preemption - * 'in progress' already - but this is not a problem and - * might happen in other circumstances as well. - */ -needs_resched: - { - unsigned long flags; + for (i = 0; i < smp_num_cpus; i++) + sum += cpu_rq(cpu_logical_map(i))->nr_uninterruptible; - /* - * Avoid taking the runqueue lock in cases where - * no preemption-check is necessery: - */ - if ((prev == idle_task(smp_processor_id())) || - (policy & SCHED_YIELD)) - goto out_unlock; + return sum; +} - spin_lock_irqsave(&runqueue_lock, flags); - if ((prev->state == TASK_RUNNING) && !task_has_cpu(prev)) - reschedule_idle(prev); - spin_unlock_irqrestore(&runqueue_lock, flags); - goto out_unlock; - } -#else - prev->policy &= ~SCHED_YIELD; -#endif /* CONFIG_SMP */ +unsigned long nr_context_switches(void) +{ + unsigned long i, sum = 0; + + for (i = 0; i < smp_num_cpus; i++) + sum += cpu_rq(cpu_logical_map(i))->nr_switches; + + return sum; } -asmlinkage void schedule_tail(struct task_struct *prev) +inline int idle_cpu(int cpu) { - __schedule_tail(prev); + return cpu_curr(cpu) == cpu_rq(cpu)->idle; } +#if CONFIG_SMP /* - * 'schedule()' is the scheduler function. It's a very simple and nice - * scheduler: it's not perfect, but certainly works for most things. - * - * The goto is "interesting". - * - * NOTE!! Task 0 is the 'idle' task, which gets called when no other - * tasks can run. It can not be killed, and it cannot sleep. The 'state' - * information in task[0] is never used. + * Lock the busiest runqueue as well, this_rq is locked already. + * Recalculate nr_running if we have to drop the runqueue lock. */ -asmlinkage void schedule(void) +static inline unsigned int double_lock_balance(runqueue_t *this_rq, + runqueue_t *busiest, int this_cpu, int idle, unsigned int nr_running) { - struct schedule_data * sched_data; - struct task_struct *prev, *next, *p; - struct list_head *tmp; - int this_cpu, c; - - - spin_lock_prefetch(&runqueue_lock); - - BUG_ON(!current->active_mm); -need_resched_back: - prev = current; - this_cpu = prev->processor; - - if (unlikely(in_interrupt())) { - printk("Scheduling in interrupt\n"); - BUG(); + if (unlikely(!spin_trylock(&busiest->lock))) { + if (busiest < this_rq) { + spin_unlock(&this_rq->lock); + spin_lock(&busiest->lock); + spin_lock(&this_rq->lock); + /* Need to recalculate nr_running */ + if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu])) + nr_running = this_rq->nr_running; + else + nr_running = this_rq->prev_nr_running[this_cpu]; + } else + spin_lock(&busiest->lock); } + return nr_running; +} - release_kernel_lock(prev, this_cpu); +#include +/* + * Current runqueue is empty, or rebalance tick: if there is an + * inbalance (current runqueue is too short) then pull from + * busiest runqueue(s). + * + * We call this with the current runqueue locked, + * irqs disabled. + */ +static void load_balance(runqueue_t *this_rq, int idle) +{ + int imbalance, nr_running, load, max_load, + idx, i, this_cpu = smp_processor_id(); + task_t *next = this_rq->idle, *tmp; + runqueue_t *busiest, *rq_src; + prio_array_t *array; + list_t *head, *curr; + + /* + * Handle platform specific balancing operations, such as + * hyperthreading. + */ + + if(arch_load_balance(this_cpu, idle)) + return; + /* - * 'sched_data' is protected by the fact that we can run - * only one process per CPU. + * We search all runqueues to find the most busy one. + * We do this lockless to reduce cache-bouncing overhead, + * we re-check the 'best' source CPU later on again, with + * the lock held. + * + * We fend off statistical fluctuations in runqueue lengths by + * saving the runqueue length during the previous load-balancing + * operation and using the smaller one the current and saved lengths. + * If a runqueue is long enough for a longer amount of time then + * we recognize it and pull tasks from it. + * + * The 'current runqueue length' is a statistical maximum variable, + * for that one we take the longer one - to avoid fluctuations in + * the other direction. So for a load-balance to happen it needs + * stable long runqueue on the target CPU and stable short runqueue + * on the local runqueue. + * + * We make an exception if this CPU is about to become idle - in + * that case we are less picky about moving a task across CPUs and + * take what can be taken. */ - sched_data = & aligned_data[this_cpu].schedule_data; + if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu])) + nr_running = this_rq->nr_running; + else + nr_running = this_rq->prev_nr_running[this_cpu]; - spin_lock_irq(&runqueue_lock); + busiest = NULL; + max_load = 1; + for (i = 0; i < smp_num_cpus; i++) { + int logical = cpu_logical_map(i); - /* move an exhausted RR process to be last.. */ - if (unlikely(prev->policy == SCHED_RR)) - if (!prev->counter) { - prev->counter = NICE_TO_TICKS(prev->nice); - move_last_runqueue(prev); + rq_src = cpu_rq(logical); + if (idle || (rq_src->nr_running < this_rq->prev_nr_running[logical])) + load = rq_src->nr_running; + else + load = this_rq->prev_nr_running[logical]; + this_rq->prev_nr_running[logical] = rq_src->nr_running; + + if ((load > max_load) && (rq_src != this_rq)) { + busiest = rq_src; + max_load = load; } - - switch (prev->state) { - case TASK_INTERRUPTIBLE: - if (signal_pending(prev)) { - prev->state = TASK_RUNNING; - break; - } - default: - del_from_runqueue(prev); - case TASK_RUNNING:; } - prev->need_resched = 0; + if (likely(!busiest)) + return; + + imbalance = (max_load - nr_running) / 2; + + /* It needs an at least ~25% imbalance to trigger balancing. */ + if (!idle && (imbalance < (max_load + 3)/4)) + return; + + nr_running = double_lock_balance(this_rq, busiest, this_cpu, idle, nr_running); /* - * this is the scheduler proper: + * Make sure nothing changed since we checked the + * runqueue length. */ + if (busiest->nr_running <= nr_running + 1) + goto out_unlock; -repeat_schedule: /* - * Default process to select.. + * We first consider expired tasks. Those will likely not be + * executed in the near future, and they are most likely to + * be cache-cold, thus switching CPUs has the least effect + * on them. */ - next = idle_task(this_cpu); - c = -1000; - list_for_each(tmp, &runqueue_head) { - p = list_entry(tmp, struct task_struct, run_list); - if (can_schedule(p, this_cpu)) { - int weight = goodness(p, this_cpu, prev->active_mm); - if (weight > c) - c = weight, next = p; + if (busiest->expired->nr_active) + array = busiest->expired; + else + array = busiest->active; + +new_array: + /* Start searching at priority 0: */ + idx = 0; +skip_bitmap: + if (!idx) + idx = sched_find_first_bit(array->bitmap); + else + idx = find_next_bit(array->bitmap, MAX_PRIO, idx); + if (idx == MAX_PRIO) { + if (array == busiest->expired) { + array = busiest->active; + goto new_array; } + goto out_unlock; } - /* Do we need to re-calculate counters? */ - if (unlikely(!c)) { - struct task_struct *p; - - spin_unlock_irq(&runqueue_lock); - read_lock(&tasklist_lock); - for_each_task(p) - p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice); - read_unlock(&tasklist_lock); - spin_lock_irq(&runqueue_lock); - goto repeat_schedule; + head = array->queue + idx; + curr = head->prev; +skip_queue: + tmp = list_entry(curr, task_t, run_list); + + /* + * We do not migrate tasks that are: + * 1) running (obviously), or + * 2) cannot be migrated to this CPU due to cpus_allowed, or + * 3) are cache-hot on their current CPU. + */ + +#define CAN_MIGRATE_TASK(p,rq,this_cpu) \ + ((jiffies - (p)->sleep_timestamp > cache_decay_ticks) && \ + ((p) != (rq)->curr) && \ + ((p)->cpus_allowed & (1UL << (this_cpu)))) + + if (!CAN_MIGRATE_TASK(tmp, busiest, this_cpu)) { + curr = curr->next; + if (curr != head) + goto skip_queue; + idx++; + goto skip_bitmap; + } + next = tmp; + /* + * take the task out of the other runqueue and + * put it into this one: + */ + dequeue_task(next, array); + busiest->nr_running--; + next->cpu = this_cpu; + this_rq->nr_running++; + enqueue_task(next, this_rq->active); + if (next->prio < current->prio) + set_need_resched(); + if (!idle && --imbalance) { + if (array == busiest->expired) { + array = busiest->active; + goto new_array; + } } +out_unlock: + spin_unlock(&busiest->lock); +} - /* - * from this point on nothing can prevent us from - * switching to the next task, save this fact in - * sched_data. - */ - sched_data->curr = next; - task_set_cpu(next, this_cpu); - spin_unlock_irq(&runqueue_lock); +/* + * One of the idle_cpu_tick() or the busy_cpu_tick() function will + * gets called every timer tick, on every CPU. Our balancing action + * frequency and balancing agressivity depends on whether the CPU is + * idle or not. + * + * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on + * systems with HZ=100, every 10 msecs.) + */ +#define BUSY_REBALANCE_TICK (HZ/4 ?: 1) +#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1) - if (unlikely(prev == next)) { - /* We won't go through the normal tail, so do this by hand */ - prev->policy &= ~SCHED_YIELD; - goto same_process; - } +static inline void idle_tick(void) +{ + if (jiffies % IDLE_REBALANCE_TICK) + return; + spin_lock(&this_rq()->lock); + load_balance(this_rq(), 1); + spin_unlock(&this_rq()->lock); +} -#ifdef CONFIG_SMP - /* - * maintain the per-process 'last schedule' value. - * (this has to be recalculated even if we reschedule to - * the same process) Currently this is only used on SMP, - * and it's approximate, so we do not have to maintain - * it while holding the runqueue spinlock. - */ - sched_data->last_schedule = get_cycles(); +#endif - /* - * We drop the scheduler lock early (it's a global spinlock), - * thus we have to lock the previous process from getting - * rescheduled during switch_to(). - */ +/* + * We place interactive tasks back into the active array, if possible. + * + * To guarantee that this does not starve expired tasks we ignore the + * interactivity of a task if the first expired task had to wait more + * than a 'reasonable' amount of time. This deadline timeout is + * load-dependent, as the frequency of array switched decreases with + * increasing number of running tasks: + */ +#define EXPIRED_STARVING(rq) \ + ((rq)->expired_timestamp && \ + (jiffies - (rq)->expired_timestamp >= \ + STARVATION_LIMIT * ((rq)->nr_running) + 1)) -#endif /* CONFIG_SMP */ +/* + * This function gets called by the timer code, with HZ frequency. + * We call it with interrupts disabled. + */ +void scheduler_tick(int user_tick, int system) +{ + int cpu = smp_processor_id(); + runqueue_t *rq = this_rq(); + task_t *p = current; - kstat.context_swtch++; - /* - * there are 3 processes which are affected by a context switch: - * - * prev == .... ==> (last => next) - * - * It's the 'much more previous' 'prev' that is on next's stack, - * but prev is set to (the just run) 'last' process by switch_to(). - * This might sound slightly confusing but makes tons of sense. - */ - prepare_to_switch(); - { - struct mm_struct *mm = next->mm; - struct mm_struct *oldmm = prev->active_mm; - if (!mm) { - BUG_ON(next->active_mm); - next->active_mm = oldmm; - atomic_inc(&oldmm->mm_count); - enter_lazy_tlb(oldmm, next, this_cpu); - } else { - BUG_ON(next->active_mm != mm); - switch_mm(oldmm, mm, next, this_cpu); + if (p == rq->idle) { + if (local_bh_count(cpu) || local_irq_count(cpu) > 1) + kstat.per_cpu_system[cpu] += system; +#if CONFIG_SMP + idle_tick(); +#endif + return; + } + if (TASK_NICE(p) > 0) + kstat.per_cpu_nice[cpu] += user_tick; + else + kstat.per_cpu_user[cpu] += user_tick; + kstat.per_cpu_system[cpu] += system; + + /* Task might have expired already, but not scheduled off yet */ + if (p->array != rq->active) { + set_tsk_need_resched(p); + return; + } + spin_lock(&rq->lock); + if (unlikely(rt_task(p))) { + /* + * RR tasks need a special form of timeslice management. + * FIFO tasks have no timeslices. + */ + if ((p->policy == SCHED_RR) && !--p->time_slice) { + p->time_slice = TASK_TIMESLICE(p); + set_tsk_need_resched(p); + + /* put it at the end of the queue: */ + dequeue_task(p, rq->active); + enqueue_task(p, rq->active); } + goto out; + } + /* + * The task was running during this tick - update the + * time slice counter and the sleep average. Note: we + * do not update a process's priority until it either + * goes to sleep or uses up its timeslice. This makes + * it possible for interactive tasks to use up their + * timeslices at their highest priority levels. + */ + if (p->sleep_avg) + p->sleep_avg--; + if (!--p->time_slice) { + dequeue_task(p, rq->active); + set_tsk_need_resched(p); + p->prio = effective_prio(p); + p->time_slice = TASK_TIMESLICE(p); + + if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) { + if (!rq->expired_timestamp) + rq->expired_timestamp = jiffies; + enqueue_task(p, rq->expired); + } else + enqueue_task(p, rq->active); + } +out: +#if CONFIG_SMP + if (!(jiffies % BUSY_REBALANCE_TICK)) + load_balance(rq, 0); +#endif + spin_unlock(&rq->lock); +} - if (!prev->mm) { - prev->active_mm = NULL; - mmdrop(oldmm); +void scheduling_functions_start_here(void) { } + +/* + * 'schedule()' is the main scheduler function. + */ +asmlinkage void schedule(void) +{ + task_t *prev, *next; + runqueue_t *rq; + prio_array_t *array; + list_t *queue; + int idx; + + if (unlikely(in_interrupt())) + BUG(); + +need_resched: + prev = current; + rq = this_rq(); + + release_kernel_lock(prev, smp_processor_id()); + prepare_arch_schedule(prev); + prev->sleep_timestamp = jiffies; + spin_lock_irq(&rq->lock); + + switch (prev->state) { + case TASK_INTERRUPTIBLE: + if (unlikely(signal_pending(prev))) { + prev->state = TASK_RUNNING; + break; } + default: + deactivate_task(prev, rq); + case TASK_RUNNING: + ; + } +#if CONFIG_SMP +pick_next_task: +#endif + if (unlikely(!rq->nr_running)) { +#if CONFIG_SMP + load_balance(rq, 1); + if (rq->nr_running) + goto pick_next_task; +#endif + next = rq->idle; + rq->expired_timestamp = 0; + goto switch_tasks; } - /* - * This just switches the register state and the - * stack. - */ - switch_to(prev, next, prev); - __schedule_tail(prev); + array = rq->active; + if (unlikely(!array->nr_active)) { + /* + * Switch the active and expired arrays. + */ + rq->active = rq->expired; + rq->expired = array; + array = rq->active; + rq->expired_timestamp = 0; + } + + idx = sched_find_first_bit(array->bitmap); + queue = array->queue + idx; + next = list_entry(queue->next, task_t, run_list); + +switch_tasks: + prefetch(next); + clear_tsk_need_resched(prev); + + if (likely(prev != next)) { + rq->nr_switches++; + rq->curr = next; + + prepare_arch_switch(rq); + prev = context_switch(prev, next); + barrier(); + rq = this_rq(); + finish_arch_switch(rq); + } else + spin_unlock_irq(&rq->lock); + finish_arch_schedule(prev); -same_process: reacquire_kernel_lock(current); - if (current->need_resched) - goto need_resched_back; - return; + if (need_resched()) + goto need_resched; } /* - * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just wake everything - * up. If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the - * non-exclusive tasks and one exclusive task. + * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just + * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve + * number) then we wake all the non-exclusive tasks and one exclusive task. * * There are circumstances in which we can try to wake a task which has already - * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns zero - * in this (rare) case, and we handle it by contonuing to scan the queue. + * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns + * zero in this (rare) case, and we handle it by continuing to scan the queue. */ -static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, - int nr_exclusive, const int sync) +static inline void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int sync) { struct list_head *tmp; - struct task_struct *p; - - CHECK_MAGIC_WQHEAD(q); - WQ_CHECK_LIST_HEAD(&q->task_list); - - list_for_each(tmp,&q->task_list) { - unsigned int state; - wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list); + unsigned int state; + wait_queue_t *curr; + task_t *p; - CHECK_MAGIC(curr->__magic); + list_for_each(tmp, &q->task_list) { + curr = list_entry(tmp, wait_queue_t, task_list); p = curr->task; state = p->state; - if (state & mode) { - WQ_NOTE_WAKER(curr); - if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) + if ((state & mode) && try_to_wake_up(p, sync) && + ((curr->flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)) break; - } } } -void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr) +void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { - if (q) { - unsigned long flags; - wq_read_lock_irqsave(&q->lock, flags); - __wake_up_common(q, mode, nr, 0); - wq_read_unlock_irqrestore(&q->lock, flags); - } + unsigned long flags; + + if (unlikely(!q)) + return; + + spin_lock_irqsave(&q->lock, flags); + __wake_up_common(q, mode, nr_exclusive, 0); + spin_unlock_irqrestore(&q->lock, flags); } -void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr) +#if CONFIG_SMP + +void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { - if (q) { - unsigned long flags; - wq_read_lock_irqsave(&q->lock, flags); - __wake_up_common(q, mode, nr, 1); - wq_read_unlock_irqrestore(&q->lock, flags); - } + unsigned long flags; + + if (unlikely(!q)) + return; + + spin_lock_irqsave(&q->lock, flags); + if (likely(nr_exclusive)) + __wake_up_common(q, mode, nr_exclusive, 1); + else + __wake_up_common(q, mode, nr_exclusive, 0); + spin_unlock_irqrestore(&q->lock, flags); } +#endif + void complete(struct completion *x) { unsigned long flags; @@ -793,14 +983,14 @@ init_waitqueue_entry(&wait, current); #define SLEEP_ON_HEAD \ - wq_write_lock_irqsave(&q->lock,flags); \ + spin_lock_irqsave(&q->lock,flags); \ __add_wait_queue(q, &wait); \ - wq_write_unlock(&q->lock); + spin_unlock(&q->lock); #define SLEEP_ON_TAIL \ - wq_write_lock_irq(&q->lock); \ + spin_lock_irq(&q->lock); \ __remove_wait_queue(q, &wait); \ - wq_write_unlock_irqrestore(&q->lock,flags); + spin_unlock_irqrestore(&q->lock, flags); void interruptible_sleep_on(wait_queue_head_t *q) { @@ -852,6 +1042,41 @@ void scheduling_functions_end_here(void) { } +void set_user_nice(task_t *p, long nice) +{ + unsigned long flags; + prio_array_t *array; + runqueue_t *rq; + + if (TASK_NICE(p) == nice || nice < -20 || nice > 19) + return; + /* + * We have to be careful, if called from sys_setpriority(), + * the task might be in the middle of scheduling on another CPU. + */ + rq = task_rq_lock(p, &flags); + if (rt_task(p)) { + p->static_prio = NICE_TO_PRIO(nice); + goto out_unlock; + } + array = p->array; + if (array) + dequeue_task(p, array); + p->static_prio = NICE_TO_PRIO(nice); + p->prio = NICE_TO_PRIO(nice); + if (array) { + enqueue_task(p, array); + /* + * If the task is running and lowered its priority, + * or increased its priority then reschedule its CPU: + */ + if ((NICE_TO_PRIO(nice) < p->static_prio) || (p == rq->curr)) + resched_task(rq->curr); + } +out_unlock: + task_rq_unlock(rq, &flags); +} + #ifndef __alpha__ /* @@ -862,7 +1087,7 @@ asmlinkage long sys_nice(int increment) { - long newprio; + long nice; /* * Setpriority might change our priority at the same moment. @@ -878,34 +1103,47 @@ if (increment > 40) increment = 40; - newprio = current->nice + increment; - if (newprio < -20) - newprio = -20; - if (newprio > 19) - newprio = 19; - current->nice = newprio; + nice = PRIO_TO_NICE(current->static_prio) + increment; + if (nice < -20) + nice = -20; + if (nice > 19) + nice = 19; + set_user_nice(current, nice); return 0; } #endif -static inline struct task_struct *find_process_by_pid(pid_t pid) +/* + * This is the priority value as seen by users in /proc + * + * RT tasks are offset by -200. Normal tasks are centered + * around 0, value goes from -16 to +15. + */ +int task_prio(task_t *p) { - struct task_struct *tsk = current; + return p->prio - MAX_USER_RT_PRIO; +} - if (pid) - tsk = find_task_by_pid(pid); - return tsk; +int task_nice(task_t *p) +{ + return TASK_NICE(p); } -static int setscheduler(pid_t pid, int policy, - struct sched_param *param) +static inline task_t *find_process_by_pid(pid_t pid) +{ + return pid ? find_task_by_pid(pid) : current; +} + +static int setscheduler(pid_t pid, int policy, struct sched_param *param) { struct sched_param lp; - struct task_struct *p; - int retval; + int retval = -EINVAL; + prio_array_t *array; + unsigned long flags; + runqueue_t *rq; + task_t *p; - retval = -EINVAL; if (!param || pid < 0) goto out_nounlock; @@ -917,14 +1155,19 @@ * We play safe to avoid deadlocks. */ read_lock_irq(&tasklist_lock); - spin_lock(&runqueue_lock); p = find_process_by_pid(pid); retval = -ESRCH; if (!p) - goto out_unlock; - + goto out_unlock_tasklist; + + /* + * To be able to change p->policy safely, the apropriate + * runqueue lock must be held. + */ + rq = task_rq_lock(p, &flags); + if (policy < 0) policy = p->policy; else { @@ -933,42 +1176,48 @@ policy != SCHED_OTHER) goto out_unlock; } - + /* - * Valid priorities for SCHED_FIFO and SCHED_RR are 1..99, valid - * priority for SCHED_OTHER is 0. + * Valid priorities for SCHED_FIFO and SCHED_RR are + * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_OTHER is 0. */ retval = -EINVAL; - if (lp.sched_priority < 0 || lp.sched_priority > 99) + if (lp.sched_priority < 0 || lp.sched_priority > MAX_USER_RT_PRIO-1) goto out_unlock; if ((policy == SCHED_OTHER) != (lp.sched_priority == 0)) goto out_unlock; retval = -EPERM; - if ((policy == SCHED_FIFO || policy == SCHED_RR) && + if ((policy == SCHED_FIFO || policy == SCHED_RR) && !capable(CAP_SYS_NICE)) goto out_unlock; if ((current->euid != p->euid) && (current->euid != p->uid) && !capable(CAP_SYS_NICE)) goto out_unlock; + array = p->array; + if (array) + deactivate_task(p, task_rq(p)); retval = 0; p->policy = policy; p->rt_priority = lp.sched_priority; - if (task_on_runqueue(p)) - move_first_runqueue(p); - - current->need_resched = 1; + if (policy != SCHED_OTHER) + p->prio = MAX_USER_RT_PRIO-1 - p->rt_priority; + else + p->prio = p->static_prio; + if (array) + activate_task(p, task_rq(p)); out_unlock: - spin_unlock(&runqueue_lock); + task_rq_unlock(rq, &flags); +out_unlock_tasklist: read_unlock_irq(&tasklist_lock); out_nounlock: return retval; } -asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, +asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param) { return setscheduler(pid, policy, param); @@ -981,10 +1230,9 @@ asmlinkage long sys_sched_getscheduler(pid_t pid) { - struct task_struct *p; - int retval; + int retval = -EINVAL; + task_t *p; - retval = -EINVAL; if (pid < 0) goto out_nounlock; @@ -992,7 +1240,7 @@ read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (p) - retval = p->policy & ~SCHED_YIELD; + retval = p->policy; read_unlock(&tasklist_lock); out_nounlock: @@ -1001,11 +1249,10 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param) { - struct task_struct *p; struct sched_param lp; - int retval; + int retval = -EINVAL; + task_t *p; - retval = -EINVAL; if (!param || pid < 0) goto out_nounlock; @@ -1030,63 +1277,141 @@ return retval; } -asmlinkage long sys_sched_yield(void) +/** + * sys_sched_setaffinity - set the cpu affinity of a process + * @pid: pid of the process + * @len: length in bytes of the bitmask pointed to by user_mask_ptr + * @user_mask_ptr: user-space pointer to the new cpu mask + */ +asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len, + unsigned long *user_mask_ptr) { + unsigned long new_mask; + int retval; + task_t *p; + + if (len < sizeof(new_mask)) + return -EINVAL; + + if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) + return -EFAULT; + + new_mask &= cpu_online_map; + if (!new_mask) + return -EINVAL; + + read_lock(&tasklist_lock); + + p = find_process_by_pid(pid); + if (!p) { + read_unlock(&tasklist_lock); + return -ESRCH; + } + /* - * Trick. sched_yield() first counts the number of truly - * 'pending' runnable processes, then returns if it's - * only the current processes. (This test does not have - * to be atomic.) In threaded applications this optimization - * gets triggered quite often. + * It is not safe to call set_cpus_allowed with the + * tasklist_lock held. We will bump the task_struct's + * usage count and then drop tasklist_lock. */ + get_task_struct(p); + read_unlock(&tasklist_lock); - int nr_pending = nr_running; + retval = -EPERM; + if ((current->euid != p->euid) && (current->euid != p->uid) && + !capable(CAP_SYS_NICE)) + goto out_unlock; -#if CONFIG_SMP - int i; + retval = 0; + set_cpus_allowed(p, new_mask); - // Subtract non-idle processes running on other CPUs. - for (i = 0; i < smp_num_cpus; i++) { - int cpu = cpu_logical_map(i); - if (aligned_data[cpu].schedule_data.curr != idle_task(cpu)) - nr_pending--; - } -#else - // on UP this process is on the runqueue as well - nr_pending--; -#endif - if (nr_pending) { - /* - * This process can only be rescheduled by us, - * so this is safe without any locking. - */ - if (current->policy == SCHED_OTHER) - current->policy |= SCHED_YIELD; - current->need_resched = 1; - - spin_lock_irq(&runqueue_lock); - move_last_runqueue(current); - spin_unlock_irq(&runqueue_lock); - } - return 0; +out_unlock: + free_task_struct(p); + return retval; } /** - * yield - yield the current processor to other threads. - * - * this is a shortcut for kernel-space yielding - it marks the - * thread runnable and calls sys_sched_yield(). + * sys_sched_getaffinity - get the cpu affinity of a process + * @pid: pid of the process + * @len: length in bytes of the bitmask pointed to by user_mask_ptr + * @user_mask_ptr: user-space pointer to hold the current cpu mask */ -void yield(void) +asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len, + unsigned long *user_mask_ptr) { - set_current_state(TASK_RUNNING); - sys_sched_yield(); + unsigned int real_len; + unsigned long mask; + int retval; + task_t *p; + + real_len = sizeof(mask); + if (len < real_len) + return -EINVAL; + + read_lock(&tasklist_lock); + + retval = -ESRCH; + p = find_process_by_pid(pid); + if (!p) + goto out_unlock; + + retval = 0; + mask = p->cpus_allowed & cpu_online_map; + +out_unlock: + read_unlock(&tasklist_lock); + if (retval) + return retval; + if (copy_to_user(user_mask_ptr, &mask, real_len)) + return -EFAULT; + return real_len; } -void __cond_resched(void) +asmlinkage long sys_sched_yield(void) { - set_current_state(TASK_RUNNING); + runqueue_t *rq = this_rq_lock(); + prio_array_t *array = current->array; + + /* + * There are three levels of how a yielding task will give up + * the current CPU: + * + * #1 - it decreases its priority by one. This priority loss is + * temporary, it's recovered once the current timeslice + * expires. + * + * #2 - once it has reached the lowest priority level, + * it will give up timeslices one by one. (We do not + * want to give them up all at once, it's gradual, + * to protect the casual yield()er.) + * + * #3 - once all timeslices are gone we put the process into + * the expired array. + * + * (special rule: RT tasks do not lose any priority, they just + * roundrobin on their current priority level.) + */ + if (likely(current->prio == MAX_PRIO-1)) { + if (current->time_slice <= 1) { + dequeue_task(current, rq->active); + enqueue_task(current, rq->expired); + } else + current->time_slice--; + } else if (unlikely(rt_task(current))) { + list_del(¤t->run_list); + list_add_tail(¤t->run_list, array->queue + current->prio); + } else { + list_del(¤t->run_list); + if (list_empty(array->queue + current->prio)) + __clear_bit(current->prio, array->bitmap); + current->prio++; + list_add_tail(¤t->run_list, array->queue + current->prio); + __set_bit(current->prio, array->bitmap); + } + spin_unlock(&rq->lock); + schedule(); + + return 0; } asmlinkage long sys_sched_get_priority_max(int policy) @@ -1096,7 +1421,7 @@ switch (policy) { case SCHED_FIFO: case SCHED_RR: - ret = 99; + ret = MAX_USER_RT_PRIO-1; break; case SCHED_OTHER: ret = 0; @@ -1122,9 +1447,9 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) { - struct timespec t; - struct task_struct *p; int retval = -EINVAL; + struct timespec t; + task_t *p; if (pid < 0) goto out_nounlock; @@ -1133,8 +1458,8 @@ read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (p) - jiffies_to_timespec(p->policy & SCHED_FIFO ? 0 : NICE_TO_TICKS(p->nice), - &t); + jiffies_to_timespec(p->policy & SCHED_FIFO ? + 0 : TASK_TIMESLICE(p), &t); read_unlock(&tasklist_lock); if (p) retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; @@ -1142,14 +1467,14 @@ return retval; } -static void show_task(struct task_struct * p) +static void show_task(task_t * p) { unsigned long free = 0; int state; static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" }; printk("%-13.13s ", p->comm); - state = p->state ? ffz(~p->state) + 1 : 0; + state = p->state ? __ffs(p->state) + 1 : 0; if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *)) printk(stat_nam[state]); else @@ -1190,7 +1515,7 @@ printk(" (NOTLB)\n"); { - extern void show_trace_task(struct task_struct *tsk); + extern void show_trace_task(task_t *tsk); show_trace_task(p); } } @@ -1212,7 +1537,7 @@ void show_state(void) { - struct task_struct *p; + task_t *p; #if (BITS_PER_LONG == 32) printk("\n" @@ -1235,128 +1560,271 @@ read_unlock(&tasklist_lock); } -/** - * reparent_to_init() - Reparent the calling kernel thread to the init task. - * - * If a kernel thread is launched as a result of a system call, or if - * it ever exits, it should generally reparent itself to init so that - * it is correctly cleaned up on exit. +/* + * double_rq_lock - safely lock two runqueues * - * The various task state such as scheduling policy and priority may have - * been inherited fro a user process, so we reset them to sane values here. + * Note this does not disable interrupts like task_rq_lock, + * you need to do so manually before calling. + */ +static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2) +{ + if (rq1 == rq2) + spin_lock(&rq1->lock); + else { + if (rq1 < rq2) { + spin_lock(&rq1->lock); + spin_lock(&rq2->lock); + } else { + spin_lock(&rq2->lock); + spin_lock(&rq1->lock); + } + } +} + +/* + * double_rq_unlock - safely unlock two runqueues * - * NOTE that reparent_to_init() gives the caller full capabilities. + * Note this does not restore interrupts like task_rq_unlock, + * you need to do so manually after calling. */ -void reparent_to_init(void) +static inline void double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2) { - struct task_struct *this_task = current; + spin_unlock(&rq1->lock); + if (rq1 != rq2) + spin_unlock(&rq2->lock); +} - write_lock_irq(&tasklist_lock); +void __init init_idle(task_t *idle, int cpu) +{ + runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(idle->cpu); + unsigned long flags; - /* Reparent to init */ - REMOVE_LINKS(this_task); - this_task->p_pptr = child_reaper; - this_task->p_opptr = child_reaper; - SET_LINKS(this_task); + __save_flags(flags); + __cli(); + double_rq_lock(idle_rq, rq); + + idle_rq->curr = idle_rq->idle = idle; + deactivate_task(idle, rq); + idle->array = NULL; + idle->prio = MAX_PRIO; + idle->state = TASK_RUNNING; + idle->cpu = cpu; + double_rq_unlock(idle_rq, rq); + set_tsk_need_resched(idle); + __restore_flags(flags); +} - /* Set the exit signal to SIGCHLD so we signal init on exit */ - this_task->exit_signal = SIGCHLD; +extern void init_timervecs(void); +extern void timer_bh(void); +extern void tqueue_bh(void); +extern void immediate_bh(void); - /* We also take the runqueue_lock while altering task fields - * which affect scheduling decisions */ - spin_lock(&runqueue_lock); +void __init sched_init(void) +{ + runqueue_t *rq; + int i, j, k; - this_task->ptrace = 0; - this_task->nice = DEF_NICE; - this_task->policy = SCHED_OTHER; - /* cpus_allowed? */ - /* rt_priority? */ - /* signals? */ - this_task->cap_effective = CAP_INIT_EFF_SET; - this_task->cap_inheritable = CAP_INIT_INH_SET; - this_task->cap_permitted = CAP_FULL_SET; - this_task->keep_capabilities = 0; - memcpy(this_task->rlim, init_task.rlim, sizeof(*(this_task->rlim))); - this_task->user = INIT_USER; + for (i = 0; i < NR_CPUS; i++) { + prio_array_t *array; - spin_unlock(&runqueue_lock); - write_unlock_irq(&tasklist_lock); + rq = cpu_rq(i); + rq->active = rq->arrays; + rq->expired = rq->arrays + 1; + spin_lock_init(&rq->lock); + INIT_LIST_HEAD(&rq->migration_queue); + + for (j = 0; j < 2; j++) { + array = rq->arrays + j; + for (k = 0; k < MAX_PRIO; k++) { + INIT_LIST_HEAD(array->queue + k); + __clear_bit(k, array->bitmap); + } + // delimiter for bitsearch + __set_bit(MAX_PRIO, array->bitmap); + } + } + /* + * We have to do a little magic to get the first + * process right in SMP mode. + */ + rq = this_rq(); + rq->curr = current; + rq->idle = current; + wake_up_process(current); + + init_timervecs(); + init_bh(TIMER_BH, timer_bh); + init_bh(TQUEUE_BH, tqueue_bh); + init_bh(IMMEDIATE_BH, immediate_bh); + + /* + * The boot idle thread does lazy MMU switching as well: + */ + atomic_inc(&init_mm.mm_count); + enter_lazy_tlb(&init_mm, current, smp_processor_id()); } +#if CONFIG_SMP + /* - * Put all the gunge required to become a kernel thread without - * attached user resources in one place where it belongs. + * This is how migration works: + * + * 1) we queue a migration_req_t structure in the source CPU's + * runqueue and wake up that CPU's migration thread. + * 2) we down() the locked semaphore => thread blocks. + * 3) migration thread wakes up (implicitly it forces the migrated + * thread off the CPU) + * 4) it gets the migration request and checks whether the migrated + * task is still in the wrong runqueue. + * 5) if it's in the wrong runqueue then the migration thread removes + * it and puts it into the right queue. + * 6) migration thread up()s the semaphore. + * 7) we wake up and the migration is done. */ -void daemonize(void) +typedef struct { + list_t list; + task_t *task; + struct semaphore sem; +} migration_req_t; + +/* + * Change a given task's CPU affinity. Migrate the process to a + * proper CPU and schedule it away if the CPU it's executing on + * is removed from the allowed bitmask. + * + * NOTE: the caller must have a valid reference to the task, the + * task must not exit() & deallocate itself prematurely. The + * call is not atomic; no spinlocks may be held. + */ +void set_cpus_allowed(task_t *p, unsigned long new_mask) { - struct fs_struct *fs; + unsigned long flags; + migration_req_t req; + runqueue_t *rq; + new_mask &= cpu_online_map; + if (!new_mask) + BUG(); + rq = task_rq_lock(p, &flags); + p->cpus_allowed = new_mask; /* - * If we were started as result of loading a module, close all of the - * user space pages. We don't need them, and if we didn't close them - * they would be locked into memory. + * Can the task run on the task's current CPU? If not then + * migrate the process off to a proper CPU. */ - exit_mm(current); - - current->session = 1; - current->pgrp = 1; - current->tty = NULL; - - /* Become as one with the init task */ + if (new_mask & (1UL << p->cpu)) { + task_rq_unlock(rq, &flags); + goto out; + } + /* + * If the task is not on a runqueue (and not running), then + * it is sufficient to simply update the task's cpu field. + */ + if (!p->array && (p != rq->curr)) { + p->cpu = __ffs(p->cpus_allowed); + task_rq_unlock(rq, &flags); + goto out; + } + init_MUTEX_LOCKED(&req.sem); + req.task = p; + list_add(&req.list, &rq->migration_queue); + task_rq_unlock(rq, &flags); + wake_up_process(rq->migration_thread); - exit_fs(current); /* current->fs->count--; */ - fs = init_task.fs; - current->fs = fs; - atomic_inc(&fs->count); - exit_files(current); - current->files = init_task.files; - atomic_inc(¤t->files->count); + down(&req.sem); +out: + ; } -extern unsigned long wait_init_idle; - -void __init init_idle(void) +static int migration_thread(void * bind_cpu) { - struct schedule_data * sched_data; - sched_data = &aligned_data[smp_processor_id()].schedule_data; + struct sched_param param = { sched_priority: MAX_RT_PRIO-1 }; + int cpu = cpu_logical_map((int) (long) bind_cpu); + runqueue_t *rq; + int ret; - if (current != &init_task && task_on_runqueue(current)) { - printk("UGH! (%d:%d) was on the runqueue, removing.\n", - smp_processor_id(), current->pid); - del_from_runqueue(current); + daemonize(); + sigfillset(¤t->blocked); + set_fs(KERNEL_DS); + /* + * The first migration thread is started on CPU #0. This one can + * migrate the other migration threads to their destination CPUs. + */ + if (cpu != 0) { + while (!cpu_rq(cpu_logical_map(0))->migration_thread) + yield(); + set_cpus_allowed(current, 1UL << cpu); } - sched_data->curr = current; - sched_data->last_schedule = get_cycles(); - clear_bit(current->processor, &wait_init_idle); -} + printk("migration_task %d on cpu=%d\n", cpu, smp_processor_id()); + ret = setscheduler(0, SCHED_FIFO, ¶m); -extern void init_timervecs (void); + rq = this_rq(); + rq->migration_thread = current; -void __init sched_init(void) -{ - /* - * We have to do a little magic to get the first - * process right in SMP mode. - */ - int cpu = smp_processor_id(); - int nr; + sprintf(current->comm, "migration_CPU%d", smp_processor_id()); + + for (;;) { + runqueue_t *rq_src, *rq_dest; + struct list_head *head; + int cpu_src, cpu_dest; + migration_req_t *req; + unsigned long flags; + task_t *p; - init_task.processor = cpu; + spin_lock_irqsave(&rq->lock, flags); + head = &rq->migration_queue; + current->state = TASK_INTERRUPTIBLE; + if (list_empty(head)) { + spin_unlock_irqrestore(&rq->lock, flags); + schedule(); + continue; + } + req = list_entry(head->next, migration_req_t, list); + list_del_init(head->next); + spin_unlock_irqrestore(&rq->lock, flags); + + p = req->task; + cpu_dest = __ffs(p->cpus_allowed); + rq_dest = cpu_rq(cpu_dest); +repeat: + cpu_src = p->cpu; + rq_src = cpu_rq(cpu_src); + + local_irq_save(flags); + double_rq_lock(rq_src, rq_dest); + if (p->cpu != cpu_src) { + double_rq_unlock(rq_src, rq_dest); + local_irq_restore(flags); + goto repeat; + } + if (rq_src == rq) { + p->cpu = cpu_dest; + if (p->array) { + deactivate_task(p, rq_src); + activate_task(p, rq_dest); + } + } + double_rq_unlock(rq_src, rq_dest); + local_irq_restore(flags); - for(nr = 0; nr < PIDHASH_SZ; nr++) - pidhash[nr] = NULL; + up(&req->sem); + } +} - init_timervecs(); +void __init migration_init(void) +{ + int cpu; - init_bh(TIMER_BH, timer_bh); - init_bh(TQUEUE_BH, tqueue_bh); - init_bh(IMMEDIATE_BH, immediate_bh); + current->cpus_allowed = 1UL << cpu_logical_map(0); + for (cpu = 0; cpu < smp_num_cpus; cpu++) + if (kernel_thread(migration_thread, (void *) (long) cpu, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) + BUG(); + current->cpus_allowed = -1L; - /* - * The boot idle thread does lazy MMU switching as well: - */ - atomic_inc(&init_mm.mm_count); - enter_lazy_tlb(&init_mm, current, cpu); + for (cpu = 0; cpu < smp_num_cpus; cpu++) + while (!cpu_rq(cpu_logical_map(cpu))->migration_thread) + schedule_timeout(2); } +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/signal.c linux.20pre2-ac1/kernel/signal.c --- linux.20pre2/kernel/signal.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/signal.c 2002-08-06 15:41:51.000000000 +0100 @@ -492,7 +492,7 @@ * No need to set need_resched since signal event passing * goes through ->blocked */ -static inline void signal_wake_up(struct task_struct *t) +inline void signal_wake_up(struct task_struct *t) { t->sigpending = 1; @@ -507,12 +507,9 @@ * process of changing - but no harm is done by that * other than doing an extra (lightweight) IPI interrupt. */ - spin_lock(&runqueue_lock); - if (task_has_cpu(t) && t->processor != smp_processor_id()) - smp_send_reschedule(t->processor); - spin_unlock(&runqueue_lock); -#endif /* CONFIG_SMP */ - + if ((t->state == TASK_RUNNING) && (t->cpu != cpu())) + kick_if_running(t); +#endif if (t->state & TASK_INTERRUPTIBLE) { wake_up_process(t); return; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/softirq.c linux.20pre2-ac1/kernel/softirq.c --- linux.20pre2/kernel/softirq.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/softirq.c 2002-08-06 15:41:51.000000000 +0100 @@ -40,7 +40,7 @@ - Bottom halves: globally serialized, grr... */ -irq_cpustat_t irq_stat[NR_CPUS]; +irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned; static struct softirq_action softirq_vec[32] __cacheline_aligned; @@ -259,10 +259,9 @@ while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { current->state = TASK_RUNNING; - do { - current->policy |= SCHED_YIELD; - schedule(); - } while (test_bit(TASKLET_STATE_SCHED, &t->state)); + do + sys_sched_yield(); + while (test_bit(TASKLET_STATE_SCHED, &t->state)); } tasklet_unlock_wait(t); clear_bit(TASKLET_STATE_SCHED, &t->state); @@ -365,13 +364,13 @@ int cpu = cpu_logical_map(bind_cpu); daemonize(); - current->nice = 19; + set_user_nice(current, 19); sigfillset(¤t->blocked); /* Migrate to the right CPU */ - current->cpus_allowed = 1UL << cpu; - while (smp_processor_id() != cpu) - schedule(); + set_cpus_allowed(current, 1UL << cpu); + if (cpu() != cpu) + BUG(); sprintf(current->comm, "ksoftirqd_CPU%d", bind_cpu); @@ -396,7 +395,7 @@ } } -static __init int spawn_ksoftirqd(void) +__init int spawn_ksoftirqd(void) { int cpu; @@ -405,10 +404,8 @@ CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) printk("spawn_ksoftirqd() failed for cpu %d\n", cpu); else { - while (!ksoftirqd_task(cpu_logical_map(cpu))) { - current->policy |= SCHED_YIELD; - schedule(); - } + while (!ksoftirqd_task(cpu_logical_map(cpu))) + sys_sched_yield(); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/sys.c linux.20pre2-ac1/kernel/sys.c --- linux.20pre2/kernel/sys.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/sys.c 2002-08-06 15:41:51.000000000 +0100 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -220,10 +221,10 @@ } if (error == -ESRCH) error = 0; - if (niceval < p->nice && !capable(CAP_SYS_NICE)) + if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) error = -EACCES; else - p->nice = niceval; + set_user_nice(p, niceval); } read_unlock(&tasklist_lock); @@ -249,7 +250,7 @@ long niceval; if (!proc_sel(p, which, who)) continue; - niceval = 20 - p->nice; + niceval = 20 - task_nice(p); if (niceval > retval) retval = niceval; } @@ -490,9 +491,10 @@ } } -static int set_user(uid_t new_ruid, int dumpclear) +int set_user(uid_t new_ruid, int dumpclear) { struct user_struct *new_user, *old_user; + struct task_struct *this_task = current; /* What if a process setreuid()'s and this brings the * new uid over his NPROC rlimit? We can check this now @@ -502,17 +504,16 @@ new_user = alloc_uid(new_ruid); if (!new_user) return -EAGAIN; - old_user = current->user; - atomic_dec(&old_user->processes); + old_user = this_task->user; atomic_inc(&new_user->processes); + atomic_dec(&old_user->processes); - if(dumpclear) - { - current->mm->dumpable = 0; + if (dumpclear && this_task->mm) { + this_task->mm->dumpable = 0; wmb(); } - current->uid = new_ruid; - current->user = new_user; + this_task->uid = new_ruid; + this_task->user = new_user; free_uid(old_user); return 0; } @@ -1128,6 +1129,12 @@ if (resource == RLIMIT_NOFILE) { if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN) return -EPERM; + } else if (resource == RLIMIT_RSS && current->mm) { + /* rlimit is specified in bytes, convert to pages */ + unsigned long pages = RLIM_INFINITY; + if (new_rlim.rlim_cur != RLIM_INFINITY) + pages = new_rlim.rlim_cur >> PAGE_SHIFT; + current->mm->rlimit_rss = pages; } *old_rlim = new_rlim; return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/sysctl.c linux.20pre2-ac1/kernel/sysctl.c --- linux.20pre2/kernel/sysctl.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/kernel/sysctl.c 2002-08-06 15:41:51.000000000 +0100 @@ -271,12 +271,12 @@ &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec}, {VM_PAGE_CLUSTER, "page-cluster", &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec}, + {VM_MAX_MAP_COUNT, "max_map_count", + &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec}, {VM_MIN_READAHEAD, "min-readahead", &vm_min_readahead,sizeof(int), 0644, NULL, &proc_dointvec}, {VM_MAX_READAHEAD, "max-readahead", &vm_max_readahead,sizeof(int), 0644, NULL, &proc_dointvec}, - {VM_MAX_MAP_COUNT, "max_map_count", - &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec}, {0} }; @@ -293,8 +293,6 @@ 0444, NULL, &proc_dointvec}, {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int), 0644, NULL, &proc_dointvec}, - {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int), - 0444, NULL, &proc_dointvec}, {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int), 0444, NULL, &proc_dointvec}, {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/kernel/timer.c linux.20pre2-ac1/kernel/timer.c --- linux.20pre2/kernel/timer.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/kernel/timer.c 2002-08-06 17:22:29.000000000 +0100 @@ -25,6 +25,8 @@ #include +struct kernel_stat kstat; + /* * Timekeeping variables */ @@ -598,18 +600,7 @@ int cpu = smp_processor_id(), system = user_tick ^ 1; update_one_process(p, user_tick, system, cpu); - if (p->pid) { - if (--p->counter <= 0) { - p->counter = 0; - p->need_resched = 1; - } - if (p->nice > 0) - kstat.per_cpu_nice[cpu] += user_tick; - else - kstat.per_cpu_user[cpu] += user_tick; - kstat.per_cpu_system[cpu] += system; - } else if (local_bh_count(cpu) || local_irq_count(cpu) > 1) - kstat.per_cpu_system[cpu] += system; + scheduler_tick(user_tick, system); } /* @@ -617,17 +608,7 @@ */ static unsigned long count_active_tasks(void) { - struct task_struct *p; - unsigned long nr = 0; - - read_lock(&tasklist_lock); - for_each_task(p) { - if ((p->state == TASK_RUNNING || - (p->state & TASK_UNINTERRUPTIBLE))) - nr += FIXED_1; - } - read_unlock(&tasklist_lock); - return nr; + return (nr_running() + nr_uninterruptible()) * FIXED_1; } /* @@ -812,6 +793,89 @@ #endif +static void process_timeout(unsigned long __data) +{ + wake_up_process((task_t *)__data); +} + +/** + * schedule_timeout - sleep until timeout + * @timeout: timeout value in jiffies + * + * Make the current task sleep until @timeout jiffies have + * elapsed. The routine will return immediately unless + * the current task state has been set (see set_current_state()). + * + * You can set the task state as follows - + * + * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to + * pass before the routine returns. The routine will return 0 + * + * %TASK_INTERRUPTIBLE - the routine may return early if a signal is + * delivered to the current task. In this case the remaining time + * in jiffies will be returned, or 0 if the timer expired in time + * + * The current task state is guaranteed to be TASK_RUNNING when this + * routine returns. + * + * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule + * the CPU away without a bound on the timeout. In this case the return + * value will be %MAX_SCHEDULE_TIMEOUT. + * + * In all cases the return value is guaranteed to be non-negative. + */ +signed long schedule_timeout(signed long timeout) +{ + struct timer_list timer; + unsigned long expire; + + switch (timeout) + { + case MAX_SCHEDULE_TIMEOUT: + /* + * These two special cases are useful to be comfortable + * in the caller. Nothing more. We could take + * MAX_SCHEDULE_TIMEOUT from one of the negative value + * but I' d like to return a valid offset (>=0) to allow + * the caller to do everything it want with the retval. + */ + schedule(); + goto out; + default: + /* + * Another bit of PARANOID. Note that the retval will be + * 0 since no piece of kernel is supposed to do a check + * for a negative retval of schedule_timeout() (since it + * should never happens anyway). You just have the printk() + * that will tell you if something is gone wrong and where. + */ + if (timeout < 0) + { + printk(KERN_ERR "schedule_timeout: wrong timeout " + "value %lx from %p\n", timeout, + __builtin_return_address(0)); + current->state = TASK_RUNNING; + goto out; + } + } + + expire = timeout + jiffies; + + init_timer(&timer); + timer.expires = expire; + timer.data = (unsigned long) current; + timer.function = process_timeout; + + add_timer(&timer); + schedule(); + del_timer_sync(&timer); + + timeout = expire - jiffies; + + out: + return timeout < 0 ? 0 : timeout; +} + /* Thread ID - the internal kernel "pid" */ asmlinkage long sys_gettid(void) { @@ -858,4 +922,3 @@ } return 0; } - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/lib/inflate.c linux.20pre2-ac1/lib/inflate.c --- linux.20pre2/lib/inflate.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/lib/inflate.c 2002-08-06 15:41:51.000000000 +0100 @@ -1009,7 +1009,7 @@ static ulg crc_32_tab[256]; static ulg crc; /* initialized in makecrc() so it'll reside in bss */ -#define CRC_VALUE (crc ^ 0xffffffffL) +#define CRC_VALUE (crc ^ 0xffffffffUL) /* * Code to compute the CRC-32 table. Borrowed from @@ -1049,7 +1049,7 @@ } /* this is initialized here so this code could reside in ROM */ - crc = (ulg)0xffffffffL; /* shift register contents */ + crc = (ulg)0xffffffffUL; /* shift register contents */ } /* gzip flag byte */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/lib/rwsem-spinlock.c linux.20pre2-ac1/lib/rwsem-spinlock.c --- linux.20pre2/lib/rwsem-spinlock.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/lib/rwsem-spinlock.c 2002-08-06 15:41:51.000000000 +0100 @@ -4,6 +4,8 @@ * Copyright (c) 2001 David Howells (dhowells@redhat.com). * - Derived partially from idea by Andrea Arcangeli * - Derived also from comments by Linus + * + * Trylock by Brian Watson (Brian.J.Watson@compaq.com). */ #include #include @@ -149,6 +151,28 @@ } /* + * trylock for reading -- returns 1 if successful, 0 if contention + */ +int __down_read_trylock(struct rw_semaphore *sem) +{ + int ret = 0; + rwsemtrace(sem,"Entering __down_read_trylock"); + + spin_lock(&sem->wait_lock); + + if (sem->activity>=0 && list_empty(&sem->wait_list)) { + /* granted */ + sem->activity++; + ret = 1; + } + + spin_unlock(&sem->wait_lock); + + rwsemtrace(sem,"Leaving __down_read_trylock"); + return ret; +} + +/* * get a write lock on the semaphore * - note that we increment the waiting count anyway to indicate an exclusive lock */ @@ -195,6 +219,28 @@ } /* + * trylock for writing -- returns 1 if successful, 0 if contention + */ +int __down_write_trylock(struct rw_semaphore *sem) +{ + int ret = 0; + rwsemtrace(sem,"Entering __down_write_trylock"); + + spin_lock(&sem->wait_lock); + + if (sem->activity==0 && list_empty(&sem->wait_list)) { + /* granted */ + sem->activity = -1; + ret = 1; + } + + spin_unlock(&sem->wait_lock); + + rwsemtrace(sem,"Leaving __down_write_trylock"); + return ret; +} + +/* * release a read lock on the semaphore */ void __up_read(struct rw_semaphore *sem) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/MAINTAINERS linux.20pre2-ac1/MAINTAINERS --- linux.20pre2/MAINTAINERS 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/MAINTAINERS 2002-08-13 14:55:39.000000000 +0100 @@ -153,6 +153,14 @@ W: http://www.ibm.com/linux/ltc/ S: Supported +AACRAID SCSI RAID DRIVER +P: Adaptec OEM Raid Solutions +M: linux-aacraid-devel@dell.com +L: linux-aacraid-devel@dell.com +L: linux-aacraid-announce@dell.com +W: http://domsch.com/linux +S: Supported + ACPI P: Andy Grover M: andrew.grover@intel.com @@ -241,6 +249,12 @@ W: http://www.ife.ee.ethz.ch/~sailer/ham/ham.html S: Maintained +BEFS FILE SYSTEM +P: Will Dyson +M: will@cs.earlham.edu +W: http://cs.earlham.edu/~will/software/linux/kernel/BeFS.html +S: Maintained + BERKSHIRE PRODUCTS PC WATCHDOG DRIVER P: Kenji Hollis M: kenji@bitgate.com @@ -632,8 +646,8 @@ S: Maintained HFS FILESYSTEM -P: Adrian Sun -M: asun@cobaltnet.com +P: Oliver Neukum +M: oliver@neukum.org L: linux-kernel@vger.kernel.org S: Maintained @@ -858,6 +872,13 @@ W: http://sources.redhat.com/jffs2/ S: Maintained +JFS FILESYSTEM +P: Dave Kleikamp +M: shaggy@austin.ibm.com +L: jfs-discussion@oss.software.ibm.com +W: http://oss.software.ibm.com/developerworks/opensource/jfs/ +S: Supported + JOYSTICK DRIVER P: Vojtech Pavlik M: vojtech@suse.cz @@ -932,6 +953,11 @@ L: linuxppc-dev@lists.linuxppc.org S: Maintained +LLC (802.2) +P: Arnaldo Carvalho de Melo +M: acme@conectiva.com.br +S: Maintained + LINUX FOR 64BIT POWERPC P: David Engebretsen M: engebret@us.ibm.com @@ -953,6 +979,13 @@ W: http://www.sistina.com/lvm S: Maintained +DEVICE-MAPPER +P: Joe Thornber +M: thornber@sistina.com +L: dm@uk.sistina.com +W: http://www.sistina.com/lvm +S: Maintained + LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers P: Gerard Roudier M: groudier@free.fr @@ -1101,7 +1134,6 @@ P: Networking Team M: netdev@oss.sgi.com L: linux-net@vger.kernel.org -W: http://www.uk.linux.org/NetNews.html (2.0 only) S: Maintained NETWORKING [IPv4/IPv6] @@ -1265,6 +1297,13 @@ W: http://www.realitydiluted.com/projects/nino S: Maintained +PHILIPS NINO PALM PC +P: Steven Hill +M: sjhill@realitydiluted.com +L: linux-mips@oss.sgi.com +W: http://www.realitydiluted.com/projects/nino +S: Maintained + PNP SUPPORT P: Tom Lees M: tom@lpsg.demon.co.uk @@ -1295,17 +1334,6 @@ W: http://www.pnd-pc.demon.co.uk/promise/ S: Maintained -PROMISE PDC202XX IDE CONTROLLER DRIVER -P: Hank Yang -M: support@promise.com.tw [TAIWAN] -P: Jordan Rhody -M: support@promise.com [U.S.A] -P: Jack Hu -M: support-china@promise.com [CHINA] -W: http://www.promise.com/support/linux_eng.asp -W: http://www.promise.com.tw/support/linux_eng.asp -S: Maintained - QNX4 FILESYSTEM P: Anders Larsen M: al@alarsen.net @@ -1357,10 +1385,10 @@ S: Maintained RME96XX MULTICHANNEL SOUND DRIVER -P: Guenter Geiger -M: geiger@epy.co.at -L: linux-kernel@vger.kernel.org -S: Maintained +P: Guenter Geiger +M: geiger@epy.co.at +L: linux-kernel@vger.kernel.org +S: Maintained RTLINUX REALTIME LINUX P: Victor Yodaiken @@ -1484,6 +1512,13 @@ L: ultralinux@vger.kernel.org S: Maintained +SPEAKUP Console speech output +P: Kirk Reiser +M: kirk@braille.uwo.ca +L: speakup@braille.uwo.ca +W: http://www.linux-speakup.org +S: Maintained + SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER P: Roger Wolff M: R.E.Wolff@BitWizard.nl @@ -1545,6 +1580,25 @@ M: hch@infradead.org S: Maintained +TI PARALLEL LINK CABLE DRIVER +P: Romain Lievin +M: roms@lpg.ticalc.org +S: Maintained + +TI GRAPH LINK USB (SilverLink) CABLE DRIVER +P: Romain Lievin +M: roms@lpg.ticalc.org +P: Julien Blache +M: jb@technologeek.org +S: Maintained + +TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER +P: Stephane Dalton +M: sdalton@videotron.ca +P: Stéphane Doyon +M: s.doyon@videotron.ca +S: Maintained + TI GRAPH LINK USB (SilverLink) CABLE DRIVER P: Romain Lievin M: roms@lpg.ticalc.org diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Makefile linux.20pre2-ac1/Makefile --- linux.20pre2/Makefile 2002-08-13 13:58:55.000000000 +0100 +++ linux.20pre2-ac1/Makefile 2002-08-13 14:56:01.000000000 +0100 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 20 -EXTRAVERSION = -pre2 +EXTRAVERSION = -pre1-ac3 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -40,10 +40,11 @@ MODFLAGS = -DMODULE CFLAGS_KERNEL = PERL = perl +AWK = awk export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \ CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \ - CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL + CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL AWK all: do-it-all @@ -172,7 +173,7 @@ DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o -DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o +DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a DRIVERS-$(CONFIG_VT) += drivers/video/video.o DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a @@ -180,11 +181,13 @@ DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o +DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o +DRIVERS-$(CONFIG_GSC) += drivers/gsc/gscbus.o DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o @@ -197,6 +200,7 @@ kernel/ksyms.lst include/linux/compile.h \ vmlinux System.map \ .tmp* \ + scripts/mkconfigs kernel/configs.c kernel/configs.o \ drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \ drivers/char/conmakehash \ drivers/char/drm/*-mod.c \ @@ -224,6 +228,7 @@ # files removed with 'make mrproper' MRPROPER_FILES = \ include/linux/autoconf.h include/linux/version.h \ + tmp* \ drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h \ drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \ drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \ @@ -241,6 +246,7 @@ include/asm \ .hdepend scripts/mkdep scripts/split-include scripts/docproc \ $(TOPDIR)/include/linux/modversions.h \ + scripts/mkconfigs kernel/configs.c kernel/configs.o \ kernel.spec # directories removed with 'make mrproper' @@ -314,7 +320,7 @@ linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) -$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h include/config/MARKER +$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h tmp_include_depends $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@) $(TOPDIR)/include/linux/version.h: include/linux/version.h @@ -354,13 +360,13 @@ comma := , -init/version.o: init/version.c include/linux/compile.h include/config/MARKER +init/version.o: init/version.c include/linux/compile.h tmp_include_depends $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(ARCH)"' -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o init/version.o init/version.c -init/main.o: init/main.c include/config/MARKER +init/main.o: init/main.c tmp_include_depends $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $< -init/do_mounts.o: init/do_mounts.c include/config/MARKER +init/do_mounts.o: init/do_mounts.c tmp_include_depends $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $< fs lib mm ipc kernel drivers net: dummy @@ -387,7 +393,7 @@ modules: $(patsubst %, _mod_%, $(SUBDIRS)) .PHONY: $(patsubst %, _mod_%, $(SUBDIRS)) -$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER +$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h tmp_include_depends $(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules .PHONY: modules_install @@ -492,6 +498,13 @@ ifdef CONFIG_MODVERSIONS $(MAKE) update-modverfile endif + (find $(TOPDIR) \( -name .depend -o -name .hdepend \) -print | xargs $(AWK) -f scripts/include_deps) > tmp_include_depends + sed -ne 's/^\([^ ].*\):.*/ \1 \\/p' tmp_include_depends > tmp_include_depends_1 + (echo ""; echo "all: \\"; cat tmp_include_depends_1; echo "") >> tmp_include_depends + rm tmp_include_depends_1 + +tmp_include_depends: include/config/MARKER dummy + $(MAKE) -r -f tmp_include_depends all ifdef CONFIG_MODVERSIONS MODVERFILE := $(TOPDIR)/include/linux/modversions.h diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/bootmem.c linux.20pre2-ac1/mm/bootmem.c --- linux.20pre2/mm/bootmem.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/mm/bootmem.c 2002-08-13 14:56:20.000000000 +0100 @@ -325,7 +325,7 @@ void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) { - pg_data_t *pgdat; + pg_data_t *pgdat = pgdat_list; void *ptr; for_each_pgdat(pgdat) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/filemap.c linux.20pre2-ac1/mm/filemap.c --- linux.20pre2/mm/filemap.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/mm/filemap.c 2002-08-13 17:45:25.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -95,6 +96,9 @@ { struct address_space * mapping = page->mapping; + if (mapping->a_ops->removepage) + mapping->a_ops->removepage(page); + mapping->nrpages--; list_del(&page->list); page->mapping = NULL; @@ -154,14 +158,11 @@ if (mapping) { spin_lock(&pagecache_lock); - mapping = page->mapping; - if (mapping) { /* may have been truncated */ - list_del(&page->list); - list_add(&page->list, &mapping->dirty_pages); - } + list_del(&page->list); + list_add(&page->list, &mapping->dirty_pages); spin_unlock(&pagecache_lock); - if (mapping && mapping->host) + if (mapping->host) mark_inode_dirty_pages(mapping->host); } } @@ -236,6 +237,10 @@ static void truncate_complete_page(struct page *page) { + /* Page has already been removed from processes, by vmtruncate() */ + if (page->pte_chain) + BUG(); + /* Leave it on the LRU if it gets converted into anonymous buffers */ if (!page->buffers || do_flushpage(page, 0)) lru_cache_del(page); @@ -803,18 +808,33 @@ /* On some cpus multiply is faster, on others gcc will do shifts */ hash *= GOLDEN_RATIO_PRIME; #endif - hash >>= zone->wait_table_shift; return &wait[hash]; } + /* * Wait for a page to get unlocked. * * This must be called with the caller "holding" the page, * ie with increased "page->count" so that the page won't * go away during the wait.. + * + * The waiting strategy is to get on a waitqueue determined + * by hashing. Waiters will then collide, and the newly woken + * task must then determine whether it was woken for the page + * it really wanted, and go back to sleep on the waitqueue if + * that wasn't it. With the waitqueue semantics, it never leaves + * the waitqueue unless it calls, so the loop moves forward one + * iteration every time there is + * (1) a collision + * and + * (2) one of the colliding pages is woken + * + * This is the thundering herd problem, but it is expected to + * be very rare due to the few pages that are actually being + * waited on at any given time and the quality of the hash function. */ void ___wait_on_page(struct page *page) { @@ -835,7 +855,11 @@ } /* - * Unlock the page and wake up sleepers in ___wait_on_page. + * unlock_page() is the other half of the story just above + * __wait_on_page(). Here a couple of quick checks are done + * and a couple of flags are set on the page, and then all + * of the waiters for all of the pages in the appropriate + * wait queue are woken. */ void unlock_page(struct page *page) { @@ -845,6 +869,13 @@ if (!test_and_clear_bit(PG_locked, &(page)->flags)) BUG(); smp_mb__after_clear_bit(); + + /* + * Although the default semantics of wake_up() are + * to wake all, here the specific function is used + * to make it even more explicit that a number of + * pages are being waited on here. + */ if (waitqueue_active(waitqueue)) wake_up_all(waitqueue); } @@ -1013,7 +1044,54 @@ /* - * Same as grab_cache_page, but do not wait if the page is unavailable. + * We combine this with read-ahead to deactivate pages when we + * think there's sequential IO going on. Note that this is + * harmless since we don't actually evict the pages from memory + * but just move them to the inactive list. + * + * TODO: + * - make the readahead code smarter + * - move readahead to the VMA level so we can do the same + * trick with mmap() + * + * Rik van Riel, 2000 + */ +static void drop_behind(struct file * file, unsigned long index) +{ + struct inode *inode = file->f_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + struct page *page; + unsigned long start; + + /* Nothing to drop-behind if we're on the first page. */ + if (!index) + return; + + if (index > file->f_rawin) + start = index - file->f_rawin; + else + start = 0; + + /* + * Go backwards from index-1 and drop all pages in the + * readahead window. Since the readahead window may have + * been increased since the last time we were called, we + * stop when the page isn't there. + */ + spin_lock(&pagemap_lru_lock); + while (--index >= start) { + struct page **hash = page_hash(mapping, index); + spin_lock(&pagecache_lock); + page = __find_page_nolock(mapping, index, *hash); + spin_unlock(&pagecache_lock); + if (!page || !PageActive(page)) + break; + drop_page(page); + } + spin_unlock(&pagemap_lru_lock); +} + +/* Same as grab_cache_page, but do not wait if the page is unavailable. * This is intended for speculative data generators, where the data can * be regenerated if the page couldn't be grabbed. This routine should * be safe to call while holding the lock for another page. @@ -1283,6 +1361,12 @@ if (filp->f_ramax > max_readahead) filp->f_ramax = max_readahead; + /* + * Move the pages that have already been passed + * to the inactive list. + */ + drop_behind(filp, index); + #ifdef PROFILE_READAHEAD profile_readahead((reada_ok == 2), filp); #endif @@ -1294,16 +1378,21 @@ /* * Mark a page as having seen activity. * - * If it was already so marked, move it - * to the active queue and drop the referenced - * bit. Otherwise, just mark it for future - * action.. + * We immediately reclaim the inactive clean pages because those are + * counted as freeable. We don't modify the inactive dirty ones because + * we're never sure if those are freeable anyway. */ void mark_page_accessed(struct page *page) { - if (!PageActive(page) && PageReferenced(page)) { + if (PageInactiveClean(page)) { + struct zone_struct *zone = page_zone(page); + int free = zone->free_pages + zone->inactive_clean_pages; + activate_page(page); - ClearPageReferenced(page); + if (free < zone->pages_low) + wakeup_kswapd(GFP_NOIO); + if (zone->free_pages < zone->pages_min) + fixup_freespace(zone, 1); return; } @@ -1819,7 +1908,7 @@ nr = max; /* And limit it to a sane percentage of the inactive list.. */ - max = nr_inactive_pages / 2; + max = nr_inactive_clean_pages / 2; if (nr > max) nr = max; @@ -2960,7 +3049,7 @@ * Check whether we've reached the file size limit. */ err = -EFBIG; - + if (!S_ISBLK(inode->i_mode) && limit != RLIM_INFINITY) { if (pos >= limit) { send_sig(SIGXFSZ, current, 0); @@ -3040,6 +3129,7 @@ unsigned long index, offset; long page_fault; char *kaddr; + int deactivate = 1; /* * Try to find the page in the cache. If it isn't there, @@ -3048,8 +3138,10 @@ offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ index = pos >> PAGE_CACHE_SHIFT; bytes = PAGE_CACHE_SIZE - offset; - if (bytes > count) + if (bytes > count) { bytes = count; + deactivate = 0; + } /* * Bring in the user page that we will copy from _first_. @@ -3093,8 +3185,11 @@ unlock: kunmap(page); /* Mark it unlocked again and drop the page.. */ - SetPageReferenced(page); UnlockPage(page); + if (deactivate) + deactivate_page(page); + else + mark_page_accessed(page); page_cache_release(page); if (status < 0) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/highmem.c linux.20pre2-ac1/mm/highmem.c --- linux.20pre2/mm/highmem.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/mm/highmem.c 2002-08-13 14:56:45.000000000 +0100 @@ -355,9 +355,8 @@ /* we need to wait I/O completion */ run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; __set_current_state(TASK_RUNNING); - schedule(); + yield(); goto repeat_alloc; } @@ -393,9 +392,8 @@ /* we need to wait I/O completion */ run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; __set_current_state(TASK_RUNNING); - schedule(); + yield(); goto repeat_alloc; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/Makefile linux.20pre2-ac1/mm/Makefile --- linux.20pre2/mm/Makefile 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/Makefile 2002-08-12 17:01:07.000000000 +0100 @@ -9,12 +9,12 @@ O_TARGET := mm.o -export-objs := shmem.o filemap.o memory.o page_alloc.o +export-objs := shmem.o filemap.o memory.o page_alloc.o mempool.o obj-y := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \ page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \ - shmem.o + shmem.o rmap.o mempool.o obj-$(CONFIG_HIGHMEM) += highmem.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/memory.c linux.20pre2-ac1/mm/memory.c --- linux.20pre2/mm/memory.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/memory.c 2002-08-06 15:41:52.000000000 +0100 @@ -34,6 +34,21 @@ * * 16.07.99 - Support of BIGMEM added by Gerhard Wichert, Siemens AG * (Gerhard.Wichert@pdb.siemens.de) + * 26.02.2002 - Added address space accounting + * + * 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 @@ -44,9 +59,11 @@ #include #include #include +#include #include #include +#include #include #include @@ -103,6 +120,7 @@ } pte = pte_offset(dir, 0); pmd_clear(dir); + pgtable_remove_rmap(pte); pte_free(pte); } @@ -240,9 +258,11 @@ if (pte_none(pte)) goto cont_copy_pte_range_noset; + /* pte contains position in swap, so copy. */ if (!pte_present(pte)) { swap_duplicate(pte_to_swp_entry(pte)); - goto cont_copy_pte_range; + set_pte(dst_pte, pte); + goto cont_copy_pte_range_noset; } ptepage = pte_page(pte); if ((!VALID_PAGE(ptepage)) || @@ -250,7 +270,7 @@ goto cont_copy_pte_range; /* If it's a COW mapping, write protect it both in the parent and the child */ - if (cow && pte_write(pte)) { + if (cow) { ptep_set_wrprotect(src_pte); pte = *src_pte; } @@ -263,6 +283,7 @@ dst->rss++; cont_copy_pte_range: set_pte(dst_pte, pte); + page_add_rmap(ptepage, dst_pte); cont_copy_pte_range_noset: address += PAGE_SIZE; if (address >= end) goto out_unlock; @@ -318,8 +339,10 @@ continue; if (pte_present(pte)) { struct page *page = pte_page(pte); - if (VALID_PAGE(page) && !PageReserved(page)) + if (VALID_PAGE(page) && !PageReserved(page)) { freed ++; + page_remove_rmap(page, ptep); + } /* This will eventually call __free_pte on the pte. */ tlb_remove_page(tlb, ptep, address + offset); } else { @@ -984,7 +1007,9 @@ if (pte_same(*page_table, pte)) { if (PageReserved(old_page)) ++mm->rss; + page_remove_rmap(old_page, page_table); break_cow(vma, new_page, address, page_table); + page_add_rmap(new_page, page_table); lru_cache_add(new_page); /* Free the old page.. */ @@ -1097,6 +1122,10 @@ struct page *new_page; unsigned long offset; + /* Low on free memory ? Don't make things worse. */ + if (free_low(ALL_ZONES) < 0) + return; + /* * Get the number of handles we should do readahead io to. */ @@ -1176,6 +1205,7 @@ flush_page_to_ram(page); flush_icache_page(vma, page); set_pte(page_table, pte); + page_add_rmap(page, page_table); /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, address, pte); @@ -1191,14 +1221,13 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr) { pte_t entry; + struct page * page = ZERO_PAGE(addr); /* Read-only mapping of ZERO_PAGE. */ entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot)); /* ..except if it's a write access */ if (write_access) { - struct page *page; - /* Allocate our own private page. */ spin_unlock(&mm->page_table_lock); @@ -1217,10 +1246,10 @@ flush_page_to_ram(page); entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); lru_cache_add(page); - mark_page_accessed(page); } set_pte(page_table, entry); + page_add_rmap(page, page_table); /* ignores ZERO_PAGE */ /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, addr, entry); @@ -1275,6 +1304,8 @@ new_page = page; } + mark_page_accessed(new_page); + spin_lock(&mm->page_table_lock); /* * This silly early PAGE_DIRTY setting removes a race @@ -1295,6 +1326,7 @@ if (write_access) entry = pte_mkwrite(pte_mkdirty(entry)); set_pte(page_table, entry); + page_add_rmap(new_page, page_table); } else { /* One of our sibling threads was faster, back out. */ page_cache_release(new_page); @@ -1371,6 +1403,14 @@ current->state = TASK_RUNNING; pgd = pgd_offset(mm, address); + /* + * If we are over our RSS limit and the system needs memory, + * we will free memory for the non-hogs and slow down a bit. + */ + if (mm->rlimit_rss && mm->rss > mm->rlimit_rss && + free_high(ALL_ZONES) > 0) + rss_free_pages(GFP_HIGHUSER); + /* * We need the page table lock to synchronize with kswapd * and the SMP-safe atomic PTE updates. @@ -1452,6 +1492,7 @@ goto out; } } + pgtable_add_rmap(new, mm, address); pmd_populate(mm, pmd, new); } out: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/mempool.c linux.20pre2-ac1/mm/mempool.c --- linux.20pre2/mm/mempool.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/mm/mempool.c 2002-08-12 17:02:46.000000000 +0100 @@ -0,0 +1,295 @@ +/* + * linux/mm/mempool.c + * + * memory buffer pool support. Such pools are mostly used + * for guaranteed, deadlock-free memory allocations during + * extreme VM load. + * + * started by Ingo Molnar, Copyright (C) 2001 + */ + +#include +#include +#include +#include +#include + +/** + * mempool_create - create a memory pool + * @min_nr: the minimum number of elements guaranteed to be + * allocated for this pool. + * @alloc_fn: user-defined element-allocation function. + * @free_fn: user-defined element-freeing function. + * @pool_data: optional private data available to the user-defined functions. + * + * this function creates and allocates a guaranteed size, preallocated + * memory pool. The pool can be used from the mempool_alloc and mempool_free + * functions. This function might sleep. Both the alloc_fn() and the free_fn() + * functions might sleep - as long as the mempool_alloc function is not called + * from IRQ contexts. The element allocated by alloc_fn() must be able to + * hold a struct list_head. (8 bytes on x86.) + */ +mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn, + mempool_free_t *free_fn, void *pool_data) +{ + mempool_t *pool; + int i; + + pool = kmalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return NULL; + memset(pool, 0, sizeof(*pool)); + + spin_lock_init(&pool->lock); + pool->min_nr = min_nr; + pool->pool_data = pool_data; + INIT_LIST_HEAD(&pool->elements); + init_waitqueue_head(&pool->wait); + pool->alloc = alloc_fn; + pool->free = free_fn; + + /* + * First pre-allocate the guaranteed number of buffers. + */ + for (i = 0; i < min_nr; i++) { + void *element; + struct list_head *tmp; + element = pool->alloc(GFP_KERNEL, pool->pool_data); + + if (unlikely(!element)) { + /* + * Not enough memory - free the allocated ones + * and return: + */ + list_for_each(tmp, &pool->elements) { + element = tmp; + pool->free(element, pool->pool_data); + } + kfree(pool); + + return NULL; + } + tmp = element; + list_add(tmp, &pool->elements); + pool->curr_nr++; + } + return pool; +} + +/** + * mempool_resize - resize an existing memory pool + * @pool: pointer to the memory pool which was allocated via + * mempool_create(). + * @new_min_nr: the new minimum number of elements guaranteed to be + * allocated for this pool. + * @gfp_mask: the usual allocation bitmask. + * + * This function shrinks/grows the pool. In the case of growing, + * it cannot be guaranteed that the pool will be grown to the new + * size immediately, but new mempool_free() calls will refill it. + * + * Note, the caller must guarantee that no mempool_destroy is called + * while this function is running. mempool_alloc() & mempool_free() + * might be called (eg. from IRQ contexts) while this function executes. + */ +void mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask) +{ + int delta; + void *element; + unsigned long flags; + struct list_head *tmp; + + if (new_min_nr <= 0) + BUG(); + + spin_lock_irqsave(&pool->lock, flags); + if (new_min_nr < pool->min_nr) { + pool->min_nr = new_min_nr; + /* + * Free possible excess elements. + */ + while (pool->curr_nr > pool->min_nr) { + tmp = pool->elements.next; + if (tmp == &pool->elements) + BUG(); + list_del(tmp); + element = tmp; + pool->curr_nr--; + spin_unlock_irqrestore(&pool->lock, flags); + + pool->free(element, pool->pool_data); + + spin_lock_irqsave(&pool->lock, flags); + } + spin_unlock_irqrestore(&pool->lock, flags); + return; + } + delta = new_min_nr - pool->min_nr; + pool->min_nr = new_min_nr; + spin_unlock_irqrestore(&pool->lock, flags); + + /* + * We refill the pool up to the new treshold - but we dont + * (cannot) guarantee that the refill succeeds. + */ + while (delta) { + element = pool->alloc(gfp_mask, pool->pool_data); + if (!element) + break; + mempool_free(element, pool); + delta--; + } +} + +/** + * mempool_destroy - deallocate a memory pool + * @pool: pointer to the memory pool which was allocated via + * mempool_create(). + * + * this function only sleeps if the free_fn() function sleeps. The caller + * has to guarantee that no mempool_alloc() nor mempool_free() happens in + * this pool when calling this function. + */ +void mempool_destroy(mempool_t *pool) +{ + void *element; + struct list_head *head, *tmp; + + if (!pool) + return; + + head = &pool->elements; + for (tmp = head->next; tmp != head; ) { + element = tmp; + tmp = tmp->next; + pool->free(element, pool->pool_data); + pool->curr_nr--; + } + if (pool->curr_nr) + BUG(); + kfree(pool); +} + +/** + * mempool_alloc - allocate an element from a specific memory pool + * @pool: pointer to the memory pool which was allocated via + * mempool_create(). + * @gfp_mask: the usual allocation bitmask. + * + * this function only sleeps if the alloc_fn function sleeps or + * returns NULL. Note that due to preallocation, this function + * *never* fails when called from process contexts. (it might + * fail if called from an IRQ context.) + */ +void * mempool_alloc(mempool_t *pool, int gfp_mask) +{ + void *element; + unsigned long flags; + struct list_head *tmp; + int curr_nr; + DECLARE_WAITQUEUE(wait, current); + int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO); + +repeat_alloc: + element = pool->alloc(gfp_nowait, pool->pool_data); + if (likely(element != NULL)) + return element; + + /* + * If the pool is less than 50% full then try harder + * to allocate an element: + */ + if ((gfp_mask != gfp_nowait) && (pool->curr_nr <= pool->min_nr/2)) { + element = pool->alloc(gfp_mask, pool->pool_data); + if (likely(element != NULL)) + return element; + } + + /* + * Kick the VM at this point. + */ + wakeup_bdflush(); + + spin_lock_irqsave(&pool->lock, flags); + if (likely(pool->curr_nr)) { + tmp = pool->elements.next; + list_del(tmp); + element = tmp; + pool->curr_nr--; + spin_unlock_irqrestore(&pool->lock, flags); + return element; + } + spin_unlock_irqrestore(&pool->lock, flags); + + /* We must not sleep in the GFP_ATOMIC case */ + if (gfp_mask == gfp_nowait) + return NULL; + + run_task_queue(&tq_disk); + + add_wait_queue_exclusive(&pool->wait, &wait); + set_task_state(current, TASK_UNINTERRUPTIBLE); + + spin_lock_irqsave(&pool->lock, flags); + curr_nr = pool->curr_nr; + spin_unlock_irqrestore(&pool->lock, flags); + + if (!curr_nr) + schedule(); + + current->state = TASK_RUNNING; + remove_wait_queue(&pool->wait, &wait); + + goto repeat_alloc; +} + +/** + * mempool_free - return an element to the pool. + * @element: pool element pointer. + * @pool: pointer to the memory pool which was allocated via + * mempool_create(). + * + * this function only sleeps if the free_fn() function sleeps. + */ +void mempool_free(void *element, mempool_t *pool) +{ + unsigned long flags; + + if (pool->curr_nr < pool->min_nr) { + spin_lock_irqsave(&pool->lock, flags); + if (pool->curr_nr < pool->min_nr) { + list_add(element, &pool->elements); + pool->curr_nr++; + spin_unlock_irqrestore(&pool->lock, flags); + wake_up(&pool->wait); + return; + } + spin_unlock_irqrestore(&pool->lock, flags); + } + pool->free(element, pool->pool_data); +} + +/* + * A commonly used alloc and free fn. + */ +void *mempool_alloc_slab(int gfp_mask, void *pool_data) +{ + kmem_cache_t *mem = (kmem_cache_t *) pool_data; + return kmem_cache_alloc(mem, gfp_mask); +} + +void mempool_free_slab(void *element, void *pool_data) +{ + kmem_cache_t *mem = (kmem_cache_t *) pool_data; + kmem_cache_free(mem, element); +} + + +EXPORT_SYMBOL(mempool_create); +EXPORT_SYMBOL(mempool_resize); +EXPORT_SYMBOL(mempool_destroy); +EXPORT_SYMBOL(mempool_alloc); +EXPORT_SYMBOL(mempool_free); +EXPORT_SYMBOL(mempool_alloc_slab); +EXPORT_SYMBOL(mempool_free_slab); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/mlock.c linux.20pre2-ac1/mm/mlock.c --- linux.20pre2/mm/mlock.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/mlock.c 2002-08-06 15:41:52.000000000 +0100 @@ -198,6 +198,7 @@ unsigned long lock_limit; int error = -ENOMEM; + vm_validate_enough("entering sys_mlock"); down_write(¤t->mm->mmap_sem); len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); start &= PAGE_MASK; @@ -220,6 +221,7 @@ error = do_mlock(start, len, 1); out: up_write(¤t->mm->mmap_sem); + vm_validate_enough("exiting sys_mlock"); return error; } @@ -227,11 +229,13 @@ { int ret; + vm_validate_enough("entering sys_munlock"); down_write(¤t->mm->mmap_sem); len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); start &= PAGE_MASK; ret = do_mlock(start, len, 0); up_write(¤t->mm->mmap_sem); + vm_validate_enough("exiting sys_munlock"); return ret; } @@ -268,6 +272,8 @@ unsigned long lock_limit; int ret = -EINVAL; + vm_validate_enough("entering sys_mlockall"); + down_write(¤t->mm->mmap_sem); if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE))) goto out; @@ -287,15 +293,18 @@ ret = do_mlockall(flags); out: up_write(¤t->mm->mmap_sem); + vm_validate_enough("exiting sys_mlockall"); return ret; } asmlinkage long sys_munlockall(void) { int ret; + vm_validate_enough("entering sys_munlockall"); down_write(¤t->mm->mmap_sem); ret = do_mlockall(0); up_write(¤t->mm->mmap_sem); + vm_validate_enough("exiting sys_munlockall"); return ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/mmap.c linux.20pre2-ac1/mm/mmap.c --- linux.20pre2/mm/mmap.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/mmap.c 2002-08-06 15:41:52.000000000 +0100 @@ -1,8 +1,25 @@ /* * linux/mm/mmap.c - * * Written by obz. + * + * Address space accounting code + * (c) Copyright 2002 Red Hat Inc, All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include #include #include @@ -46,6 +63,7 @@ int sysctl_overcommit_memory; int max_map_count = DEFAULT_MAX_MAP_COUNT; +atomic_t vm_committed_space = ATOMIC_INIT(0); /* Check that a process has enough memory to allocate a * new virtual mapping. @@ -55,42 +73,109 @@ /* Stupid algorithm to decide if we have enough memory: while * simple, it hopefully works in most obvious cases.. Easy to * fool it, but this should catch most mistakes. - */ - /* 23/11/98 NJC: Somewhat less stupid version of algorithm, + * + * 23/11/98 NJC: Somewhat less stupid version of algorithm, * which tries to do "TheRightThing". Instead of using half of * (buffers+cache), use the minimum values. Allow an extra 2% * of num_physpages for safety margin. + * + * 2002/02/26 Alan Cox: Added two new modes that do real accounting */ + unsigned long free, allowed; + struct sysinfo i; - unsigned long free; + atomic_add(pages, &vm_committed_space); /* Sometimes we want to use more memory than we have. */ - if (sysctl_overcommit_memory) - return 1; + if (sysctl_overcommit_memory == 1) + return 1; + + if (sysctl_overcommit_memory == 0) + { + /* The page cache contains buffer pages these days.. */ + free = atomic_read(&page_cache_size); + free += nr_free_pages(); + free += nr_swap_pages; + + /* + * This double-counts: the nrpages are both in the page-cache + * and in the swapper space. At the same time, this compensates + * for the swap-space over-allocation (ie "nr_swap_pages" being + * too small. + */ + free += swapper_space.nrpages; + + /* + * The code below doesn't account for free space in the inode + * and dentry slab cache, slab cache fragmentation, inodes and + * dentries which will become freeable under VM load, etc. + * Lets just hope all these (complex) factors balance out... + */ + free += (dentry_stat.nr_unused * sizeof(struct dentry)) >> PAGE_SHIFT; + free += (inodes_stat.nr_unused * sizeof(struct inode)) >> PAGE_SHIFT; + + if(free > pages) + return 1; + atomic_sub(pages, &vm_committed_space); + return 0; + } + allowed = total_swap_pages; + + if(sysctl_overcommit_memory == 2) + { + /* FIXME - need to add arch hooks to get the bits we need + without the higher overhead crap */ + si_meminfo(&i); + allowed += i.totalram >> 1; + } + if(atomic_read(&vm_committed_space) < allowed) + return 1; + atomic_sub(pages, &vm_committed_space); + return 0; + +} - /* The page cache contains buffer pages these days.. */ - free = atomic_read(&page_cache_size); - free += nr_free_pages(); - free += nr_swap_pages; +void vm_unacct_memory(long pages) +{ + atomic_sub(pages, &vm_committed_space); +} - /* - * This double-counts: the nrpages are both in the page-cache - * and in the swapper space. At the same time, this compensates - * for the swap-space over-allocation (ie "nr_swap_pages" being - * too small. - */ - free += swapper_space.nrpages; +/* + * Don't even bother telling me the locking is wrong - its a test + * routine and uniprocessor is quite sufficient.. + * + * To enable this debugging you must tweak the #if below, and build + * with no SYS5 shared memory (thats not validated yet) and non SMP + */ - /* - * The code below doesn't account for free space in the inode - * and dentry slab cache, slab cache fragmentation, inodes and - * dentries which will become freeable under VM load, etc. - * Lets just hope all these (complex) factors balance out... - */ - free += (dentry_stat.nr_unused * sizeof(struct dentry)) >> PAGE_SHIFT; - free += (inodes_stat.nr_unused * sizeof(struct inode)) >> PAGE_SHIFT; +void vm_validate_enough(char *x) +{ +#if 0 + unsigned long count = 0UL; + struct mm_struct *mm; + struct vm_area_struct *vma; + struct list_head *mmp; + unsigned long flags; + + spin_lock_irqsave(&mmlist_lock, flags); - return free > pages; + list_for_each(mmp, &init_mm.mmlist) + { + mm = list_entry(mmp, struct mm_struct, mmlist); + for(vma = mm->mmap; vma!=NULL; vma=vma->vm_next) + { + if(vma->vm_flags & VM_ACCOUNT) + count += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + } + } + if(count != atomic_read(&vm_committed_space)) + { + printk("MM crappo accounting %s: %lu %ld.\n", + x, count, atomic_read(&vm_committed_space)); + atomic_set(&vm_committed_space, count); + } + spin_unlock_irqrestore(&mmlist_lock, flags); +#endif } /* Remove one vm structure from the inode's i_mapping address space. */ @@ -161,12 +246,13 @@ /* Always allow shrinking brk. */ if (brk <= mm->brk) { - if (!do_munmap(mm, newbrk, oldbrk-newbrk)) + if (!do_munmap(mm, newbrk, oldbrk-newbrk, 1)) goto set_brk; goto out; } /* Check against rlimit.. */ + /* FIXME: - this seems to be checked in do_brk.. */ rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim) goto out; @@ -175,10 +261,6 @@ if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) goto out; - /* Check if we have enough memory.. */ - if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) - goto out; - /* Ok, looks good - let it rip. */ if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) goto out; @@ -390,6 +472,12 @@ return 0; } + +/* + * NOTE: in this function we rely on TASK_SIZE being lower than + * SIZE_MAX-PAGE_SIZE at least. I'm pretty sure that it is. + */ + unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long pgoff) { @@ -399,16 +487,20 @@ int correct_wcount = 0; int error; rb_node_t ** rb_link, * rb_parent; + unsigned long charged = 0; + vm_validate_enough("entering do_mmap_pgoff"); if (file && (!file->f_op || !file->f_op->mmap)) return -ENODEV; - if ((len = PAGE_ALIGN(len)) == 0) + if (!len) return addr; if (len > TASK_SIZE) return -EINVAL; + len = PAGE_ALIGN(len); /* This cannot be zero now */ + /* offset overflow? */ if ((pgoff + (len >> PAGE_SHIFT)) < pgoff) return -EINVAL; @@ -482,7 +574,7 @@ munmap_back: vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); if (vma && vma->vm_start < addr + len) { - if (do_munmap(mm, addr, len)) + if (do_munmap(mm, addr, len, 1)) return -ENOMEM; goto munmap_back; } @@ -492,11 +584,20 @@ > current->rlim[RLIMIT_AS].rlim_cur) return -ENOMEM; + /* FIXME - this ought to be a nice inline ! */ + if(sysctl_overcommit_memory > 1) + flags &= ~MAP_NORESERVE; + /* Private writable mapping? Check memory availability.. */ - if ((vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE && - !(flags & MAP_NORESERVE) && - !vm_enough_memory(len >> PAGE_SHIFT)) - return -ENOMEM; + + if ((((vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) || (file == NULL)) + && !(flags & MAP_NORESERVE)) + { + charged = len >> PAGE_SHIFT; + if(!vm_enough_memory(charged)) + return -ENOMEM; + vm_flags |= VM_ACCOUNT; + } /* Can we just expand an old anonymous mapping? */ if (!file && !(vm_flags & VM_SHARED) && rb_parent) @@ -508,8 +609,9 @@ * not unmapped, but the maps are removed from the list. */ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + error = -ENOMEM; if (!vma) - return -ENOMEM; + goto unacct_error; vma->vm_mm = mm; vma->vm_start = addr; @@ -561,8 +663,7 @@ * to update the tree pointers. */ addr = vma->vm_start; - stale_vma = find_vma_prepare(mm, addr, &prev, - &rb_link, &rb_parent); + stale_vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); /* * Make sure the lowlevel driver did its job right. */ @@ -583,6 +684,7 @@ mm->locked_vm += len >> PAGE_SHIFT; make_pages_present(addr, addr + len); } + vm_validate_enough("out from do_mmap_pgoff"); return addr; unmap_and_free_vma: @@ -595,6 +697,10 @@ zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start); free_vma: kmem_cache_free(vm_area_cachep, vma); +unacct_error: + if(charged) + vm_unacct_memory(charged); + vm_validate_enough("error path from do_mmap_pgoff"); return error; } @@ -737,6 +843,96 @@ return NULL; } +/* vma is the first one with address < vma->vm_end, + * and even address < vma->vm_start. Have to extend vma. */ + +#ifdef ARCH_STACK_GROWSUP +static inline int expand_stack(struct vm_area_struct * vma, unsigned long address) +{ + unsigned long grow; + + if (!(vma->vm_flags & VM_GROWSUP)) + return -EFAULT; + + vm_validate_enough("entering expand_stack"); + + /* + * vma->vm_start/vm_end cannot change under us because the caller is required + * to hold the mmap_sem in write mode. We need to get the spinlock only + * before relocating the vma range ourself. + */ + spin_lock(&vma->vm_mm->page_table_lock); + + address += 4 + PAGE_SIZE - 1; + address &= PAGE_MASK; + grow = (address - vma->vm_end) >> PAGE_SHIFT; + + /* Overcommit.. */ + if(!vm_enough_memory(grow)) { + spin_unlock(&vma->vm_mm->page_table_lock); + return -ENOMEM; + } + + if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur || + ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) + { + spin_unlock(&vma->vm_mm->page_table_lock); + vm_unacct_memory(grow); + vm_validate_enough("exiting expand_stack - FAIL"); + return -ENOMEM; + } + vma->vm_end = address; + vma->vm_mm->total_vm += grow; + if (vma->vm_flags & VM_LOCKED) + vma->vm_mm->locked_vm += grow; + vm_validate_enough("exiting expand_stack"); + return 0; +} +#else + +int expand_stack(struct vm_area_struct * vma, unsigned long address) +{ + unsigned long grow; + + if (!(vma->vm_flags & VM_GROWSDOWN)) + return -EFAULT; + + vm_validate_enough("entering expand_stack"); + + /* + * vma->vm_start/vm_end cannot change under us because the caller is required + * to hold the mmap_sem in write mode. We need to get the spinlock only + * before relocating the vma range ourself. + */ + address &= PAGE_MASK; + spin_lock(&vma->vm_mm->page_table_lock); + grow = (vma->vm_start - address) >> PAGE_SHIFT; + + /* Overcommit.. */ + if(!vm_enough_memory(grow)) { + spin_unlock(&vma->vm_mm->page_table_lock); + return -ENOMEM; + } + + if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || + ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) { + spin_unlock(&vma->vm_mm->page_table_lock); + vm_unacct_memory(grow); + vm_validate_enough("exiting expand_stack - FAIL"); + return -ENOMEM; + } + vma->vm_start = address; + vma->vm_pgoff -= grow; + vma->vm_mm->total_vm += grow; + if (vma->vm_flags & VM_LOCKED) + vma->vm_mm->locked_vm += grow; + spin_unlock(&vma->vm_mm->page_table_lock); + vm_validate_enough("exiting expand_stack"); + return 0; +} + +#endif + struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr) { struct vm_area_struct * vma; @@ -784,7 +980,7 @@ */ static struct vm_area_struct * unmap_fixup(struct mm_struct *mm, struct vm_area_struct *area, unsigned long addr, size_t len, - struct vm_area_struct *extra) + struct vm_area_struct *extra, int acct) { struct vm_area_struct *mpnt; unsigned long end = addr + len; @@ -792,6 +988,8 @@ area->vm_mm->total_vm -= len >> PAGE_SHIFT; if (area->vm_flags & VM_LOCKED) area->vm_mm->locked_vm -= len >> PAGE_SHIFT; + if (acct && (area->vm_flags & VM_ACCOUNT)) + vm_unacct_memory(len >> PAGE_SHIFT); /* Unmapping the whole area. */ if (addr == area->vm_start && end == area->vm_end) { @@ -802,7 +1000,7 @@ kmem_cache_free(vm_area_cachep, area); return extra; } - + /* Work out to one of the ends. */ if (end == area->vm_end) { /* @@ -916,10 +1114,12 @@ * work. This now handles partial unmappings. * Jeremy Fitzhardine */ -int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) +int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len, int acct) { struct vm_area_struct *mpnt, *prev, **npp, *free, *extra; + if(acct) vm_validate_enough("entering do_munmap"); + if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr) return -EINVAL; @@ -986,6 +1186,7 @@ (file = mpnt->vm_file) != NULL) { atomic_dec(&file->f_dentry->d_inode->i_writecount); } + remove_shared_vm_struct(mpnt); mm->map_count--; @@ -994,7 +1195,7 @@ /* * Fix the mapping, and free the old area if it wasn't reused. */ - extra = unmap_fixup(mm, mpnt, st, size, extra); + extra = unmap_fixup(mm, mpnt, st, size, extra, acct); if (file) atomic_inc(&file->f_dentry->d_inode->i_writecount); } @@ -1005,6 +1206,7 @@ kmem_cache_free(vm_area_cachep, extra); free_pgtables(mm, prev, addr, addr+len); + if(acct) vm_validate_enough("exit -ok- do_munmap"); return 0; } @@ -1015,7 +1217,7 @@ struct mm_struct *mm = current->mm; down_write(&mm->mmap_sem); - ret = do_munmap(mm, addr, len); + ret = do_munmap(mm, addr, len, 1); up_write(&mm->mmap_sem); return ret; } @@ -1032,6 +1234,9 @@ unsigned long flags; rb_node_t ** rb_link, * rb_parent; + vm_validate_enough("entering do_brk"); + + len = PAGE_ALIGN(len); if (!len) return addr; @@ -1052,7 +1257,7 @@ munmap_back: vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); if (vma && vma->vm_start < addr + len) { - if (do_munmap(mm, addr, len)) + if (do_munmap(mm, addr, len, 1)) return -ENOMEM; goto munmap_back; } @@ -1068,7 +1273,7 @@ if (!vm_enough_memory(len >> PAGE_SHIFT)) return -ENOMEM; - flags = VM_DATA_DEFAULT_FLAGS | mm->def_flags; + flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; /* Can we just expand an old anonymous mapping? */ if (rb_parent && vma_merge(mm, prev, rb_parent, addr, addr + len, flags)) @@ -1079,8 +1284,11 @@ */ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!vma) + { + /* We accounted this address space - undo it */ + vm_unacct_memory(len >> PAGE_SHIFT); return -ENOMEM; - + } vma->vm_mm = mm; vma->vm_start = addr; vma->vm_end = addr + len; @@ -1099,6 +1307,9 @@ mm->locked_vm += len >> PAGE_SHIFT; make_pages_present(addr, addr + len); } + + vm_validate_enough("exiting do_brk"); + return addr; } @@ -1140,6 +1351,10 @@ unsigned long end = mpnt->vm_end; unsigned long size = end - start; + /* If the VMA has been charged for, account for its removal */ + if (mpnt->vm_flags & VM_ACCOUNT) + vm_unacct_memory(size >> PAGE_SHIFT); + if (mpnt->vm_ops) { if (mpnt->vm_ops->close) mpnt->vm_ops->close(mpnt); @@ -1159,6 +1374,9 @@ BUG(); clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD); + + vm_validate_enough("exiting exit_mmap"); + } /* Insert vm structure into process list sorted by address diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/mprotect.c linux.20pre2-ac1/mm/mprotect.c --- linux.20pre2/mm/mprotect.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/mprotect.c 2002-08-06 15:41:52.000000000 +0100 @@ -2,6 +2,23 @@ * linux/mm/mprotect.c * * (C) Copyright 1994 Linus Torvalds + * + * Address space accounting code + * (c) Copyright 2002 Red Hat Inc, All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include @@ -241,11 +258,32 @@ { pgprot_t newprot; int error; + unsigned long charged = 0; if (newflags == vma->vm_flags) { *pprev = vma; return 0; } + +#ifdef COMPLETE_BOLLOCKS + /* + * If we take an anonymous mapped vma writable we + * increase our commit (was one page per file now one page + * per writable private instance) + * FIXME: shared private mapping R/O versus R/W accounting + */ + if(vma->vm_file != NULL && + ((vma->vm_flags & (VM_ACCOUNT|VM_SHARED)) == (VM_ACCOUNT|VM_SHARED)) && + ((newflags & PROT_WRITE) != (vma->vm_flags & PROT_WRITE))) + { + charged = (end - start) >> PAGE_SHIFT; + if(newflags & PROT_WRITE) + { + if(!vm_enough_memory(charged)) + return -ENOMEM; + } + } +#endif newprot = protection_map[newflags & 0xf]; if (start == vma->vm_start) { if (end == vma->vm_end) @@ -258,8 +296,15 @@ error = mprotect_fixup_middle(vma, pprev, start, end, newflags, newprot); if (error) + { + if(newflags & PROT_WRITE) + vm_unacct_memory(charged); return error; - + } + /* Delayed accounting for reduction of memory use - done last to + avoid allocation races */ + if (charged && !(newflags & PROT_WRITE)) + vm_unacct_memory(charged); change_protection(start, end, newprot); return 0; } @@ -270,6 +315,8 @@ struct vm_area_struct * vma, * next, * prev; int error = -EINVAL; + vm_validate_enough("entering mprotect"); + if (start & ~PAGE_MASK) return -EINVAL; len = PAGE_ALIGN(len); @@ -333,5 +380,6 @@ } out: up_write(¤t->mm->mmap_sem); + vm_validate_enough("exiting mprotect"); return error; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/mremap.c linux.20pre2-ac1/mm/mremap.c --- linux.20pre2/mm/mremap.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/mremap.c 2002-08-06 15:41:52.000000000 +0100 @@ -2,6 +2,23 @@ * linux/mm/remap.c * * (C) Copyright 1996 Linus Torvalds + * + * Address space accounting code + * (c) Copyright 2002 Red Hat Inc, All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include @@ -13,8 +30,6 @@ #include #include -extern int vm_enough_memory(long pages); - static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr) { pgd_t * pgd; @@ -61,8 +76,14 @@ { int error = 0; pte_t pte; + struct page * page = NULL; + + if (pte_present(*src)) + page = pte_page(*src); if (!pte_none(*src)) { + if (page) + page_remove_rmap(page, src); pte = ptep_get_and_clear(src); if (!dst) { /* No dest? We must put it back. */ @@ -70,6 +91,8 @@ error++; } set_pte(dst, pte); + if (page) + page_add_rmap(page, dst); } return error; } @@ -130,6 +153,7 @@ struct vm_area_struct * new_vma, * next, * prev; int allocated_vma; + new_vma = NULL; next = find_vma_prev(mm, new_addr, &prev); if (next) { @@ -189,7 +213,8 @@ new_vma->vm_ops->open(new_vma); insert_vm_struct(current->mm, new_vma); } - do_munmap(current->mm, addr, old_len); + /* The old VMA has been accounted for, don't double account */ + do_munmap(current->mm, addr, old_len, 0); current->mm->total_vm += new_len >> PAGE_SHIFT; if (new_vma->vm_flags & VM_LOCKED) { current->mm->locked_vm += new_len >> PAGE_SHIFT; @@ -215,8 +240,11 @@ unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) { + extern int sysctl_overcommit_memory; /* FIXME!! */ + struct vm_area_struct *vma; unsigned long ret = -EINVAL; + unsigned long charged = 0; if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE)) goto out; @@ -246,16 +274,17 @@ if ((addr <= new_addr) && (addr+old_len) > new_addr) goto out; - do_munmap(current->mm, new_addr, new_len); + do_munmap(current->mm, new_addr, new_len, 1); } /* * Always allow a shrinking remap: that just unmaps * the unnecessary pages.. + * do_munmap does all the needed commit accounting */ ret = addr; if (old_len >= new_len) { - do_munmap(current->mm, addr+new_len, old_len - new_len); + do_munmap(current->mm, addr+new_len, old_len - new_len, 1); if (!(flags & MREMAP_FIXED) || (new_addr == addr)) goto out; } @@ -285,12 +314,17 @@ if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) > current->rlim[RLIMIT_AS].rlim_cur) goto out; - /* Private writable mapping? Check memory availability.. */ - if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE && - !(flags & MAP_NORESERVE) && - !vm_enough_memory((new_len - old_len) >> PAGE_SHIFT)) - goto out; + /* FIXME - this ought to be a nice inline ! */ + if(sysctl_overcommit_memory > 1) + flags &= ~MAP_NORESERVE; + + if(vma->vm_flags&VM_ACCOUNT) + { + charged = (new_len - old_len) >> PAGE_SHIFT; + if(!vm_enough_memory(charged)) + goto out_nc; + } /* old_len exactly to the end of the area.. * And we're not relocating the area. */ @@ -313,6 +347,7 @@ addr + new_len); } ret = addr; + vm_validate_enough("mremap path1"); goto out; } } @@ -336,6 +371,12 @@ ret = move_vma(vma, addr, old_len, new_len, new_addr); } out: + if(ret & ~PAGE_MASK) + { + vm_unacct_memory(charged); + vm_validate_enough("mremap error path"); + } +out_nc: return ret; } @@ -345,8 +386,10 @@ { unsigned long ret; + vm_validate_enough("entry to mremap"); down_write(¤t->mm->mmap_sem); ret = do_mremap(addr, old_len, new_len, flags, new_addr); up_write(¤t->mm->mmap_sem); + vm_validate_enough("exit from mremap"); return ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/oom_kill.c linux.20pre2-ac1/mm/oom_kill.c --- linux.20pre2/mm/oom_kill.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/oom_kill.c 2002-08-06 15:41:52.000000000 +0100 @@ -82,7 +82,7 @@ * Niced processes are most likely less important, so double * their badness points. */ - if (p->nice > 0) + if (task_nice(p) > 0) points *= 2; /* @@ -146,7 +146,7 @@ * all the memory it needs. That way it should be able to * exit() and clear out its resources quickly... */ - p->counter = 5 * HZ; + p->time_slice = HZ; p->flags |= PF_MEMALLOC | PF_MEMDIE; /* This process has hardware access, be more careful. */ @@ -168,6 +168,7 @@ static void oom_kill(void) { struct task_struct *p, *q; + extern wait_queue_head_t kswapd_done; read_lock(&tasklist_lock); p = select_bad_process(); @@ -183,13 +184,15 @@ } read_unlock(&tasklist_lock); + /* Chances are by this time our victim is sleeping on kswapd. */ + wake_up(&kswapd_done); + /* * Make kswapd go out of the way, so "p" has a good chance of * killing itself before someone else gets the chance to ask * for more memory. */ - current->policy |= SCHED_YIELD; - schedule(); + yield(); return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/page_alloc.c linux.20pre2-ac1/mm/page_alloc.c --- linux.20pre2/mm/page_alloc.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/mm/page_alloc.c 2002-08-06 18:20:29.000000000 +0100 @@ -21,17 +21,18 @@ #include #include #include +#include int nr_swap_pages; int nr_active_pages; -int nr_inactive_pages; -LIST_HEAD(inactive_list); -LIST_HEAD(active_list); +int nr_inactive_dirty_pages; +int nr_inactive_clean_pages; pg_data_t *pgdat_list; /* - * Used by page_zone() to look up the address of the struct zone whose - * id is encoded in the upper bits of page->flags + * The zone_table array is used to look up the address of the + * struct zone corresponding to a given zone number (ZONE_DMA, + * ZONE_NORMAL, or ZONE_HIGHMEM). */ zone_t *zone_table[MAX_NR_ZONES*MAX_NR_NODES]; EXPORT_SYMBOL(zone_table); @@ -40,21 +41,25 @@ static int zone_balance_ratio[MAX_NR_ZONES] __initdata = { 128, 128, 128, }; static int zone_balance_min[MAX_NR_ZONES] __initdata = { 20 , 20, 20, }; static int zone_balance_max[MAX_NR_ZONES] __initdata = { 255 , 255, 255, }; +static int zone_extrafree_ratio[MAX_NR_ZONES] __initdata = { 128, 512, 0, }; +static int zone_extrafree_max[MAX_NR_ZONES] __initdata = { 1024 , 1024, 0, }; /* * Temporary debugging check. */ #define BAD_RANGE(zone, page) \ ( \ - (((page) - mem_map) >= ((zone)->zone_start_mapnr+(zone)->size)) \ + (((page) - mem_map) >= ((zone)->zone_start_mapnr+(zone)->size)) \ || (((page) - mem_map) < (zone)->zone_start_mapnr) \ || ((zone) != page_zone(page)) \ ) /* * Freeing function for a buddy system allocator. + * Contrary to prior comments, this is *NOT* hairy, and there + * is no reason for anyone not to understand it. * - * The concept of a buddy system is to maintain direct-mapped table + * The concept of a buddy system is to maintain direct-mapped tables * (containing bit values) for memory blocks of various "orders". * The bottom level table contains the map for the smallest allocatable * units of memory (here, pages), and each level above it describes @@ -82,32 +87,37 @@ struct page *base; zone_t *zone; - /* - * Yes, think what happens when other parts of the kernel take + /* Yes, think what happens when other parts of the kernel take * a reference to a page in order to pin it for io. -ben */ - if (PageLRU(page)) { - if (unlikely(in_interrupt())) - BUG(); + if (PageLRU(page)) lru_cache_del(page); - } if (page->buffers) BUG(); - if (page->mapping) + if (page->mapping) { + printk(KERN_CRIT "Page has mapping still set. This is a serious situation. However if you \n"); + printk(KERN_CRIT "are using the NVidia binary only module please report this bug to \n"); + printk(KERN_CRIT "NVidia and not to the linux kernel mailinglist.\n"); BUG(); + } if (!VALID_PAGE(page)) BUG(); + if (PageSwapCache(page)) + BUG(); if (PageLocked(page)) BUG(); if (PageActive(page)) BUG(); + if (PageInactiveDirty(page)) + BUG(); + if (PageInactiveClean(page)) + BUG(); + if (page->pte_chain) + BUG(); page->flags &= ~((1<flags & PF_FREE_PAGES) - goto local_freelist; - back_local_freelist: - + page->age = PAGE_AGE_START; + zone = page_zone(page); mask = (~0UL) << order; @@ -136,7 +146,7 @@ /* * Move the buddy up one level. * This code is taking advantage of the identity: - * -mask = 1+~mask + * -mask = 1+~mask */ buddy1 = base + (page_idx ^ -mask); buddy2 = base + page_idx; @@ -154,17 +164,6 @@ list_add(&(base + page_idx)->list, &area->free_list); spin_unlock_irqrestore(&zone->lock, flags); - return; - - local_freelist: - if (current->nr_local_pages) - goto back_local_freelist; - if (in_interrupt()) - goto back_local_freelist; - - list_add(&page->list, ¤t->local_pages); - page->index = order; - current->nr_local_pages++; } #define MARK_USED(index, order, area) \ @@ -223,10 +222,7 @@ set_page_count(page, 1); if (BAD_RANGE(zone,page)) BUG(); - if (PageLRU(page)) - BUG(); - if (PageActive(page)) - BUG(); + DEBUG_LRU_PAGE(page); return page; } curr_order++; @@ -245,76 +241,83 @@ } #endif -static struct page * FASTCALL(balance_classzone(zone_t *, unsigned int, unsigned int, int *)); -static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask, unsigned int order, int * freed) +/* + * If we are able to directly reclaim pages, we move pages from the + * inactive_clean list onto the free list until the zone has enough + * free pages or until the inactive_clean pages are exhausted. + * If we cannot do this work ourselves, call kswapd. + */ +void FASTCALL(fixup_freespace(zone_t * zone, int direct_reclaim)); +void fixup_freespace(zone_t * zone, int direct_reclaim) +{ + if (direct_reclaim) { + struct page * page; + do { + if ((page = reclaim_page(zone))) + __free_pages_ok(page, 0); + } while (page && zone->free_pages <= zone->pages_min); + } else + wakeup_kswapd(GFP_ATOMIC); +} + +#define PAGES_KERNEL 0 +#define PAGES_MIN 1 +#define PAGES_LOW 2 +#define PAGES_HIGH 3 + +/* + * This function does the dirty work for __alloc_pages + * and is separated out to keep the code size smaller. + * (suggested by Davem at 1:30 AM, typed by Rik at 6 AM) + */ +static struct page * __alloc_pages_limit(zonelist_t *zonelist, + unsigned long order, int limit, int direct_reclaim) { - struct page * page = NULL; - int __freed = 0; + zone_t **zone = zonelist->zones; + unsigned long water_mark = 0; + + for (;;) { + zone_t *z = *(zone++); - if (!(gfp_mask & __GFP_WAIT)) - goto out; - if (in_interrupt()) - BUG(); - - current->allocation_order = order; - current->flags |= PF_MEMALLOC | PF_FREE_PAGES; - - __freed = try_to_free_pages(classzone, gfp_mask, order); - - current->flags &= ~(PF_MEMALLOC | PF_FREE_PAGES); - - if (current->nr_local_pages) { - struct list_head * entry, * local_pages; - struct page * tmp; - int nr_pages; - - local_pages = ¤t->local_pages; - - if (likely(__freed)) { - /* pick from the last inserted so we're lifo */ - entry = local_pages->next; - do { - tmp = list_entry(entry, struct page, list); - if (tmp->index == order && memclass(page_zone(tmp), classzone)) { - list_del(entry); - current->nr_local_pages--; - set_page_count(tmp, 1); - page = tmp; - - if (page->buffers) - BUG(); - if (page->mapping) - BUG(); - if (!VALID_PAGE(page)) - BUG(); - if (PageLocked(page)) - BUG(); - if (PageLRU(page)) - BUG(); - if (PageActive(page)) - BUG(); - if (PageDirty(page)) - BUG(); + if (!z) + break; + if (!z->size) + BUG(); - break; - } - } while ((entry = entry->next) != local_pages); + /* + * We allocate if the number of (free + inactive_clean) + * pages is above the watermark. + */ + switch (limit) { + case PAGES_KERNEL: + water_mark = z->pages_min / 2; + break; + case PAGES_MIN: + water_mark = z->pages_min; + break; + case PAGES_LOW: + water_mark = z->pages_low; + break; + default: + case PAGES_HIGH: + water_mark = z->pages_high; } - nr_pages = current->nr_local_pages; - /* free in reverse order so that the global order will be lifo */ - while ((entry = local_pages->prev) != local_pages) { - list_del(entry); - tmp = list_entry(entry, struct page, list); - __free_pages_ok(tmp, tmp->index); - if (!nr_pages--) - BUG(); + if (z->free_pages + z->inactive_clean_pages >= water_mark) { + struct page *page = NULL; + /* If possible, reclaim a page directly. */ + if (direct_reclaim) + page = reclaim_page(z); + /* If that fails, fall back to rmqueue. */ + if (!page) + page = rmqueue(z, order); + if (page) + return page; } - current->nr_local_pages = 0; } - out: - *freed = __freed; - return page; + + /* Found nothing. */ + return NULL; } /* @@ -322,102 +325,247 @@ */ struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist) { - unsigned long min; - zone_t **zone, * classzone; + zone_t **zone; + int min, direct_reclaim = 0; struct page * page; - int freed; + /* + * (If anyone calls gfp from interrupts nonatomically then it + * will sooner or later tripped up by a schedule().) + * + * We fall back to lower-level zones if allocation + * in a higher zone fails. + */ + + /* + * Can we take pages directly from the inactive_clean + * list? + */ + if (order == 0 && (gfp_mask & __GFP_WAIT)) + direct_reclaim = 1; + +try_again: + /* + * First, see if we have any zones with lots of free memory. + * + * We allocate free memory first because it doesn't contain + * any data we would want to cache. + */ zone = zonelist->zones; - classzone = *zone; - if (classzone == NULL) - return NULL; min = 1UL << order; for (;;) { zone_t *z = *(zone++); if (!z) break; + if (!z->size) + BUG(); - min += z->pages_low; + min += z->pages_min; if (z->free_pages > min) { page = rmqueue(z, order); if (page) return page; - } + } else if (z->free_pages < z->pages_min) + fixup_freespace(z, direct_reclaim); + } + + /* + * Next, try to allocate a page from a zone with a HIGH + * amount of (free + inactive_clean) pages. + * + * If there is a lot of activity, inactive_target + * will be high and we'll have a good chance of + * finding a page using the HIGH limit. + */ + page = __alloc_pages_limit(zonelist, order, PAGES_HIGH, direct_reclaim); + if (page) + return page; + + /* + * Then try to allocate a page from a zone with more + * than zone->pages_low of (free + inactive_clean) pages. + * + * When the working set is very large and VM activity + * is low, we're most likely to have our allocation + * succeed here. + */ + page = __alloc_pages_limit(zonelist, order, PAGES_LOW, direct_reclaim); + if (page) + return page; + + /* + * OK, none of the zones on our zonelist has lots + * of pages free. + * + * We wake up kswapd, in the hope that kswapd will + * resolve this situation before memory gets tight. + * + * We'll also help a bit trying to free pages, this + * way statistics will make sure really fast allocators + * are slowed down more than slow allocators and other + * programs in the system shouldn't be impacted as much + * by the hogs. + */ + wakeup_kswapd(gfp_mask); + + /* + * After waking up kswapd, we try to allocate a page + * from any zone which isn't critical yet. + * + * Kswapd should, in most situations, bring the situation + * back to normal in no time. + */ + page = __alloc_pages_limit(zonelist, order, PAGES_MIN, direct_reclaim); + if (page) + return page; + + /* + * Kernel allocations can eat a few emergency pages. + * We should be able to run without this, find out why + * the SCSI layer isn't happy ... + */ + if (gfp_mask & __GFP_HIGH) { + page = __alloc_pages_limit(zonelist, order, PAGES_KERNEL, direct_reclaim); + if (page) + return page; } - classzone->need_balance = 1; - mb(); - if (waitqueue_active(&kswapd_wait)) - wake_up_interruptible(&kswapd_wait); + /* + * Oh well, we didn't succeed. + */ + if (!(current->flags & PF_MEMALLOC)) { + /* + * Are we dealing with a higher order allocation? + * + * If so, try to defragment some memory. + */ + if (order > 0 && (gfp_mask & __GFP_WAIT)) + goto defragment; + /* + * If we arrive here, we are really tight on memory. + * Since kswapd didn't succeed in freeing pages for us, + * we need to help it. + * + * Single page allocs loop until the allocation succeeds. + * Multi-page allocs can fail due to memory fragmentation; + * in that case we bail out to prevent infinite loops and + * hanging device drivers ... + * + * Another issue are GFP_NOFS allocations; because they + * do not have __GFP_FS set it's possible we cannot make + * any progress freeing pages, in that case it's better + * to give up than to deadlock the kernel looping here. + * + * NFS: we must yield the CPU (to rpciod) to avoid deadlock. + */ + if (gfp_mask & __GFP_WAIT) { + __set_current_state(TASK_RUNNING); + yield(); + if (!order || free_high(ALL_ZONES) >= 0) { + int progress = try_to_free_pages(gfp_mask); + if (progress || (gfp_mask & __GFP_FS)) + goto try_again; + /* + * Fail if no progress was made and the + * allocation may not be able to block on IO. + */ + return NULL; + } + } + } + + /* + * Final phase: allocate anything we can! + * + * Higher order allocations, GFP_ATOMIC allocations and + * recursive allocations (PF_MEMALLOC) end up here. + * + * Only recursive allocations can use the very last pages + * in the system, otherwise it would be just too easy to + * deadlock the system... + */ zone = zonelist->zones; min = 1UL << order; for (;;) { - unsigned long local_min; zone_t *z = *(zone++); + struct page * page = NULL; if (!z) break; - local_min = z->pages_min; - if (!(gfp_mask & __GFP_WAIT)) - local_min >>= 2; - min += local_min; - if (z->free_pages > min) { + /* + * SUBTLE: direct_reclaim is only possible if the task + * becomes PF_MEMALLOC while looping above. This will + * happen when the OOM killer selects this task for + * death. + */ + if (direct_reclaim) { + page = reclaim_page(z); + if (page) + return page; + } + + /* XXX: is pages_min/4 a good amount to reserve for this? */ + min += z->pages_min / 4; + if (z->free_pages > min || ((current->flags & PF_MEMALLOC) && !in_interrupt())) { page = rmqueue(z, order); if (page) return page; } } + goto out_failed; - /* here we're in the low on memory slow path */ -rebalance: - if (current->flags & (PF_MEMALLOC | PF_MEMDIE)) { + /* + * Naive "defragmentation" for higher-order allocations. First we + * free the inactive_clean pages to see if we can allocate our + * allocation, then we call page_launder() to clean some dirty + * pages, and last we try once more. + * + * We might want to turn this into something which defragments + * memory based on physical page, simply by looking for unmapped + * pages next to pages on the free list... + */ +defragment: + { + int freed = 0; +defragment_again: zone = zonelist->zones; for (;;) { zone_t *z = *(zone++); if (!z) break; - - page = rmqueue(z, order); - if (page) - return page; + if (!z->size) + continue; + while (z->inactive_clean_pages) { + struct page * page; + /* Move one page to the free list. */ + page = reclaim_page(z); + if (!page) + break; + __free_page(page); + /* Try if the allocation succeeds. */ + page = rmqueue(z, order); + if (page) + return page; + } } - return NULL; - } - - /* Atomic allocations - we can't balance anything */ - if (!(gfp_mask & __GFP_WAIT)) - return NULL; - page = balance_classzone(classzone, gfp_mask, order, &freed); - if (page) - return page; - - zone = zonelist->zones; - min = 1UL << order; - for (;;) { - zone_t *z = *(zone++); - if (!z) - break; - - min += z->pages_min; - if (z->free_pages > min) { - page = rmqueue(z, order); - if (page) - return page; + /* XXX: do real defragmentation instead of calling launder ? */ + if (!freed & !(current->flags & PF_MEMALLOC)) { + freed = 1; + current->flags |= PF_MEMALLOC; + try_to_free_pages(gfp_mask); + current->flags &= ~PF_MEMALLOC; + goto defragment_again; } } - /* Don't let big-order allocations loop */ - if (order > 3) - return NULL; - - /* Yield for kswapd, and try again */ - current->policy |= SCHED_YIELD; - __set_current_state(TASK_RUNNING); - schedule(); - goto rebalance; + +out_failed: + /* No luck.. */ +// printk(KERN_ERR "__alloc_pages: %lu-order allocation failed.\n", order); + return NULL; } /* @@ -463,12 +611,13 @@ */ unsigned int nr_free_pages (void) { - unsigned int sum = 0; + unsigned int sum; zone_t *zone; + sum = 0; for_each_zone(zone) sum += zone->free_pages; - + return sum; } @@ -486,11 +635,11 @@ zone_t *zone; for (zone = *zonep++; zone; zone = *zonep++) { - unsigned long size = zone->size; - unsigned long high = zone->pages_high; - if (size > high) - sum += size - high; + sum += zone->free_pages; + sum += zone->inactive_clean_pages; + sum += zone->inactive_dirty_pages; } + } return sum; @@ -509,25 +658,6 @@ } #endif -int try_to_free_pages_nozone(unsigned int gfp_mask) -{ - pg_data_t *pgdat; - zonelist_t *zonelist; - unsigned long pf_free_pages; - int error = 0; - - pf_free_pages = current->flags & PF_FREE_PAGES; - current->flags &= ~PF_FREE_PAGES; - - for_each_pgdat(pgdat) { - zonelist = pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK); - error |= try_to_free_pages(zonelist->zones[0], gfp_mask, 0); - } - - current->flags |= pf_free_pages; - return error; -} - #define K(x) ((x) << (PAGE_SHIFT-10)) /* @@ -560,10 +690,15 @@ tmpdat = tmpdat->node_next; } - printk("( Active: %d, inactive: %d, free: %d )\n", - nr_active_pages, - nr_inactive_pages, - nr_free_pages()); + printk("Free pages: %6dkB (%6dkB HighMem)\n", + nr_free_pages() << (PAGE_SHIFT-10), + nr_free_highpages() << (PAGE_SHIFT-10)); + + printk("( Active: %d, inactive_dirty: %d, inactive_clean: %d, free: %d )\n", + nr_active_pages, + nr_inactive_dirty_pages, + nr_inactive_clean_pages, + nr_free_pages()); for (type = 0; type < MAX_NR_ZONES; type++) { struct list_head *head, *curr; @@ -698,6 +833,7 @@ * - mark all memory queues empty * - clear the memory bitmaps */ +extern unsigned int kswapd_minfree; void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap, unsigned long *zones_size, unsigned long zone_start_paddr, unsigned long *zholes_size, struct page *lmem_map) @@ -744,7 +880,7 @@ offset = lmem_map - mem_map; for (j = 0; j < MAX_NR_ZONES; j++) { zone_t *zone = pgdat->node_zones + j; - unsigned long mask; + unsigned long mask, extrafree = 0; unsigned long size, realsize; zone_table[nid * MAX_NR_ZONES + j] = zone; @@ -758,13 +894,25 @@ zone->lock = SPIN_LOCK_UNLOCKED; zone->zone_pgdat = pgdat; zone->free_pages = 0; + zone->inactive_clean_pages = 0; + zone->inactive_dirty_pages = 0; zone->need_balance = 0; + zone->pte_chain_freelist = NULL; + INIT_LIST_HEAD(&zone->active_list); + INIT_LIST_HEAD(&zone->inactive_dirty_list); + INIT_LIST_HEAD(&zone->inactive_clean_list); + spin_lock_init(&zone->pte_chain_freelist_lock); + if (!size) continue; /* - * The per-page waitqueue mechanism uses hashed waitqueues - * per zone. + * The per-page waitqueue mechanism requires hash tables + * whose buckets are waitqueues. These hash tables are + * per-zone, and dynamically sized according to the size + * of the zone so as to maintain a good ratio of waiters + * to hash table buckets. Right here we just allocate + * and initialize them for later use (in filemap.c) */ zone->wait_table_size = wait_table_size(size); zone->wait_table_shift = @@ -778,15 +926,22 @@ pgdat->nr_zones = j+1; + /* + * On large memory machines we keep extra memory + * free for kernel allocations. + */ + if (zone_extrafree_ratio[j]) + extrafree = min_t(int, (realtotalpages / zone_extrafree_ratio[j]), zone_extrafree_max[j]); + if (extrafree < zone_balance_max[j]) + extrafree = 0; + mask = (realsize / zone_balance_ratio[j]); if (mask < zone_balance_min[j]) mask = zone_balance_min[j]; - else if (mask > zone_balance_max[j]) - mask = zone_balance_max[j]; - zone->pages_min = mask; - zone->pages_low = mask*2; - zone->pages_high = mask*3; - + zone->pages_min = extrafree + min(mask, (unsigned long)zone_balance_max[j]); + zone->pages_low = extrafree + mask*2; + zone->pages_high = extrafree + mask*3; + zone->pages_plenty = extrafree + mask*6; zone->zone_mem_map = mem_map + offset; zone->zone_start_mapnr = offset; zone->zone_start_paddr = zone_start_paddr; @@ -794,6 +949,8 @@ if ((zone_start_paddr >> PAGE_SHIFT) & (zone_required_alignment-1)) printk("BUG: wrong zone alignment, it will crash\n"); + kswapd_minfree += zone->pages_min; + /* * Initially all pages are reserved - free ones are freed * up by free_all_bootmem() once the early boot process is diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/page_io.c linux.20pre2-ac1/mm/page_io.c --- linux.20pre2/mm/page_io.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/mm/page_io.c 2002-08-13 14:57:05.000000000 +0100 @@ -72,6 +72,11 @@ /* block_size == PAGE_SIZE/zones_used */ brw_page(rw, page, dev, zones, block_size); + + /* Note! For consistency we do all of the logic, + * decrementing the page count, and unlocking the page in the + * swap lock map - in the IO completion handler. + */ return 1; } @@ -82,6 +87,7 @@ * - it's marked as being swap-cache * - it's associated with the swap inode */ + void rw_swap_page(int rw, struct page *page) { swp_entry_t entry; @@ -92,6 +98,8 @@ PAGE_BUG(page); if (!PageSwapCache(page)) PAGE_BUG(page); + if (page->mapping != &swapper_space) + PAGE_BUG(page); if (!rw_swap_page_base(rw, entry, page)) UnlockPage(page); } @@ -107,6 +115,8 @@ if (!PageLocked(page)) PAGE_BUG(page); + if (PageSwapCache(page)) + PAGE_BUG(page); if (page->mapping) PAGE_BUG(page); /* needs sync_page to wait I/O completation */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/rmap.c linux.20pre2-ac1/mm/rmap.c --- linux.20pre2/mm/rmap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/mm/rmap.c 2002-08-06 15:41:52.000000000 +0100 @@ -0,0 +1,433 @@ +/* + * mm/rmap.c - physical to virtual reverse mappings + * + * Copyright 2001, Rik van Riel + * Released under the General Public License (GPL). + * + * + * Simple, low overhead pte-based reverse mapping scheme. + * This is kept modular because we may want to experiment + * with object-based reverse mapping schemes. Please try + * to keep this thing as modular as possible. + */ + +/* + * Locking: + * - the page->pte_chain is protected by the PG_chainlock bit, + * which nests within the pagemap_lru_lock, then the + * mm->page_table_lock, and then the page lock. + * - because swapout locking is opposite to the locking order + * in the page fault path, the swapout path uses trylocks + * on the mm->page_table_lock + */ +#include +#include +#include + +#include +#include +#include + +/* #define DEBUG_RMAP */ + +/* + * Shared pages have a chain of pte_chain structures, used to locate + * all the mappings to this page. We only need a pointer to the pte + * here, the page struct for the page table page contains the process + * it belongs to and the offset within that process. + * + * A singly linked list should be fine for most, if not all, workloads. + * On fork-after-exec the mapping we'll be removing will still be near + * the start of the list, on mixed application systems the short-lived + * processes will have their mappings near the start of the list and + * in systems with long-lived applications the relative overhead of + * exit() will be lower since the applications are long-lived. + */ +struct pte_chain { + struct pte_chain * next; + pte_t * ptep; +}; + +static inline struct pte_chain * pte_chain_alloc(zone_t *); +static inline void pte_chain_free(struct pte_chain *, struct pte_chain *, + struct page *, zone_t *); +static void alloc_new_pte_chains(zone_t *); + +/** + * page_referenced - test if the page was referenced + * @page: the page to test + * + * Quick test_and_clear_referenced for all mappings to a page, + * returns the number of processes which referenced the page. + * Caller needs to hold the pte_chain_lock. + */ +int page_referenced(struct page * page) +{ + struct pte_chain * pc; + int referenced = 0; + + if (PageTestandClearReferenced(page)) + referenced++; + + /* Check all the page tables mapping this page. */ + for (pc = page->pte_chain; pc; pc = pc->next) { + if (ptep_test_and_clear_young(pc->ptep)) + referenced++; + } + + return referenced; +} + +/** + * page_add_rmap - add reverse mapping entry to a page + * @page: the page to add the mapping to + * @ptep: the page table entry mapping this page + * + * Add a new pte reverse mapping to a page. + * The caller needs to hold the mm->page_table_lock. + */ +void page_add_rmap(struct page * page, pte_t * ptep) +{ + struct pte_chain * pte_chain; + +#ifdef DEBUG_RMAP + if (!page || !ptep) + BUG(); + if (!pte_present(*ptep)) + BUG(); + if (!ptep_to_mm(ptep)); + BUG(); +#endif + + if (!VALID_PAGE(page) || PageReserved(page)) + return; + +#ifdef DEBUG_RMAP + pte_chain_lock(page); + { + struct pte_chain * pc; + for (pc = page->pte_chain; pc; pc = pc->next) { + if (pc->ptep == ptep) + BUG(); + } + } + pte_chain_unlock(page); +#endif + + pte_chain = pte_chain_alloc(page_zone(page)); + + pte_chain_lock(page); + + /* Hook up the pte_chain to the page. */ + pte_chain->ptep = ptep; + pte_chain->next = page->pte_chain; + page->pte_chain = pte_chain; + + pte_chain_unlock(page); +} + +/** + * page_remove_rmap - take down reverse mapping to a page + * @page: page to remove mapping from + * @ptep: page table entry to remove + * + * Removes the reverse mapping from the pte_chain of the page, + * after that the caller can clear the page table entry and free + * the page. + * Caller needs to hold the mm->page_table_lock. + */ +void page_remove_rmap(struct page * page, pte_t * ptep) +{ + struct pte_chain * pc, * prev_pc = NULL; + zone_t *zone; + + if (!page || !ptep) + BUG(); + if (!VALID_PAGE(page) || PageReserved(page)) + return; + + zone = page_zone(page); + + pte_chain_lock(page); + for (pc = page->pte_chain; pc; prev_pc = pc, pc = pc->next) { + if (pc->ptep == ptep) { + pte_chain_free(pc, prev_pc, page, zone); + goto out; + } + } +#ifdef DEBUG_RMAP + /* Not found. This should NEVER happen! */ + printk(KERN_ERR "page_remove_rmap: pte_chain %p not present.\n", ptep); + printk(KERN_ERR "page_remove_rmap: only found: "); + for (pc = page->pte_chain; pc; pc = pc->next) + printk("%p ", pc->ptep); + printk("\n"); + printk(KERN_ERR "page_remove_rmap: driver cleared PG_reserved ?\n"); +#endif + +out: + pte_chain_unlock(page); + return; + +} + +/** + * try_to_unmap_one - worker function for try_to_unmap + * @page: page to unmap + * @ptep: page table entry to unmap from page + * + * Internal helper function for try_to_unmap, called for each page + * table entry mapping a page. Because locking order here is opposite + * to the locking order used by the page fault path, we use trylocks. + * Locking: + * pagemap_lru_lock page_launder() + * page lock page_launder(), trylock + * pte_chain_lock page_launder() + * mm->page_table_lock try_to_unmap_one(), trylock + */ +static int FASTCALL(try_to_unmap_one(struct page *, pte_t *)); +static int try_to_unmap_one(struct page * page, pte_t * ptep) +{ + unsigned long address = ptep_to_address(ptep); + struct mm_struct * mm = ptep_to_mm(ptep); + struct vm_area_struct * vma; + pte_t pte; + int ret; + + if (!mm) + BUG(); + + /* + * We need the page_table_lock to protect us from page faults, + * munmap, fork, etc... + */ + if (!spin_trylock(&mm->page_table_lock)) + return SWAP_AGAIN; + + /* During mremap, it's possible pages are not in a VMA. */ + vma = find_vma(mm, address); + if (!vma) { + ret = SWAP_FAIL; + goto out_unlock; + } + + /* The page is mlock()d, we cannot swap it out. */ + if (vma->vm_flags & VM_LOCKED) { + ret = SWAP_FAIL; + goto out_unlock; + } + + /* Nuke the page table entry. */ + pte = ptep_get_and_clear(ptep); + flush_tlb_page(vma, address); + flush_cache_page(vma, address); + + /* Store the swap location in the pte. See handle_pte_fault() ... */ + if (PageSwapCache(page)) { + swp_entry_t entry; + entry.val = page->index; + swap_duplicate(entry); + set_pte(ptep, swp_entry_to_pte(entry)); + } + + /* Move the dirty bit to the physical page now the pte is gone. */ + if (pte_dirty(pte)) + set_page_dirty(page); + + mm->rss--; + page_cache_release(page); + ret = SWAP_SUCCESS; + +out_unlock: + spin_unlock(&mm->page_table_lock); + return ret; +} + +/** + * try_to_unmap - try to remove all page table mappings to a page + * @page: the page to get unmapped + * + * Tries to remove all the page table entries which are mapping this + * page, used in the pageout path. Caller must hold pagemap_lru_lock + * and the page lock. Return values are: + * + * SWAP_SUCCESS - we succeeded in removing all mappings + * SWAP_AGAIN - we missed a trylock, try again later + * SWAP_FAIL - the page is unswappable + * SWAP_ERROR - an error occurred + */ +int try_to_unmap(struct page * page) +{ + struct pte_chain * pc, * next_pc, * prev_pc = NULL; + zone_t *zone = page_zone(page); + int ret = SWAP_SUCCESS; + + /* This page should not be on the pageout lists. */ + if (!VALID_PAGE(page) || PageReserved(page)) + BUG(); + if (!PageLocked(page)) + BUG(); + /* We need backing store to swap out a page. */ + if (!page->mapping) + BUG(); + + for (pc = page->pte_chain; pc; pc = next_pc) { + next_pc = pc->next; + switch (try_to_unmap_one(page, pc->ptep)) { + case SWAP_SUCCESS: + /* Free the pte_chain struct. */ + pte_chain_free(pc, prev_pc, page, zone); + break; + case SWAP_AGAIN: + /* Skip this pte, remembering status. */ + prev_pc = pc; + ret = SWAP_AGAIN; + continue; + case SWAP_FAIL: + return SWAP_FAIL; + case SWAP_ERROR: + return SWAP_ERROR; + } + } + + return ret; +} + +/** + * page_over_rsslimit - test if the page is over its RSS limit + * @page - page to test + * + * This function returns true if the process owning this page + * is over its RSS (resident set size) limit. For shared pages + * we penalise it only if all processes using it are over their + * rss limits. + * The caller needs to hold the page's pte_chain_lock. + */ +int page_over_rsslimit(struct page * page) +{ + struct pte_chain * pte_chain = page->pte_chain; + struct mm_struct * mm; + pte_t * ptep; + + /* No process is using the page. */ + if (!pte_chain) + return 0; + + do { + ptep = pte_chain->ptep; + mm = ptep_to_mm(ptep); + + /* + * If the process is under its RSS limit, stop + * scanning and don't penalise the page. + */ + if(!mm->rlimit_rss || mm->rss <= mm->rlimit_rss) + return 0; + + pte_chain = pte_chain->next; + } while (pte_chain); + + return 1; +} + +/** + ** No more VM stuff below this comment, only pte_chain helper + ** functions. + **/ + +static inline void pte_chain_push(zone_t * zone, + struct pte_chain * pte_chain) +{ + pte_chain->ptep = NULL; + pte_chain->next = zone->pte_chain_freelist; + zone->pte_chain_freelist = pte_chain; +} + +static inline struct pte_chain * pte_chain_pop(zone_t * zone) +{ + struct pte_chain *pte_chain; + + pte_chain = zone->pte_chain_freelist; + zone->pte_chain_freelist = pte_chain->next; + pte_chain->next = NULL; + + return pte_chain; +} + +/** + * pte_chain_free - free pte_chain structure + * @pte_chain: pte_chain struct to free + * @prev_pte_chain: previous pte_chain on the list (may be NULL) + * @page: page this pte_chain hangs off (may be NULL) + * @zone: memory zone to free pte chain in + * + * This function unlinks pte_chain from the singly linked list it + * may be on and adds the pte_chain to the free list. May also be + * called for new pte_chain structures which aren't on any list yet. + * Caller needs to hold the pte_chain_lock if the page is non-NULL. + */ +static inline void pte_chain_free(struct pte_chain * pte_chain, + struct pte_chain * prev_pte_chain, struct page * page, + zone_t * zone) +{ + if (prev_pte_chain) + prev_pte_chain->next = pte_chain->next; + else if (page) + page->pte_chain = pte_chain->next; + + spin_lock(&zone->pte_chain_freelist_lock); + pte_chain_push(zone, pte_chain); + spin_unlock(&zone->pte_chain_freelist_lock); +} + +/** + * pte_chain_alloc - allocate a pte_chain struct + * @zone: memory zone to allocate pte_chain for + * + * Returns a pointer to a fresh pte_chain structure. Allocates new + * pte_chain structures as required. + * Caller needs to hold the page's pte_chain_lock. + */ +static inline struct pte_chain * pte_chain_alloc(zone_t * zone) +{ + struct pte_chain * pte_chain; + + spin_lock(&zone->pte_chain_freelist_lock); + + /* Allocate new pte_chain structs as needed. */ + if (!zone->pte_chain_freelist) + alloc_new_pte_chains(zone); + + /* Grab the first pte_chain from the freelist. */ + pte_chain = pte_chain_pop(zone); + + spin_unlock(&zone->pte_chain_freelist_lock); + + return pte_chain; +} + +/** + * alloc_new_pte_chains - convert a free page to pte_chain structures + * @zone: memory zone to allocate pte_chains for + * + * Grabs a free page and converts it to pte_chain structures. We really + * should pre-allocate these earlier in the pagefault path or come up + * with some other trick. + * + * Note that we cannot use the slab cache because the pte_chain structure + * is way smaller than the minimum size of a slab cache allocation. + * Caller needs to hold the zone->pte_chain_freelist_lock + */ +static void alloc_new_pte_chains(zone_t *zone) +{ + struct pte_chain * pte_chain = (void *) get_zeroed_page(GFP_ATOMIC); + int i = PAGE_SIZE / sizeof(struct pte_chain); + + if (pte_chain) { + for (; i-- > 0; pte_chain++) + pte_chain_push(zone, pte_chain); + } else { + /* Yeah yeah, I'll fix the pte_chain allocation ... */ + panic("Fix pte_chain allocation!\n"); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/shmem.c linux.20pre2-ac1/mm/shmem.c --- linux.20pre2/mm/shmem.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/shmem.c 2002-08-06 15:41:52.000000000 +0100 @@ -5,8 +5,25 @@ * 2000 Transmeta Corp. * 2000-2001 Christoph Rohland * 2000-2001 SAP AG + * 2002 Red Hat Inc. + * TODO: + * Accounting needs verification + * We need to verify all the security fixes from generic_file_write are + * now there * - * This file is released under the GPL. + * 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 */ /* @@ -21,6 +38,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,6 +53,11 @@ #define TMPFS_MAGIC 0x01021994 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long)) +#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512) + +#define SHMEM_MAX_INDEX (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE * (ENTRIES_PER_PAGE/2) * (ENTRIES_PER_PAGE+1)) +#define SHMEM_MAX_BYTES ((unsigned long long)SHMEM_MAX_INDEX << PAGE_CACHE_SHIFT) +#define VM_ACCT(size) (((size) + PAGE_CACHE_SIZE - 1) >> PAGE_SHIFT) #define SHMEM_SB(sb) (&sb->u.shmem_sb) @@ -46,45 +70,25 @@ LIST_HEAD (shmem_inodes); static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED; -atomic_t shmem_nrpages = ATOMIC_INIT(0); /* Not used right now */ +atomic_t shmem_nrpages = ATOMIC_INIT(0); static struct page *shmem_getpage_locked(struct shmem_inode_info *, struct inode *, unsigned long); -#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512) - -/* - * shmem_recalc_inode - recalculate the size of an inode - * - * @inode: inode to recalc - * @swap: additional swap pages freed externally - * - * We have to calculate the free blocks since the mm can drop pages - * behind our back - * - * But we know that normally - * inodes->i_blocks/BLOCKS_PER_PAGE == - * inode->i_mapping->nrpages + info->swapped - * - * So the mm freed - * inodes->i_blocks/BLOCKS_PER_PAGE - - * (inode->i_mapping->nrpages + info->swapped) - * - * It has to be called with the spinlock held. - */ - -static void shmem_recalc_inode(struct inode * inode) +static void shmem_removepage(struct page *page) { - unsigned long freed; + struct inode * inode; + struct shmem_sb_info * sbinfo; - freed = (inode->i_blocks/BLOCKS_PER_PAGE) - - (inode->i_mapping->nrpages + SHMEM_I(inode)->swapped); - if (freed){ - struct shmem_sb_info * sbinfo = SHMEM_SB(inode->i_sb); - inode->i_blocks -= freed*BLOCKS_PER_PAGE; - spin_lock (&sbinfo->stat_lock); - sbinfo->free_blocks += freed; - spin_unlock (&sbinfo->stat_lock); - } + atomic_dec(&shmem_nrpages); + if (PageLaunder(page)) + return; + + inode = page->mapping->host; + sbinfo = SHMEM_SB(inode->i_sb); + inode->i_blocks -= BLOCKS_PER_PAGE; + spin_lock (&sbinfo->stat_lock); + sbinfo->free_blocks++; + spin_unlock (&sbinfo->stat_lock); } /* @@ -127,9 +131,6 @@ * +-> 48-51 * +-> 52-55 */ - -#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE * ENTRIES_PER_PAGE/2*(ENTRIES_PER_PAGE+1)) - static swp_entry_t * shmem_swp_entry (struct shmem_inode_info *info, unsigned long index, unsigned long page) { unsigned long offset; @@ -182,7 +183,7 @@ unsigned long page = 0; swp_entry_t * res; - if (index >= SHMEM_MAX_BLOCKS) + if (index >= SHMEM_MAX_INDEX) return ERR_PTR(-EFBIG); if (info->next_index <= index) @@ -317,6 +318,7 @@ unsigned long partial; unsigned long freed = 0; struct shmem_inode_info * info = SHMEM_I(inode); + struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); down(&info->sem); inode->i_ctime = inode->i_mtime = CURRENT_TIME; @@ -349,20 +351,51 @@ freed += shmem_truncate_indirect(info, index); info->swapped -= freed; - shmem_recalc_inode(inode); + inode->i_blocks -= freed*BLOCKS_PER_PAGE; spin_unlock (&info->lock); + spin_lock (&sbinfo->stat_lock); + sbinfo->free_blocks += freed; + spin_unlock (&sbinfo->stat_lock); up(&info->sem); } +static int shmem_notify_change(struct dentry * dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + long change = 0; + int error; + + if ((attr->ia_valid & ATTR_SIZE) && (attr->ia_size <= SHMEM_MAX_BYTES)) { + /* + * Account swap file usage based on new file size, + * but just let vmtruncate fail on out-of-range sizes. + */ + change = VM_ACCT(attr->ia_size) - VM_ACCT(inode->i_size); + if (change > 0) { + if (!vm_enough_memory(change)) + return -ENOMEM; + } else + vm_unacct_memory(-change); + + } + error = inode_change_ok(inode, attr); + if (!error) + error = inode_setattr(inode, attr); + if (error && change) + vm_unacct_memory(change); + return error; +} + static void shmem_delete_inode(struct inode * inode) { struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - inode->i_size = 0; - if (inode->i_op->truncate == shmem_truncate){ + if (inode->i_op->truncate == shmem_truncate) { spin_lock (&shmem_ilock); list_del (&SHMEM_I(inode)->list); spin_unlock (&shmem_ilock); + vm_unacct_memory(VM_ACCT(inode->i_size)); + inode->i_size = 0; shmem_truncate (inode); } spin_lock (&sbinfo->stat_lock); @@ -416,6 +449,7 @@ swap_free(entry); ptr[offset] = (swp_entry_t) {0}; delete_from_swap_cache(page); + atomic_inc(&shmem_nrpages); add_to_page_cache(page, info->inode->i_mapping, offset + idx); SetPageDirty(page); SetPageUptodate(page); @@ -481,7 +515,6 @@ entry = shmem_swp_entry(info, index, 0); if (IS_ERR(entry)) /* this had been allocated on page allocation */ BUG(); - shmem_recalc_inode(inode); if (entry->val) BUG(); @@ -495,6 +528,7 @@ * Raced with "speculative" read_swap_cache_async. * Add page back to page cache, unref swap, try again. */ + atomic_inc(&shmem_nrpages); add_to_page_cache_locked(page, mapping, index); spin_unlock(&info->lock); swap_free(swap); @@ -552,7 +586,6 @@ return page; } - shmem_recalc_inode(inode); if (entry->val) { unsigned long flags; @@ -618,6 +651,7 @@ /* We have the page */ SetPageUptodate(page); + atomic_inc(&shmem_nrpages); return page; no_space: spin_unlock (&sbinfo->stat_lock); @@ -775,6 +809,13 @@ static struct inode_operations shmem_symlink_inode_operations; static struct inode_operations shmem_symlink_inline_operations; +/* + * This is a copy of generic_file_write slightly modified. It would + * help no end if it were kept remotely up to date with the + * generic_file_write changes. I don't alas see a good way to merge + * it back and use the generic one -- Alan + */ + static ssize_t shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos) { @@ -786,6 +827,7 @@ unsigned long written; long status; int err; + loff_t maxpos; if ((ssize_t) count < 0) return -EINVAL; @@ -798,12 +840,12 @@ pos = *ppos; err = -EINVAL; if (pos < 0) - goto out; + goto out_nc; err = file->f_error; if (err) { file->f_error = 0; - goto out; + goto out_nc; } written = 0; @@ -811,30 +853,99 @@ if (file->f_flags & O_APPEND) pos = inode->i_size; + maxpos = inode->i_size; + + if (pos + count > inode->i_size) { + maxpos = pos + count; + if (maxpos > SHMEM_MAX_BYTES) + maxpos = SHMEM_MAX_BYTES; + if (!vm_enough_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size))) { + err = -ENOMEM; + goto out_nc; + } + } + /* * Check whether we've reached the file size limit. */ err = -EFBIG; + if (limit != RLIM_INFINITY) { if (pos >= limit) { send_sig(SIGXFSZ, current, 0); goto out; } - if (count > limit - pos) { + if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) { + /* send_sig(SIGXFSZ, current, 0); */ + count = limit - (u32)pos; + } + } + + /* + * LFS rule + */ + if ( pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { + if (pos >= MAX_NON_LFS) { send_sig(SIGXFSZ, current, 0); - count = limit - pos; + goto out; + } + if (count > MAX_NON_LFS - (u32)pos) { + /* send_sig(SIGXFSZ, current, 0); */ + count = MAX_NON_LFS - (u32)pos; } } - status = 0; - if (count) { - remove_suid(inode); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; + /* + * Are we about to exceed the fs block limit ? + * + * If we have written data it becomes a short write + * If we have exceeded without writing data we send + * a signal and give them an EFBIG. + * + * Linus frestrict idea will clean these up nicely.. + */ + + if (!S_ISBLK(inode->i_mode)) { + if (pos >= inode->i_sb->s_maxbytes) + { + if (count || pos > inode->i_sb->s_maxbytes) { + send_sig(SIGXFSZ, current, 0); + err = -EFBIG; + goto out; + } + /* zero-length writes at ->s_maxbytes are OK */ + } + + if (pos + count > inode->i_sb->s_maxbytes) + count = inode->i_sb->s_maxbytes - pos; + } else { + if (is_read_only(inode->i_rdev)) { + err = -EPERM; + goto out; + } + if (pos >= inode->i_size) { + if (count || pos > inode->i_size) { + err = -ENOSPC; + goto out; + } + } + + if (pos + count > inode->i_size) + count = inode->i_size - pos; } + err = 0; + if (count == 0) + goto out; + status = 0; + + remove_suid(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + while (count) { unsigned long bytes, index, offset; char *kaddr; + int deactivate = 1; /* * Try to find the page in the cache. If it isn't there, @@ -845,6 +956,7 @@ bytes = PAGE_CACHE_SIZE - offset; if (bytes > count) { bytes = count; + deactivate = 0; } /* @@ -873,7 +985,7 @@ } kaddr = kmap(page); - status = copy_from_user(kaddr+offset, buf, bytes); + status = __copy_from_user(kaddr+offset, buf, bytes); kunmap(page); if (status) goto fail_write; @@ -891,6 +1003,10 @@ unlock: /* Mark it unlocked again and drop the page.. */ UnlockPage(page); + if (deactivate) + deactivate_page(page); + else + mark_page_accessed(page); page_cache_release(page); if (status < 0) @@ -900,6 +1016,10 @@ err = written ? written : status; out: + /* Short writes give back address space */ + if (inode->i_size != maxpos) + vm_unacct_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size)); +out_nc: up(&inode->i_sem); return err; fail_write: @@ -1145,42 +1265,43 @@ static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char * symname) { - int error; int len; struct inode *inode; struct page *page; char *kaddr; struct shmem_inode_info * info; - error = shmem_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0); - if (error) - return error; - len = strlen(symname) + 1; - inode = dentry->d_inode; + if (len > PAGE_CACHE_SIZE) + return -ENAMETOOLONG; + + inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + if (!inode) + return -ENOSPC; + info = SHMEM_I(inode); inode->i_size = len-1; - inode->i_op = &shmem_symlink_inline_operations; - if (len <= sizeof(struct shmem_inode_info)) { /* do it inline */ memcpy(info, symname, len); + inode->i_op = &shmem_symlink_inline_operations; } else { - if (len > PAGE_CACHE_SIZE) { - error = -ENAMETOOLONG; - goto rmnod; + if (!vm_enough_memory(VM_ACCT(1))) { + iput(inode); + return -ENOMEM; } - inode->i_op = &shmem_symlink_inode_operations; - spin_lock (&shmem_ilock); - list_add_tail(&info->list, &shmem_inodes); - spin_unlock (&shmem_ilock); down(&info->sem); page = shmem_getpage_locked(info, inode, 0); if (IS_ERR(page)) { up(&info->sem); - error = PTR_ERR(page); - goto rmnod; + vm_unacct_memory(VM_ACCT(1)); + iput(inode); + return PTR_ERR(page); } + inode->i_op = &shmem_symlink_inode_operations; + spin_lock (&shmem_ilock); + list_add_tail(&info->list, &shmem_inodes); + spin_unlock (&shmem_ilock); kaddr = kmap(page); memcpy(kaddr, symname, len); kunmap(page); @@ -1190,12 +1311,9 @@ up(&info->sem); } dir->i_ctime = dir->i_mtime = CURRENT_TIME; + d_instantiate(dentry, inode); + dget(dentry); return 0; - -rmnod: - if (!shmem_unlink(dir, dentry)) - d_delete(dentry); - return error; } static int shmem_readlink_inline(struct dentry *dentry, char *buffer, int buflen) @@ -1355,7 +1473,7 @@ sbinfo->free_blocks = blocks; sbinfo->max_inodes = inodes; sbinfo->free_inodes = inodes; - sb->s_maxbytes = (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT; + sb->s_maxbytes = SHMEM_MAX_BYTES; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = TMPFS_MAGIC; @@ -1378,6 +1496,7 @@ static struct address_space_operations shmem_aops = { + removepage: shmem_removepage, writepage: shmem_writepage, }; @@ -1392,6 +1511,7 @@ static struct inode_operations shmem_inode_operations = { truncate: shmem_truncate, + setattr: shmem_notify_change, }; static struct inode_operations shmem_dir_inode_operations = { @@ -1487,21 +1607,21 @@ struct inode * inode; struct dentry *dentry, *root; struct qstr this; - int vm_enough_memory(long pages); - if (size > (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT) + if (size > SHMEM_MAX_BYTES) return ERR_PTR(-EINVAL); - if (!vm_enough_memory((size) >> PAGE_CACHE_SHIFT)) + if (!vm_enough_memory(VM_ACCT(size))) return ERR_PTR(-ENOMEM); + error = -ENOMEM; this.name = name; this.len = strlen(name); this.hash = 0; /* will go */ root = shm_mnt->mnt_root; dentry = d_alloc(root, &this); if (!dentry) - return ERR_PTR(-ENOMEM); + goto put_memory; error = -ENFILE; file = get_empty_filp(); @@ -1527,8 +1647,11 @@ put_filp(file); put_dentry: dput (dentry); +put_memory: + vm_unacct_memory(VM_ACCT(size)); return ERR_PTR(error); } + /* * shmem_zero_setup - setup a shared anonymous mapping * diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/swap.c linux.20pre2-ac1/mm/swap.c --- linux.20pre2/mm/swap.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/swap.c 2002-08-06 15:41:52.000000000 +0100 @@ -15,10 +15,10 @@ #include #include -#include #include #include #include +#include #include #include /* for copy_to/from_user */ @@ -33,15 +33,97 @@ 8, /* do swap I/O in clusters of this size */ }; +/** + * (de)activate_page - move pages from/to active and inactive lists + * @page: the page we want to move + * @nolock - are we already holding the pagemap_lru_lock? + * + * Deactivate_page will move an active page to the right + * inactive list, while activate_page will move a page back + * from one of the inactive lists to the active list. If + * called on a page which is not on any of the lists, the + * page is left alone. + */ +void deactivate_page_nolock(struct page * page) +{ + /* + * Don't touch it if it's not on the active list. + * (some pages aren't on any list at all) + */ + ClearPageReferenced(page); + page->age = 0; + if (PageActive(page)) { + del_page_from_active_list(page); + add_page_to_inactive_dirty_list(page); + } +} + +void deactivate_page(struct page * page) +{ + spin_lock(&pagemap_lru_lock); + deactivate_page_nolock(page); + spin_unlock(&pagemap_lru_lock); +} + +/** + * drop_page - like deactivate_page, but try inactive_clean list + * @page: the page to drop + * + * Try to move a page to the inactive_clean list, this succeeds if the + * page is clean and not in use by anybody. If the page cannot be placed + * on the inactive_clean list it is placed on the inactive_dirty list + * instead. + * + * Note: this function gets called with the pagemap_lru_lock held. + */ +void drop_page(struct page * page) +{ + if (!TryLockPage(page)) { + if (page->mapping && page->buffers) { + page_cache_get(page); + spin_unlock(&pagemap_lru_lock); + try_to_release_page(page, GFP_NOIO); + spin_lock(&pagemap_lru_lock); + page_cache_release(page); + } + UnlockPage(page); + } + + /* Make sure the page really is reclaimable. */ + pte_chain_lock(page); + if (!page->mapping || PageDirty(page) || page->pte_chain || + page->buffers || page_count(page) > 1) + deactivate_page_nolock(page); + + else if (page_count(page) == 1) { + ClearPageReferenced(page); + page->age = 0; + if (PageActive(page)) { + del_page_from_active_list(page); + add_page_to_inactive_clean_list(page); + } else if (PageInactiveDirty(page)) { + del_page_from_inactive_dirty_list(page); + add_page_to_inactive_clean_list(page); + } + } + pte_chain_unlock(page); +} + /* * Move an inactive page to the active list. */ -static inline void activate_page_nolock(struct page * page) +void activate_page_nolock(struct page * page) { - if (PageLRU(page) && !PageActive(page)) { - del_page_from_inactive_list(page); + if (PageInactiveDirty(page)) { + del_page_from_inactive_dirty_list(page); + add_page_to_active_list(page); + } else if (PageInactiveClean(page)) { + del_page_from_inactive_clean_list(page); add_page_to_active_list(page); } + + /* Make sure the page gets a fair chance at staying active. */ + page->age = max((int)page->age, PAGE_AGE_START); } void activate_page(struct page * page) @@ -57,9 +139,10 @@ */ void lru_cache_add(struct page * page) { - if (!TestSetPageLRU(page)) { + if (!PageLRU(page)) { spin_lock(&pagemap_lru_lock); - add_page_to_inactive_list(page); + SetPageLRU(page); + add_page_to_active_list(page); spin_unlock(&pagemap_lru_lock); } } @@ -73,13 +156,14 @@ */ void __lru_cache_del(struct page * page) { - if (TestClearPageLRU(page)) { - if (PageActive(page)) { - del_page_from_active_list(page); - } else { - del_page_from_inactive_list(page); - } + if (PageActive(page)) { + del_page_from_active_list(page); + } else if (PageInactiveDirty(page)) { + del_page_from_inactive_dirty_list(page); + } else if (PageInactiveClean(page)) { + del_page_from_inactive_clean_list(page); } + ClearPageLRU(page); } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/swapfile.c linux.20pre2-ac1/mm/swapfile.c --- linux.20pre2/mm/swapfile.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/swapfile.c 2002-08-06 15:41:52.000000000 +0100 @@ -373,6 +373,7 @@ return; get_page(page); set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot))); + page_add_rmap(page, dir); swap_free(entry); ++vma->vm_mm->rss; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/swap_state.c linux.20pre2-ac1/mm/swap_state.c --- linux.20pre2/mm/swap_state.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/mm/swap_state.c 2002-08-13 15:40:26.000000000 +0100 @@ -89,6 +89,40 @@ return 0; } +/** + * add_to_swap - allocate swap space for a page + * @page: page we want to move to swap + * + * Allocate swap space for the page and add the page to the + * swap cache. Caller needs to hold the page lock. + */ +int add_to_swap(struct page * page) +{ + swp_entry_t entry; + + if (!PageLocked(page)) + BUG(); + + for (;;) { + entry = get_swap_page(); + if (!entry.val) + return 0; + /* + * Add it to the swap cache and mark it dirty + * (adding to the page cache will clear the dirty + * and uptodate bits, so we need to do it again) + */ + if (add_to_swap_cache(page, entry) == 0) { + SetPageUptodate(page); + set_page_dirty(page); + swap_free(entry); + return 1; + } + /* Raced with "speculative" read_swap_cache_async */ + swap_free(entry); + } +} + /* * This must be called only on pages that have * been verified to be in the swap cache. @@ -118,7 +152,7 @@ BUG(); if (unlikely(!block_flushpage(page, 0))) - BUG(); /* an anonymous page cannot have page->buffers set */ + PAGE_BUG(); /* an anonymous page cannot have page->buffers set */ entry.val = page->index; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/vmalloc.c linux.20pre2-ac1/mm/vmalloc.c --- linux.20pre2/mm/vmalloc.c 2002-08-13 13:58:16.000000000 +0100 +++ linux.20pre2-ac1/mm/vmalloc.c 2002-08-12 17:02:04.000000000 +0100 @@ -321,3 +321,22 @@ read_unlock(&vmlist_lock); return buf - buf_start; } + +void *vcalloc(unsigned long nmemb, unsigned long elem_size) +{ + unsigned long size; + void *addr; + + /* + * Check that we're not going to overflow. + */ + if (nmemb > (ULONG_MAX / elem_size)) + return NULL; + + size = nmemb * elem_size; + addr = vmalloc(size); + if (addr) + memset(addr, 0, size); + + return addr; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/mm/vmscan.c linux.20pre2-ac1/mm/vmscan.c --- linux.20pre2/mm/vmscan.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/mm/vmscan.c 2002-08-06 15:41:52.000000000 +0100 @@ -1,6 +1,9 @@ /* * linux/mm/vmscan.c * + * The pageout daemon, decides which pages to evict (swap out) and + * does the actual work of freeing them. + * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds * * Swap reorganised 29.12.95, Stephen Tweedie. @@ -20,9 +23,12 @@ #include #include #include +#include #include +static void refill_freelist(void); +static void wakeup_memwaiters(void); /* * The "priority" of VM scanning is how much of the queues we * will scan in one go. A value of 6 for DEF_PRIORITY implies @@ -31,368 +37,297 @@ */ #define DEF_PRIORITY (6) -/* - * The swap-out function returns 1 if it successfully - * scanned all the pages it was asked to (`count'). - * It returns zero if it couldn't do anything, - * - * rss may decrease because pages are shared, but this - * doesn't count as having freed a page. - */ +static inline void age_page_up(struct page *page) +{ + page->age = min((int) (page->age + PAGE_AGE_ADV), PAGE_AGE_MAX); +} -/* mm->page_table_lock is held. mmap_sem is not held */ -static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page, zone_t * classzone) +static inline void age_page_down(struct page *page) { - pte_t pte; - swp_entry_t entry; + page->age -= min(PAGE_AGE_DECL, (int)page->age); +} - /* Don't look at this pte if it's been accessed recently. */ - if ((vma->vm_flags & VM_LOCKED) || ptep_test_and_clear_young(page_table)) { - mark_page_accessed(page); - return 0; - } +/* Must be called with page's pte_chain_lock held. */ +static inline int page_mapping_inuse(struct page * page) +{ + struct address_space * mapping = page->mapping; - /* Don't bother unmapping pages that are active */ - if (PageActive(page)) - return 0; + /* Page is in somebody's page tables. */ + if (page->pte_chain) + return 1; - /* Don't bother replenishing zones not under pressure.. */ - if (!memclass(page_zone(page), classzone)) + /* XXX: does this happen ? */ + if (!mapping) return 0; - if (TryLockPage(page)) - return 0; + /* File is mmaped by somebody. */ + if (mapping->i_mmap || mapping->i_mmap_shared) + return 1; - /* From this point on, the odds are that we're going to - * nuke this pte, so read and clear the pte. This hook - * is needed on CPUs which update the accessed and dirty - * bits in hardware. - */ - flush_cache_page(vma, address); - pte = ptep_get_and_clear(page_table); - flush_tlb_page(vma, address); + return 0; +} - if (pte_dirty(pte)) - set_page_dirty(page); +/** + * reclaim_page - reclaims one page from the inactive_clean list + * @zone: reclaim a page from this zone + * + * The pages on the inactive_clean can be instantly reclaimed. + * The tests look impressive, but most of the time we'll grab + * the first page of the list and exit successfully. + */ +struct page * reclaim_page(zone_t * zone) +{ + struct page * page = NULL; + struct list_head * page_lru; + swp_entry_t entry = {0}; + int maxscan; /* - * Is the page already in the swap cache? If so, then - * we can just drop our reference to it without doing - * any IO - it's already up-to-date on disk. + * We need to hold the pagecache_lock around all tests to make sure + * reclaim_page() cannot race with find_get_page() and friends. */ - if (PageSwapCache(page)) { - entry.val = page->index; - swap_duplicate(entry); -set_swap_pte: - set_pte(page_table, swp_entry_to_pte(entry)); -drop_pte: - mm->rss--; - UnlockPage(page); - { - int freeable = page_count(page) - !!page->buffers <= 2; - page_cache_release(page); - return freeable; + spin_lock(&pagemap_lru_lock); + spin_lock(&pagecache_lock); + maxscan = zone->inactive_clean_pages; + while (maxscan-- && !list_empty(&zone->inactive_clean_list)) { + page_lru = zone->inactive_clean_list.prev; + page = list_entry(page_lru, struct page, lru); + + /* Wrong page on list?! (list corruption, should not happen) */ + if (unlikely(!PageInactiveClean(page))) { + printk("VM: reclaim_page, wrong page on list.\n"); + list_del(page_lru); + page_zone(page)->inactive_clean_pages--; + continue; } - } - - /* - * Is it a clean page? Then it must be recoverable - * by just paging it in again, and we can just drop - * it.. or if it's dirty but has backing store, - * just mark the page dirty and drop it. - * - * However, this won't actually free any real - * memory, as the page will just be in the page cache - * somewhere, and as such we should just continue - * our scan. - * - * Basically, this just makes it possible for us to do - * some real work in the future in "refill_inactive()". - */ - if (page->mapping) - goto drop_pte; - if (!PageDirty(page)) - goto drop_pte; - /* - * Anonymous buffercache pages can be left behind by - * concurrent truncate and pagefault. - */ - if (page->buffers) - goto preserve; - - /* - * This is a dirty, swappable page. First of all, - * get a suitable swap entry for it, and make sure - * we have the swap cache set up to associate the - * page with that swap entry. - */ - for (;;) { - entry = get_swap_page(); - if (!entry.val) - break; - /* Add it to the swap cache and mark it dirty - * (adding to the page cache will clear the dirty - * and uptodate bits, so we need to do it again) - */ - if (add_to_swap_cache(page, entry) == 0) { - SetPageUptodate(page); - set_page_dirty(page); - goto set_swap_pte; + /* Page is being freed */ + if (unlikely(page_count(page)) == 0) { + list_del(page_lru); + list_add(page_lru, &zone->inactive_clean_list); + continue; } - /* Raced with "speculative" read_swap_cache_async */ - swap_free(entry); - } - - /* No swap space left */ -preserve: - set_pte(page_table, pte); - UnlockPage(page); - return 0; -} -/* mm->page_table_lock is held. mmap_sem is not held */ -static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone) -{ - pte_t * pte; - unsigned long pmd_end; - - if (pmd_none(*dir)) - return count; - if (pmd_bad(*dir)) { - pmd_ERROR(*dir); - pmd_clear(dir); - return count; - } - - pte = pte_offset(dir, address); - - pmd_end = (address + PMD_SIZE) & PMD_MASK; - if (end > pmd_end) - end = pmd_end; + /* Page cannot be reclaimed ? Move to inactive_dirty list. */ + pte_chain_lock(page); + if (unlikely(page->pte_chain || page->buffers || + PageReferenced(page) || PageDirty(page) || + page_count(page) > 1 || TryLockPage(page))) { + del_page_from_inactive_clean_list(page); + add_page_to_inactive_dirty_list(page); + pte_chain_unlock(page); + continue; + } - do { - if (pte_present(*pte)) { - struct page *page = pte_page(*pte); + /* + * From here until reaching either the bottom of the loop + * or found_page: the pte_chain_lock is held. + */ - if (VALID_PAGE(page) && !PageReserved(page)) { - count -= try_to_swap_out(mm, vma, address, pte, page, classzone); - if (!count) { - address += PAGE_SIZE; - break; - } - } + /* OK, remove the page from the caches. */ + if (PageSwapCache(page)) { + entry.val = page->index; + __delete_from_swap_cache(page); + goto found_page; } - address += PAGE_SIZE; - pte++; - } while (address && (address < end)); - mm->swap_address = address; - return count; -} -/* mm->page_table_lock is held. mmap_sem is not held */ -static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone) -{ - pmd_t * pmd; - unsigned long pgd_end; + if (page->mapping) { + __remove_inode_page(page); + goto found_page; + } - if (pgd_none(*dir)) - return count; - if (pgd_bad(*dir)) { - pgd_ERROR(*dir); - pgd_clear(dir); - return count; + /* We should never ever get here. */ + printk(KERN_ERR "VM: reclaim_page, found unknown page\n"); + list_del(page_lru); + zone->inactive_clean_pages--; + pte_chain_unlock(page); + UnlockPage(page); } + spin_unlock(&pagecache_lock); + spin_unlock(&pagemap_lru_lock); + return NULL; - pmd = pmd_offset(dir, address); - - pgd_end = (address + PGDIR_SIZE) & PGDIR_MASK; - if (pgd_end && (end > pgd_end)) - end = pgd_end; - - do { - count = swap_out_pmd(mm, vma, pmd, address, end, count, classzone); - if (!count) - break; - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address && (address < end)); - return count; -} - -/* mm->page_table_lock is held. mmap_sem is not held */ -static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count, zone_t * classzone) -{ - pgd_t *pgdir; - unsigned long end; - - /* Don't swap out areas which are reserved */ - if (vma->vm_flags & VM_RESERVED) - return count; - - pgdir = pgd_offset(mm, address); - end = vma->vm_end; - BUG_ON(address >= end); - do { - count = swap_out_pgd(mm, vma, pgdir, address, end, count, classzone); - if (!count) - break; - address = (address + PGDIR_SIZE) & PGDIR_MASK; - pgdir++; - } while (address && (address < end)); - return count; +found_page: + __lru_cache_del(page); + pte_chain_unlock(page); + spin_unlock(&pagecache_lock); + spin_unlock(&pagemap_lru_lock); + if (entry.val) + swap_free(entry); + UnlockPage(page); + page->age = PAGE_AGE_START; + if (page_count(page) != 1) + printk("VM: reclaim_page, found page with count %d!\n", + page_count(page)); + return page; } -/* Placeholder for swap_out(): may be updated by fork.c:mmput() */ -struct mm_struct *swap_mm = &init_mm; - -/* - * Returns remaining count of pages to be swapped out by followup call. +/** + * page_dirty - do we need to write the data out to disk + * @page: page to test + * + * Returns true if the page contains data which needs to + * be written to disk. Doesn't test the page tables (yet?). */ -static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter, zone_t * classzone) +static inline int page_dirty(struct page *page) { - unsigned long address; - struct vm_area_struct* vma; + struct buffer_head *tmp, *bh; - /* - * Find the proper vm-area after freezing the vma chain - * and ptes. - */ - spin_lock(&mm->page_table_lock); - address = mm->swap_address; - if (address == TASK_SIZE || swap_mm != mm) { - /* We raced: don't count this mm but try again */ - ++*mmcounter; - goto out_unlock; - } - vma = find_vma(mm, address); - if (vma) { - if (address < vma->vm_start) - address = vma->vm_start; - - for (;;) { - count = swap_out_vma(mm, vma, address, count, classzone); - vma = vma->vm_next; - if (!vma) - break; - if (!count) - goto out_unlock; - address = vma->vm_start; - } - } - /* Indicate that we reached the end of address space */ - mm->swap_address = TASK_SIZE; + if (PageDirty(page)) + return 1; -out_unlock: - spin_unlock(&mm->page_table_lock); - return count; -} + if (page->mapping && !page->buffers) + return 0; -static int FASTCALL(swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * classzone)); -static int swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * classzone) -{ - int counter, nr_pages = SWAP_CLUSTER_MAX; - struct mm_struct *mm; + tmp = bh = page->buffers; - counter = mmlist_nr; do { - if (unlikely(current->need_resched)) { - __set_current_state(TASK_RUNNING); - schedule(); - } - - spin_lock(&mmlist_lock); - mm = swap_mm; - while (mm->swap_address == TASK_SIZE || mm == &init_mm) { - mm->swap_address = 0; - mm = list_entry(mm->mmlist.next, struct mm_struct, mmlist); - if (mm == swap_mm) - goto empty; - swap_mm = mm; - } - - /* Make sure the mm doesn't disappear when we drop the lock.. */ - atomic_inc(&mm->mm_users); - spin_unlock(&mmlist_lock); - - nr_pages = swap_out_mm(mm, nr_pages, &counter, classzone); - - mmput(mm); - - if (!nr_pages) + if (tmp->b_state & ((1<= 0); - - return 0; + tmp = tmp->b_this_page; + } while (tmp != bh); -empty: - spin_unlock(&mmlist_lock); return 0; } -static int FASTCALL(shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority)); -static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority) +/** + * page_launder_zone - clean dirty inactive pages, move to inactive_clean list + * @zone: zone to free pages in + * @gfp_mask: what operations we are allowed to do + * + * This function is called when we are low on free / inactive_clean + * pages, its purpose is to refill the free/clean list as efficiently + * as possible. + * + * This means we do writes asynchronously as long as possible and will + * only sleep on IO when we don't have another option. Since writeouts + * cause disk seeks and make read IO slower, we skip writes alltogether + * when the amount of dirty pages is small. + * + * This code is heavily inspired by the FreeBSD source code. Thanks + * go out to Matthew Dillon. + */ +#define CAN_DO_FS ((gfp_mask & __GFP_FS) && should_write) +int page_launder_zone(zone_t * zone, int gfp_mask, int priority) { + int maxscan, cleaned_pages, target; struct list_head * entry; - int max_scan = nr_inactive_pages / priority; - int max_mapped = min((nr_pages << (10 - priority)), max_scan / 10); + target = free_plenty(zone); + cleaned_pages = 0; + + /* The main launder loop. */ spin_lock(&pagemap_lru_lock); - while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) { + maxscan = zone->inactive_dirty_pages >> priority; + while (maxscan-- && !list_empty(&zone->inactive_dirty_list)) { struct page * page; - - if (unlikely(current->need_resched)) { + + /* Low latency reschedule point */ + if (current->need_resched) { spin_unlock(&pagemap_lru_lock); - __set_current_state(TASK_RUNNING); schedule(); spin_lock(&pagemap_lru_lock); continue; } + entry = zone->inactive_dirty_list.prev; page = list_entry(entry, struct page, lru); - BUG_ON(!PageLRU(page)); - BUG_ON(PageActive(page)); + if (cleaned_pages > target) + break; list_del(entry); - list_add(entry, &inactive_list); + list_add(entry, &zone->inactive_dirty_list); + + /* Wrong page on list?! (list corruption, should not happen) */ + if (!PageInactiveDirty(page)) { + printk("VM: page_launder, wrong page on list.\n"); + list_del(entry); + nr_inactive_dirty_pages--; + page_zone(page)->inactive_dirty_pages--; + continue; + } /* - * Zero page counts can happen because we unlink the pages - * _after_ decrementing the usage count.. + * Page is being freed, don't worry about it. */ - if (unlikely(!page_count(page))) + if (unlikely(page_count(page)) == 0) continue; - if (!memclass(page_zone(page), classzone)) + /* + * The page is locked. IO in progress? + * Move it to the back of the list. + * Acquire PG_locked early in order to safely + * access page->mapping. + */ + if (unlikely(TryLockPage(page))) continue; - /* Racy check to avoid trylocking when not worthwhile */ - if (!page->buffers && (page_count(page) != 1 || !page->mapping)) - goto page_mapped; + /* + * The page is in active use or really unfreeable. Move to + * the active list and adjust the page age if needed. + */ + pte_chain_lock(page); + if (page_referenced(page) && page_mapping_inuse(page) && + !page_over_rsslimit(page)) { + del_page_from_inactive_dirty_list(page); + add_page_to_active_list(page); + page->age = max((int)page->age, PAGE_AGE_START); + pte_chain_unlock(page); + UnlockPage(page); + continue; + } + pte_chain_unlock(page); /* - * The page is locked. IO in progress? - * Move it to the back of the list. + * Anonymous process memory without backing store. Try to + * allocate it some swap space here. + * + * XXX: implement swap clustering ? */ - if (unlikely(TryLockPage(page))) { - if (PageLaunder(page) && (gfp_mask & __GFP_FS)) { - page_cache_get(page); - spin_unlock(&pagemap_lru_lock); - wait_on_page(page); + pte_chain_lock(page); + if (page->pte_chain && !page->mapping && !page->buffers) { + page_cache_get(page); + pte_chain_unlock(page); + spin_unlock(&pagemap_lru_lock); + if (!add_to_swap(page)) { + activate_page(page); + UnlockPage(page); page_cache_release(page); spin_lock(&pagemap_lru_lock); + continue; + } + page_cache_release(page); + spin_lock(&pagemap_lru_lock); + pte_chain_lock(page); + } + + /* + * The page is mapped into the page tables of one or more + * processes. Try to unmap it here. + */ + if (page->pte_chain) { + switch (try_to_unmap(page)) { + case SWAP_ERROR: + case SWAP_FAIL: + goto page_active; + case SWAP_AGAIN: + pte_chain_unlock(page); + UnlockPage(page); + continue; + case SWAP_SUCCESS: + ; /* try to free the page below */ } - continue; } + pte_chain_unlock(page); - if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) { + if (PageDirty(page) && page->mapping) { /* * It is not critical here to write it only if * the page is unmapped beause any direct writer * like O_DIRECT would set the PG_dirty bitflag - * on the phisical page after having successfully + * on the physical page after having successfully * pinned it and after the I/O to the page is finished, * so the direct writes to the page cannot get lost. */ @@ -421,7 +356,7 @@ if (page->buffers) { spin_unlock(&pagemap_lru_lock); - /* avoid to free a locked page */ + /* To avoid freeing our page before we're done. */ page_cache_get(page); if (try_to_release_page(page, gfp_mask)) { @@ -439,14 +374,14 @@ /* effectively free the page here */ page_cache_release(page); - if (--nr_pages) - continue; - break; + cleaned_pages++; + continue; } else { /* - * The page is still in pagecache so undo the stuff - * before the try_to_release_page since we've not - * finished and we can now try the next step. + * We freed the buffers but may have + * slept; undo the stuff we did before + * try_to_release_page and fall through + * to the next step. */ page_cache_release(page); @@ -462,224 +397,290 @@ } } - spin_lock(&pagecache_lock); /* - * this is the non-racy check for busy page. + * If the page is really freeable now, move it to the + * inactive_clean list. + * + * We re-test everything since the page could have been + * used by somebody else while we waited on IO above. + * This test is not safe from races, but only the one + * in reclaim_page() needs to be. */ - if (!page->mapping || !is_page_cache_freeable(page)) { - spin_unlock(&pagecache_lock); + pte_chain_lock(page); + if (page->mapping && !PageDirty(page) && !page->pte_chain && + page_count(page) == 1) { + del_page_from_inactive_dirty_list(page); + add_page_to_inactive_clean_list(page); + pte_chain_unlock(page); UnlockPage(page); -page_mapped: - if (--max_mapped >= 0) - continue; - + cleaned_pages++; + } else { /* - * Alert! We've found too many mapped pages on the - * inactive list, so we start swapping out now! + * OK, we don't know what to do with the page. + * It's no use keeping it here, so we move it to + * the active list. */ - spin_unlock(&pagemap_lru_lock); - swap_out(priority, gfp_mask, classzone); - return nr_pages; +page_active: + del_page_from_inactive_dirty_list(page); + add_page_to_active_list(page); + pte_chain_unlock(page); + UnlockPage(page); + } + } + spin_unlock(&pagemap_lru_lock); + + /* Return the number of pages moved to the inactive_clean list. */ + return cleaned_pages; +} + +/** + * page_launder - clean dirty inactive pages, move to inactive_clean list + * @gfp_mask: what operations we are allowed to do + * + * This function iterates over all zones and calls page_launder_zone(), + * balancing still needs to be added... + */ +int page_launder(int gfp_mask) +{ + int maxtry = 1 << DEF_PRIORITY; + struct zone_struct * zone; + int freed = 0; + + /* Global balancing while we have a global shortage. */ + while (maxtry-- && free_high(ALL_ZONES) >= 0) { + for_each_zone(zone) + if (free_plenty(zone) >= 0) + freed += page_launder_zone(zone, gfp_mask, 6); + } + + /* Clean up the remaining zones with a serious shortage, if any. */ + for_each_zone(zone) + if (free_min(zone) >= 0) + freed += page_launder_zone(zone, gfp_mask, 0); + + return freed; +} + +/** + * refill_inactive_zone - scan the active list and find pages to deactivate + * @priority: how much are we allowed to scan + * + * This function will scan a portion of the active list of a zone to find + * unused pages, those pages will then be moved to the inactive list. + */ +int refill_inactive_zone(struct zone_struct * zone, int priority) +{ + int maxscan = zone->active_pages >> priority; + int target = inactive_high(zone); + struct list_head * page_lru; + int nr_deactivated = 0; + struct page * page; + + /* Take the lock while messing with the list... */ + spin_lock(&pagemap_lru_lock); + while (maxscan-- && !list_empty(&zone->active_list)) { + page_lru = zone->active_list.prev; + page = list_entry(page_lru, struct page, lru); + + /* Wrong page on list?! (list corruption, should not happen) */ + if (unlikely(!PageActive(page))) { + printk("VM: refill_inactive, wrong page on list.\n"); + list_del(page_lru); + nr_active_pages--; + continue; + } + + /* Needed to follow page->mapping */ + if (TryLockPage(page)) { + list_del(page_lru); + list_add(page_lru, &zone->active_list); + continue; } /* - * It is critical to check PageDirty _after_ we made sure - * the page is freeable* so not in use by anybody. + * If the object the page is in is not in use we don't + * bother with page aging. If the page is touched again + * while on the inactive_clean list it'll be reactivated. + * From here until the end of the current iteration + * both PG_locked and the pte_chain_lock are held. */ - if (PageDirty(page)) { - spin_unlock(&pagecache_lock); + pte_chain_lock(page); + if (!page_mapping_inuse(page)) { + pte_chain_unlock(page); UnlockPage(page); + drop_page(page); continue; } - /* point of no return */ - if (likely(!PageSwapCache(page))) { - __remove_inode_page(page); - spin_unlock(&pagecache_lock); + /* + * Do aging on the pages. + */ + if (page_referenced(page)) { + age_page_up(page); } else { - swp_entry_t swap; - swap.val = page->index; - __delete_from_swap_cache(page); - spin_unlock(&pagecache_lock); - swap_free(swap); + age_page_down(page); } - __lru_cache_del(page); + /* + * If the page age is 'hot' and the process using the + * page doesn't exceed its RSS limit we keep the page. + * Otherwise we move it to the inactive_dirty list. + */ + if (page->age && !page_over_rsslimit(page)) { + list_del(page_lru); + list_add(page_lru, &zone->active_list); + } else { + deactivate_page_nolock(page); + if (++nr_deactivated > target) { + pte_chain_unlock(page); + UnlockPage(page); + goto done; + } + } + pte_chain_unlock(page); UnlockPage(page); - /* effectively free the page here */ - page_cache_release(page); - - if (--nr_pages) - continue; - break; + /* Low latency reschedule point */ + if (current->need_resched) { + spin_unlock(&pagemap_lru_lock); + schedule(); + spin_lock(&pagemap_lru_lock); + } } + +done: spin_unlock(&pagemap_lru_lock); - return nr_pages; + return nr_deactivated; } -/* - * This moves pages from the active list to - * the inactive list. +/** + * refill_inactive - checks all zones and refills the inactive list as needed * - * We move them the other way when we see the - * reference bit on the page. + * This function tries to balance page eviction from all zones by aging + * the pages from each zone in the same ratio until the global inactive + * shortage is resolved. After that it does one last "clean-up" scan to + * fix up local inactive shortages. */ -static void refill_inactive(int nr_pages) +int refill_inactive(void) { - struct list_head * entry; - - spin_lock(&pagemap_lru_lock); - entry = active_list.prev; - while (nr_pages && entry != &active_list) { - struct page * page; + int maxtry = 1 << DEF_PRIORITY; + zone_t * zone; + int ret = 0; - page = list_entry(entry, struct page, lru); - entry = entry->prev; - if (PageTestandClearReferenced(page)) { - list_del(&page->lru); - list_add(&page->lru, &active_list); - continue; + /* Global balancing while we have a global shortage. */ + while (maxtry-- && inactive_low(ALL_ZONES) >= 0) { + for_each_zone(zone) { + if (inactive_high(zone) >= 0) + ret += refill_inactive_zone(zone, DEF_PRIORITY); } + } - nr_pages--; - - del_page_from_active_list(page); - add_page_to_inactive_list(page); - SetPageReferenced(page); + /* Local balancing for zones which really need it. */ + for_each_zone(zone) { + if (inactive_min(zone) >= 0) + ret += refill_inactive_zone(zone, 0); } - spin_unlock(&pagemap_lru_lock); + + return ret; } -static int FASTCALL(shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages)); -static int shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages) +/** + * background_aging - slow background aging of zones + * @priority: priority at which to scan + * + * When the VM load is low or nonexistant, this function is + * called once a second to "sort" the pages in the VM. This + * way we know which pages to evict once a load spike happens. + * The effects of this function are very slow, the CPU usage + * should be minimal to nonexistant under most loads. + */ +static inline void background_aging(int priority) { - int chunk_size = nr_pages; - unsigned long ratio; - - nr_pages -= kmem_cache_reap(gfp_mask); - if (nr_pages <= 0) - return 0; + struct zone_struct * zone; - nr_pages = chunk_size; - /* try to keep the active list 2/3 of the size of the cache */ - ratio = (unsigned long) nr_pages * nr_active_pages / ((nr_inactive_pages + 1) * 2); - refill_inactive(ratio); + for_each_zone(zone) + if (inactive_high(zone) > 0) + refill_inactive_zone(zone, priority); +} - nr_pages = shrink_cache(nr_pages, classzone, gfp_mask, priority); - if (nr_pages <= 0) - return 0; +/* + * Worker function for kswapd and try_to_free_pages, we get + * called whenever there is a shortage of free/inactive_clean + * pages. + * + * This function will also move pages to the inactive list, + * if needed. + */ +static int do_try_to_free_pages(unsigned int gfp_mask) +{ + int ret = 0; - shrink_dcache_memory(priority, gfp_mask); - shrink_icache_memory(priority, gfp_mask); + /* + * Eat memory from filesystem page cache, buffer cache, + * dentry, inode and filesystem quota caches. + */ + ret += page_launder(gfp_mask); + ret += shrink_dcache_memory(DEF_PRIORITY, gfp_mask); + ret += shrink_icache_memory(1, gfp_mask); #ifdef CONFIG_QUOTA - shrink_dqcache_memory(DEF_PRIORITY, gfp_mask); + ret += shrink_dqcache_memory(DEF_PRIORITY, gfp_mask); #endif - return nr_pages; -} + /* + * Move pages from the active list to the inactive list. + */ + refill_inactive(); -int try_to_free_pages(zone_t *classzone, unsigned int gfp_mask, unsigned int order) -{ - int priority = DEF_PRIORITY; - int nr_pages = SWAP_CLUSTER_MAX; + /* + * Reclaim unused slab cache memory. + */ + ret += kmem_cache_reap(gfp_mask); - gfp_mask = pf_gfp_mask(gfp_mask); - do { - nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages); - if (nr_pages <= 0) - return 1; - } while (--priority); + refill_freelist(); + + /* Start IO when needed. */ + if (free_plenty(ALL_ZONES) > 0 || free_low(ANY_ZONE) > 0) + run_task_queue(&tq_disk); /* * Hmm.. Cache shrink failed - time to kill something? * Mhwahahhaha! This is the part I really like. Giggle. */ - out_of_memory(); - return 0; -} + if (!ret && free_min(ANY_ZONE) > 0) + out_of_memory(); -DECLARE_WAIT_QUEUE_HEAD(kswapd_wait); - -static int check_classzone_need_balance(zone_t * classzone) -{ - zone_t * first_classzone; - - first_classzone = classzone->zone_pgdat->node_zones; - while (classzone >= first_classzone) { - if (classzone->free_pages > classzone->pages_high) - return 0; - classzone--; - } - return 1; + return ret; } -static int kswapd_balance_pgdat(pg_data_t * pgdat) -{ - int need_more_balance = 0, i; - zone_t * zone; - - for (i = pgdat->nr_zones-1; i >= 0; i--) { - zone = pgdat->node_zones + i; - if (unlikely(current->need_resched)) - schedule(); - if (!zone->need_balance) - continue; - if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) { - zone->need_balance = 0; - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - continue; - } - if (check_classzone_need_balance(zone)) - need_more_balance = 1; - else - zone->need_balance = 0; - } - - return need_more_balance; -} - -static void kswapd_balance(void) -{ - int need_more_balance; - pg_data_t * pgdat; - - do { - need_more_balance = 0; - - for_each_pgdat(pgdat) - need_more_balance |= kswapd_balance_pgdat(pgdat); - } while (need_more_balance); -} - -static int kswapd_can_sleep_pgdat(pg_data_t * pgdat) +/** + * refill_freelist - move inactive_clean pages to free list if needed + * + * Move some pages from the inactive_clean lists to the free + * lists so atomic allocations have pages to work from. This + * function really only does something when we don't have a + * userspace load on __alloc_pages(). + * + * We refill the freelist in a bump from pages_min to pages_min * 2 + * in order to give the buddy allocator something to play with. + */ +static void refill_freelist(void) { + struct page * page; zone_t * zone; - int i; - for (i = pgdat->nr_zones-1; i >= 0; i--) { - zone = pgdat->node_zones + i; - if (!zone->need_balance) + for_each_zone(zone) { + if (!zone->size || zone->free_pages >= zone->pages_min) continue; - return 0; - } - return 1; -} - -static int kswapd_can_sleep(void) -{ - pg_data_t * pgdat; - - for_each_pgdat(pgdat) { - if (!kswapd_can_sleep_pgdat(pgdat)) - return 0; + while (zone->free_pages < zone->pages_min * 2) { + page = reclaim_page(zone); + if (!page) + break; + __free_page(page); + } } - - return 1; } /* @@ -698,7 +699,6 @@ int kswapd(void *unused) { struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); daemonize(); strcpy(tsk->comm, "kswapd"); @@ -722,24 +722,155 @@ * Kswapd main loop. */ for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&kswapd_wait, &wait); + static long recalc = 0; - mb(); - if (kswapd_can_sleep()) - schedule(); + /* + * We try to rebalance the VM either when we have a + * global shortage of free pages or when one particular + * zone is very short on free pages. + */ + if (free_high(ALL_ZONES) >= 0 || free_low(ANY_ZONE) > 0) + do_try_to_free_pages(GFP_KSWAPD); + + refill_freelist(); + + /* Once a second ... */ + if (time_after(jiffies, recalc + HZ)) { + recalc = jiffies; + + /* Do background page aging. */ + background_aging(DEF_PRIORITY); + } + + wakeup_memwaiters(); + } +} + +static int kswapd_overloaded; +unsigned int kswapd_minfree; /* initialized in mm/page_alloc.c */ +DECLARE_WAIT_QUEUE_HEAD(kswapd_wait); +DECLARE_WAIT_QUEUE_HEAD(kswapd_done); + +/** + * wakeup_kswapd - wake up the pageout daemon + * gfp_mask: page freeing flags + * + * This function wakes up kswapd and can, under heavy VM pressure, + * put the calling task to sleep temporarily. + */ +void wakeup_kswapd(unsigned int gfp_mask) +{ + DECLARE_WAITQUEUE(wait, current); + + /* If we're in the memory freeing business ourself, don't sleep + * but just wake kswapd and go back to businesss. + */ + if (current->flags & PF_MEMALLOC) { + wake_up_interruptible(&kswapd_wait); + return; + } - __set_current_state(TASK_RUNNING); + /* We need all of kswapd's GFP flags, otherwise we can't sleep on it. + * We still wake kswapd of course. + */ + if ((gfp_mask & GFP_KSWAPD) != GFP_KSWAPD) { + wake_up_interruptible(&kswapd_wait); + return; + } + + add_wait_queue(&kswapd_done, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + + /* Wake kswapd .... */ + wake_up_interruptible(&kswapd_wait); + + /* ... and check if we need to wait on it */ + if ((free_low(ALL_ZONES) > (kswapd_minfree / 2)) && !kswapd_overloaded) + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&kswapd_done, &wait); +} + +static void wakeup_memwaiters(void) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&kswapd_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + /* Don't let the processes waiting on memory get stuck, ever. */ + wake_up(&kswapd_done); + + /* Enough free RAM, we can easily keep up with memory demand. */ + if (free_high(ALL_ZONES) <= 0) { + schedule_timeout(HZ); remove_wait_queue(&kswapd_wait, &wait); + return; + } + remove_wait_queue(&kswapd_wait, &wait); - /* - * If we actually get into a low-memory situation, - * the processes needing more memory will wake us - * up on a more timely basis. - */ - kswapd_balance(); - run_task_queue(&tq_disk); + /* OK, the VM is very loaded. Sleep instead of using all CPU. */ + kswapd_overloaded = 1; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 4); + kswapd_overloaded = 0; + return; +} + +/** + * try_to_free_pages - run the pageout code ourselves + * gfp_mask: mask of things the pageout code is allowed to do + * + * When the load on the system gets higher, it can happen + * that kswapd no longer manages to keep enough memory + * free. In those cases user programs allocating memory + * will call try_to_free_pages() and help the pageout code. + * This has the effects of freeing memory and slowing down + * the largest memory hogs a bit. + */ +int try_to_free_pages(unsigned int gfp_mask) +{ + int ret = 1; + + gfp_mask = pf_gfp_mask(gfp_mask); + if (gfp_mask & __GFP_WAIT) { + current->flags |= PF_MEMALLOC; + ret = do_try_to_free_pages(gfp_mask); + current->flags &= ~PF_MEMALLOC; } + + return ret; +} + +/** + * rss_free_pages - run part of the pageout code and slow down a bit + * @gfp_mask: mask of things the pageout code is allowed to do + * + * This function is called when a task is over its RSS limit and + * has a page fault. It's goal is to free some memory so non-hogs + * can run faster and slow down itself when needed so it won't eat + * the memory non-hogs can use. + */ +void rss_free_pages(unsigned int gfp_mask) +{ + long pause = 0; + + if (current->flags & PF_MEMALLOC) + return; + + current->flags |= PF_MEMALLOC; + + do { + page_launder(gfp_mask); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(pause); + set_current_state(TASK_RUNNING); + pause++; + } while (free_high(ALL_ZONES) >= 0); + + current->flags &= ~PF_MEMALLOC; + return; } static int __init kswapd_init(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/802/p8022.c linux.20pre2-ac1/net/802/p8022.c --- linux.20pre2/net/802/p8022.c 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/net/802/p8022.c 2002-08-06 15:41:56.000000000 +0100 @@ -11,11 +11,10 @@ * matches. The control byte is ignored and handling of such items * is up to the routine passed the frame. * - * Unlike the 802.3 datalink we have a list of 802.2 entries as there - * are multiple protocols to demux. The list is currently short (3 or - * 4 entries at most). The current demux assumes this. + * Unlike the 802.3 datalink we have a list of 802.2 entries as + * there are multiple protocols to demux. The list is currently + * short (3 or 4 entries at most). The current demux assumes this. */ - #include #include #include @@ -25,8 +24,13 @@ #include #include -static struct datalink_proto *p8022_list = NULL; +extern void llc_register_sap(unsigned char sap, + int (*rcvfunc)(struct sk_buff *, + struct net_device *, + struct packet_type *)); +extern void llc_unregister_sap(unsigned char sap); +static struct datalink_proto *p8022_list; /* * We don't handle the loopback SAP stuff, the extended * 802.2 command set, multicast SAP identifiers and non UI @@ -34,91 +38,68 @@ * IP and Appletalk phase 2. See the llc_* routines for * support libraries if your protocol needs these. */ - static struct datalink_proto *find_8022_client(unsigned char type) { - struct datalink_proto *proto; - - for (proto = p8022_list; - ((proto != NULL) && (*(proto->type) != type)); - proto = proto->next) - ; + struct datalink_proto *proto = p8022_list; + while (proto && *(proto->type) != type) + proto = proto->next; return proto; } -int p8022_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) +int p8022_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) { - struct datalink_proto *proto; + struct datalink_proto *proto; + int rc = 0; proto = find_8022_client(*(skb->h.raw)); - if (proto != NULL) - { - skb->h.raw += 3; - skb->nh.raw += 3; - skb_pull(skb,3); - return proto->rcvfunc(skb, dev, pt); + if (!proto) { + skb->sk = NULL; + kfree_skb(skb); + goto out; } - - skb->sk = NULL; - kfree_skb(skb); - return 0; + skb->h.raw += 3; + skb->nh.raw += 3; + skb_pull(skb, 3); + rc = proto->rcvfunc(skb, dev, pt); +out: return rc; } static void p8022_datalink_header(struct datalink_proto *dl, - struct sk_buff *skb, unsigned char *dest_node) + struct sk_buff *skb, unsigned char *dest_node) { - struct net_device *dev = skb->dev; - unsigned char *rawp; + struct net_device *dev = skb->dev; + unsigned char *rawp = skb_push(skb, 3); - rawp = skb_push(skb,3); *rawp++ = dl->type[0]; *rawp++ = dl->type[0]; - *rawp = 0x03; /* UI */ + *rawp = 0x03; /* UI */ dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len); } -static struct packet_type p8022_packet_type = -{ - 0, /* MUTTER ntohs(ETH_P_8022),*/ - NULL, /* All devices */ - p8022_rcv, - NULL, - NULL, -}; - -EXPORT_SYMBOL(register_8022_client); -EXPORT_SYMBOL(unregister_8022_client); - -static int __init p8022_init(void) -{ - p8022_packet_type.type=htons(ETH_P_802_2); - dev_add_pack(&p8022_packet_type); - return 0; -} - -module_init(p8022_init); - -struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *)) -{ - struct datalink_proto *proto; - - if (find_8022_client(type) != NULL) - return NULL; - - proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); - if (proto != NULL) { - proto->type[0] = type; - proto->type_len = 1; - proto->rcvfunc = rcvfunc; - proto->header_length = 3; - proto->datalink_header = p8022_datalink_header; - proto->string_name = "802.2"; - proto->next = p8022_list; - p8022_list = proto; +struct datalink_proto *register_8022_client(unsigned char type, + int (*rcvfunc)(struct sk_buff *, + struct net_device *, + struct packet_type *)) +{ + struct datalink_proto *proto = NULL; + + if (find_8022_client(type)) + goto out; + proto = kmalloc(sizeof(*proto), GFP_ATOMIC); + if (proto) { + proto->type[0] = type; + proto->type_len = 1; + proto->rcvfunc = rcvfunc; + proto->header_length = 3; + proto->datalink_header = p8022_datalink_header; + proto->string_name = "802.2"; + proto->next = p8022_list; + p8022_list = proto; + llc_register_sap(type, p8022_rcv); } - - return proto; +out: return proto; } void unregister_8022_client(unsigned char type) @@ -128,17 +109,18 @@ save_flags(flags); cli(); - - while ((tmp = *clients) != NULL) - { + while (*clients) { + tmp = *clients; if (tmp->type[0] == type) { *clients = tmp->next; kfree(tmp); + llc_unregister_sap(type); break; - } else { - clients = &tmp->next; } + clients = &tmp->next; } - restore_flags(flags); } + +EXPORT_SYMBOL(register_8022_client); +EXPORT_SYMBOL(unregister_8022_client); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/atm/proc.c linux.20pre2-ac1/net/atm/proc.c --- linux.20pre2/net/atm/proc.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/atm/proc.c 2002-08-06 15:42:06.000000000 +0100 @@ -551,9 +551,12 @@ digits = 0; for (num = dev->number; num; num /= 10) digits++; if (!digits) digits++; - dev->proc_name = kmalloc(strlen(dev->type)+digits+2,GFP_KERNEL); - if (!dev->proc_name) goto fail1; + + dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_ATOMIC); + if (!dev->proc_name) + goto fail1; sprintf(dev->proc_name,"%s:%d",dev->type, dev->number); + dev->proc_entry = create_proc_entry(dev->proc_name, 0, atm_proc_root); if (!dev->proc_entry) goto fail0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/atm/resources.c linux.20pre2-ac1/net/atm/resources.c --- linux.20pre2/net/atm/resources.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/atm/resources.c 2002-08-06 15:42:06.000000000 +0100 @@ -27,15 +27,14 @@ struct atm_vcc *nodev_vccs = NULL; extern spinlock_t atm_dev_lock; -/* Caller must hold atm_dev_lock. */ -static struct atm_dev *__alloc_atm_dev(const char *type) + +static struct atm_dev *alloc_atm_dev(const char *type) { struct atm_dev *dev; dev = kmalloc(sizeof(*dev), GFP_ATOMIC); - if (!dev) - return NULL; - memset(dev, 0, sizeof(*dev)); + if (!dev) return NULL; + memset(dev,0,sizeof(*dev)); dev->type = type; dev->signal = ATM_PHY_SIG_UNKNOWN; dev->link_rate = ATM_OC3_PCR; @@ -43,118 +42,100 @@ dev->prev = last_dev; - if (atm_devs) - last_dev->next = dev; - else - atm_devs = dev; + if (atm_devs) last_dev->next = dev; + else atm_devs = dev; last_dev = dev; - return dev; } -/* Caller must hold atm_dev_lock. */ -static void __free_atm_dev(struct atm_dev *dev) -{ - if (dev->prev) - dev->prev->next = dev->next; - else - atm_devs = dev->next; - - if (dev->next) - dev->next->prev = dev->prev; - else - last_dev = dev->prev; +static void free_atm_dev(struct atm_dev *dev) +{ + if (dev->prev) dev->prev->next = dev->next; + else atm_devs = dev->next; + if (dev->next) dev->next->prev = dev->prev; + else last_dev = dev->prev; kfree(dev); } -/* Caller must hold atm_dev_lock. */ struct atm_dev *atm_find_dev(int number) { struct atm_dev *dev; for (dev = atm_devs; dev; dev = dev->next) - if (dev->ops && dev->number == number) - return dev; + if (dev->ops && dev->number == number) return dev; return NULL; } -struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, - int number, atm_dev_flags_t *flags) +struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, + int number,atm_dev_flags_t *flags) { - struct atm_dev *dev; + struct atm_dev *dev = NULL; spin_lock(&atm_dev_lock); - dev = __alloc_atm_dev(type); + dev = alloc_atm_dev(type); if (!dev) { printk(KERN_ERR "atm_dev_register: no space for dev %s\n", - type); + type); goto done; } if (number != -1) { if (atm_find_dev(number)) { - __free_atm_dev(dev); - dev = NULL; - goto done; + free_atm_dev(dev); + return NULL; } dev->number = number; } else { dev->number = 0; - while (atm_find_dev(dev->number)) - dev->number++; + while (atm_find_dev(dev->number)) dev->number++; } dev->vccs = dev->last = NULL; dev->dev_data = NULL; barrier(); dev->ops = ops; - if (flags) + if (flags) dev->flags = *flags; - else - memset(&dev->flags, 0, sizeof(dev->flags)); - memset(&dev->stats, 0, sizeof(dev->stats)); - + else + memset(&dev->flags,0,sizeof(dev->flags)); + memset((void *) &dev->stats,0,sizeof(dev->stats)); #ifdef CONFIG_PROC_FS - if (ops->proc_read) { + if (ops->proc_read) if (atm_proc_dev_register(dev) < 0) { printk(KERN_ERR "atm_dev_register: " - "atm_proc_dev_register failed for dev %s\n", - type); - __free_atm_dev(dev); - dev = NULL; + "atm_proc_dev_register failed for dev %s\n",type); + free_atm_dev(dev); goto done; } - } #endif done: - spin_unlock(&atm_dev_lock); - + spin_unlock(&atm_dev_lock); return dev; } + void atm_dev_deregister(struct atm_dev *dev) { #ifdef CONFIG_PROC_FS - if (dev->ops->proc_read) - atm_proc_dev_deregister(dev); + if (dev->ops->proc_read) atm_proc_dev_deregister(dev); #endif spin_lock(&atm_dev_lock); - __free_atm_dev(dev); + free_atm_dev(dev); spin_unlock(&atm_dev_lock); } void shutdown_atm_dev(struct atm_dev *dev) { if (dev->vccs) { - set_bit(ATM_DF_CLOSE, &dev->flags); + set_bit(ATM_DF_CLOSE,&dev->flags); return; } - if (dev->ops->dev_close) - dev->ops->dev_close(dev); + if (dev->ops->dev_close) dev->ops->dev_close(dev); atm_dev_deregister(dev); } + /* Handler for sk->destruct, invoked by sk_free() */ static void atm_free_sock(struct sock *sk) { @@ -167,48 +148,44 @@ struct atm_vcc *vcc; sk = sk_alloc(family, GFP_KERNEL, 1); - if (!sk) - return NULL; + if (!sk) return NULL; vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL); if (!vcc) { sk_free(sk); return NULL; } - sock_init_data(NULL, sk); + sock_init_data(NULL,sk); sk->destruct = atm_free_sock; memset(vcc,0,sizeof(*vcc)); vcc->sk = sk; - if (nodev_vccs) - nodev_vccs->prev = vcc; + if (nodev_vccs) nodev_vccs->prev = vcc; vcc->prev = NULL; vcc->next = nodev_vccs; nodev_vccs = vcc; return sk; } + static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev) { - if (vcc->prev) - vcc->prev->next = vcc->next; - else if (vcc->dev) - vcc->dev->vccs = vcc->next; - else - nodev_vccs = vcc->next; - if (vcc->next) - vcc->next->prev = vcc->prev; - else if (vcc->dev) - vcc->dev->last = vcc->prev; + if (vcc->prev) vcc->prev->next = vcc->next; + else if (vcc->dev) vcc->dev->vccs = vcc->next; + else nodev_vccs = vcc->next; + if (vcc->next) vcc->next->prev = vcc->prev; + else if (vcc->dev) vcc->dev->last = vcc->prev; if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs && test_bit(ATM_DF_CLOSE,&vcc->dev->flags)) shutdown_atm_dev(vcc->dev); } + void free_atm_vcc_sk(struct sock *sk) { - unlink_vcc(sk->protinfo.af_atm, NULL); + unlink_vcc(sk->protinfo.af_atm,NULL); sk_free(sk); } + void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev) { unlink_vcc(vcc,dev); @@ -216,20 +193,19 @@ if (dev) { vcc->next = NULL; vcc->prev = dev->last; - if (dev->vccs) - dev->last->next = vcc; - else - dev->vccs = vcc; + if (dev->vccs) dev->last->next = vcc; + else dev->vccs = vcc; dev->last = vcc; - } else { - if (nodev_vccs) - nodev_vccs->prev = vcc; + } + else { + if (nodev_vccs) nodev_vccs->prev = vcc; vcc->next = nodev_vccs; vcc->prev = NULL; nodev_vccs = vcc; } } + EXPORT_SYMBOL(atm_dev_register); EXPORT_SYMBOL(atm_dev_deregister); EXPORT_SYMBOL(atm_find_dev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/bluetooth/bnep/core.c linux.20pre2-ac1/net/bluetooth/bnep/core.c --- linux.20pre2/net/bluetooth/bnep/core.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/bluetooth/bnep/core.c 2002-08-06 15:42:06.000000000 +0100 @@ -458,8 +458,6 @@ sigfillset(¤t->blocked); flush_signals(current); - current->nice = -15; - set_fs(KERNEL_DS); init_waitqueue_entry(&wait, current); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/Config.in linux.20pre2-ac1/net/Config.in --- linux.20pre2/net/Config.in 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/Config.in 2002-08-06 15:41:56.000000000 +0100 @@ -68,11 +68,12 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25 tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB - bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC + tristate 'ANSI/IEEE 802.2 Data link layer protocol' CONFIG_LLC + if [ "$CONFIG_LLC" != "n" ]; then + # When NETBEUI is added the following line will be a tristate + define_bool CONFIG_LLC_UI y + fi bool 'Frame Diverter (EXPERIMENTAL)' CONFIG_NET_DIVERT -# if [ "$CONFIG_LLC" = "y" ]; then -# bool ' Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI -# fi if [ "$CONFIG_INET" = "y" ]; then tristate 'Acorn Econet/AUN protocols (EXPERIMENTAL)' CONFIG_ECONET if [ "$CONFIG_ECONET" != "n" ]; then diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/core/dst.c linux.20pre2-ac1/net/core/dst.c --- linux.20pre2/net/core/dst.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/core/dst.c 2002-08-06 17:26:28.000000000 +0100 @@ -5,8 +5,7 @@ * */ -#include -#include +#include #include #include #include diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/core/ext8022.c linux.20pre2-ac1/net/core/ext8022.c --- linux.20pre2/net/core/ext8022.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/core/ext8022.c 2002-08-06 15:41:56.000000000 +0100 @@ -0,0 +1,76 @@ +/* + * (ext8022.c) + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include + +typedef int (*func_type)(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt); +static int llc_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *); + +static func_type llc_sap_table[128]; +static int llc_users; + +static struct packet_type llc_packet_type = { + type: __constant_htons(ETH_P_802_2), + func: llc_rcv, +}; +static struct packet_type llc_tr_packet_type = { + type: __constant_htons(ETH_P_TR_802_2), + func: llc_rcv, +}; + +static int llc_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + unsigned char n = (*(skb->h.raw)) >> 1; + + br_read_lock(BR_LLC_LOCK); + if (llc_sap_table[n]) + llc_sap_table[n](skb, dev, pt); + else + kfree_skb(skb); + br_read_unlock(BR_LLC_LOCK); + return 0; +} + +void llc_register_sap(unsigned char sap, func_type rcvfunc) +{ + sap >>= 1; + br_write_lock_bh(BR_LLC_LOCK); + llc_sap_table[sap] = rcvfunc; + if (!llc_users) { + dev_add_pack(&llc_packet_type); + dev_add_pack(&llc_tr_packet_type); + } + llc_users++; + br_write_unlock_bh(BR_LLC_LOCK); +} + +void llc_unregister_sap(unsigned char sap) +{ + sap >>= 1; + br_write_lock_bh(BR_LLC_LOCK); + llc_sap_table[sap] = NULL; + if (!--llc_users) { + dev_remove_pack(&llc_packet_type); + dev_remove_pack(&llc_tr_packet_type); + } + br_write_unlock_bh(BR_LLC_LOCK); +} + +EXPORT_SYMBOL(llc_register_sap); +EXPORT_SYMBOL(llc_unregister_sap); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/core/Makefile linux.20pre2-ac1/net/core/Makefile --- linux.20pre2/net/core/Makefile 2002-08-13 13:58:22.000000000 +0100 +++ linux.20pre2-ac1/net/core/Makefile 2002-08-06 15:41:56.000000000 +0100 @@ -9,7 +9,7 @@ O_TARGET := core.o -export-objs := netfilter.o profile.o +export-objs := ext8022.o netfilter.o profile.o obj-y := sock.o skbuff.o iovec.o datagram.o scm.o @@ -23,6 +23,10 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o +ifneq ($(CONFIG_LLC),n) +obj-y += ext8022.o +endif + obj-$(CONFIG_NETFILTER) += netfilter.o obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PROFILE) += profile.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/core/pktgen.c linux.20pre2-ac1/net/core/pktgen.c --- linux.20pre2/net/core/pktgen.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/core/pktgen.c 2002-08-06 17:26:28.000000000 +0100 @@ -900,6 +900,7 @@ case ' ': goto done_str; default: + break; }; } done_str: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/ipv4/netfilter/ipchains_core.c linux.20pre2-ac1/net/ipv4/netfilter/ipchains_core.c --- linux.20pre2/net/ipv4/netfilter/ipchains_core.c 2002-08-13 13:58:22.000000000 +0100 +++ linux.20pre2-ac1/net/ipv4/netfilter/ipchains_core.c 2002-08-06 15:41:56.000000000 +0100 @@ -1779,4 +1779,4 @@ #endif return ret; } -MODULE_LICENSE("BSD without advertisement clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/ipv4/tcp_diag.c linux.20pre2-ac1/net/ipv4/tcp_diag.c --- linux.20pre2/net/ipv4/tcp_diag.c 2002-08-13 13:58:22.000000000 +0100 +++ linux.20pre2-ac1/net/ipv4/tcp_diag.c 2002-08-06 15:41:56.000000000 +0100 @@ -69,7 +69,8 @@ r->id.tcpdiag_src[0] = sk->rcv_saddr; r->id.tcpdiag_dst[0] = sk->daddr; r->id.tcpdiag_if = sk->bound_dev_if; - *((struct sock **)&r->id.tcpdiag_cookie) = sk; + r->id.tcpdiag_cookie[0] = (u32)sk; + r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)sk>>31)>>1); if (r->tcpdiag_state == TCP_TIME_WAIT) { struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk; @@ -229,7 +230,8 @@ err = -ESTALE; if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE || req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) && - sk != *((struct sock **)&req->id.tcpdiag_cookie[0])) + (u32)sk != req->id.tcpdiag_cookie[0] && + (((unsigned long)sk)>>31)>>1 != req->id.tcpdiag_cookie[0] ) goto out; err = -ENOMEM; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/ipv4/tcp_output.c linux.20pre2-ac1/net/ipv4/tcp_output.c --- linux.20pre2/net/ipv4/tcp_output.c 2002-08-13 13:58:22.000000000 +0100 +++ linux.20pre2-ac1/net/ipv4/tcp_output.c 2002-08-06 15:41:56.000000000 +0100 @@ -1010,8 +1010,7 @@ skb = alloc_skb(MAX_TCP_HEADER, GFP_KERNEL); if (skb) break; - current->policy |= SCHED_YIELD; - schedule(); + yield(); } /* Reserve space for headers and prepare control bits. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/irda/discovery.c linux.20pre2-ac1/net/irda/discovery.c --- linux.20pre2/net/irda/discovery.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/irda/discovery.c 2002-08-06 15:41:57.000000000 +0100 @@ -108,7 +108,7 @@ { discovery_t *discovery; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); /* * If log is missing this means that IrLAP was unable to perform the @@ -144,7 +144,7 @@ discovery_t *discovery, *curr; unsigned long flags; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); spin_lock_irqsave(&irlmp->log_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/irda/ircomm/ircomm_tty.c linux.20pre2-ac1/net/irda/ircomm/ircomm_tty.c --- linux.20pre2/net/irda/ircomm/ircomm_tty.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/irda/ircomm/ircomm_tty.c 2002-08-13 14:58:20.000000000 +0100 @@ -93,7 +93,7 @@ { ircomm_tty = hashbin_new(HB_LOCAL); if (ircomm_tty == NULL) { - ERROR(__FUNCTION__ "(), can't allocate hashbin!\n"); + ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__); return -ENOMEM; } @@ -136,7 +136,7 @@ driver.read_proc = ircomm_tty_read_proc; #endif /* CONFIG_PROC_FS */ if (tty_register_driver(&driver)) { - ERROR(__FUNCTION__ "Couldn't register serial driver\n"); + ERROR("%s: Couldn't register serial driver\n", __FUNCTION__); return -1; } return 0; @@ -145,7 +145,7 @@ #ifdef MODULE static void __ircomm_tty_cleanup(struct ircomm_tty_cb *self) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -166,11 +166,11 @@ { int ret; - IRDA_DEBUG(4, __FUNCTION__"()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ret = tty_unregister_driver(&driver); if (ret) { - ERROR(__FUNCTION__ "(), failed to unregister driver\n"); + ERROR("%s, failed to unregister driver\n", __FUNCTION__); return; } @@ -189,14 +189,14 @@ notify_t notify; int ret; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); /* Already open */ if (self->flags & ASYNC_INITIALIZED) { - IRDA_DEBUG(2, __FUNCTION__ "(), already open so break out!\n"); + IRDA_DEBUG(2, "%s(), already open so break out!\n", __FUNCTION__); return 0; } @@ -226,7 +226,7 @@ /* Connect IrCOMM link with remote device */ ret = ircomm_tty_attach_cable(self); if (ret < 0) { - ERROR(__FUNCTION__ "(), error attaching cable!\n"); + ERROR("%s(), error attaching cable!\n", __FUNCTION__); return ret; } @@ -250,7 +250,7 @@ unsigned long flags; struct tty_struct *tty; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); tty = self->tty; @@ -282,18 +282,18 @@ return -EBUSY; self->flags |= ASYNC_NORMAL_ACTIVE; - IRDA_DEBUG(1, __FUNCTION__ "(), O_NONBLOCK requested!\n"); + IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __FUNCTION__); return 0; } if (self->flags & ASYNC_CALLOUT_ACTIVE) { if (self->normal_termios.c_cflag & CLOCAL) { - IRDA_DEBUG(1, __FUNCTION__ "(), doing CLOCAL!\n"); + IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__); do_clocal = 1; } } else { if (tty->termios->c_cflag & CLOCAL) { - IRDA_DEBUG(1, __FUNCTION__ "(), doing CLOCAL!\n"); + IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__); do_clocal = 1; } } @@ -390,7 +390,7 @@ int line; int ret; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); MOD_INC_USE_COUNT; line = MINOR(tty->device) - tty->driver.minor_start; @@ -405,7 +405,7 @@ /* No, so make new instance */ self = kmalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL); if (self == NULL) { - ERROR(__FUNCTION__"(), kmalloc failed!\n"); + ERROR("%s(), kmalloc failed!\n", __FUNCTION__); MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -443,8 +443,8 @@ tty->driver_data = self; self->tty = tty; - IRDA_DEBUG(1, __FUNCTION__"(), %s%d, count = %d\n", tty->driver.name, - self->line, self->open_count); + IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __FUNCTION__, + tty->driver.name, self->line, self->open_count); /* Not really used by us, but lets do it anyway */ self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0; @@ -470,9 +470,9 @@ self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE; self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */ self->settings.dce = IRCOMM_CTS | IRCOMM_CD; /* Default line settings */ - IRDA_DEBUG(2, __FUNCTION__ "(), IrCOMM device\n"); + IRDA_DEBUG(2, "%s(), IrCOMM device\n", __FUNCTION__); } else { - IRDA_DEBUG(2, __FUNCTION__ "(), IrLPT device\n"); + IRDA_DEBUG(2, "%s(), IrLPT device\n", __FUNCTION__); self->service_type = IRCOMM_3_WIRE_RAW; self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */ } @@ -484,9 +484,8 @@ ret = ircomm_tty_block_til_ready(self, filp); if (ret) { /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ - IRDA_DEBUG(2, __FUNCTION__ - "(), returning after block_til_ready with %d\n", - ret); + IRDA_DEBUG(2, "%s(), returning after block_til_ready with %d\n", + __FUNCTION__, ret); return ret; } @@ -508,7 +507,7 @@ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long flags; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); if (!tty) return; @@ -520,7 +519,7 @@ MOD_DEC_USE_COUNT; restore_flags(flags); - IRDA_DEBUG(0, __FUNCTION__ "(), returning 1\n"); + IRDA_DEBUG(0, "%s(), returning 1\n", __FUNCTION__); return; } @@ -535,23 +534,22 @@ * one, we've got real problems, since it means the * serial port won't be shutdown. */ - IRDA_DEBUG(0, __FUNCTION__ "(), bad serial port count; " + IRDA_DEBUG(0, "%s(), bad serial port count; " "tty->count is 1, state->count is %d\n", - self->open_count); + __FUNCTION__, self->open_count); self->open_count = 1; } if (--self->open_count < 0) { - ERROR(__FUNCTION__ - "(), bad serial port count for ttys%d: %d\n", - self->line, self->open_count); + ERROR("%s(), bad serial port count for ttys%d: %d\n", + __FUNCTION__, self->line, self->open_count); self->open_count = 0; } if (self->open_count) { MOD_DEC_USE_COUNT; restore_flags(flags); - IRDA_DEBUG(0, __FUNCTION__ "(), open count > 0\n"); + IRDA_DEBUG(0, "%s(), open count > 0\n", __FUNCTION__); return; } self->flags |= ASYNC_CLOSING; @@ -625,7 +623,7 @@ unsigned long flags; struct sk_buff *skb, *ctrl_skb; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); if (!self || self->magic != IRCOMM_TTY_MAGIC) return; @@ -690,8 +688,8 @@ int len = 0; int size; - IRDA_DEBUG(2, __FUNCTION__ "(), count=%d, hw_stopped=%d\n", count, - tty->hw_stopped); + IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", + __FUNCTION__, count, tty->hw_stopped); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); @@ -822,7 +820,7 @@ ret = self->max_data_size; restore_flags(flags); } - IRDA_DEBUG(2, __FUNCTION__ "(), ret=%d\n", ret); + IRDA_DEBUG(2, "%s(), ret=%d\n", __FUNCTION__, ret); return ret; } @@ -838,7 +836,7 @@ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long orig_jiffies, poll_time; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -870,7 +868,7 @@ { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -901,7 +899,7 @@ { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -916,7 +914,7 @@ self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS); ircomm_param_request(self, IRCOMM_DTE, TRUE); - IRDA_DEBUG(1, __FUNCTION__"(), FLOW_START\n"); + IRDA_DEBUG(1, "%s(), FLOW_START\n", __FUNCTION__); } ircomm_flow_request(self->ircomm, FLOW_START); } @@ -954,7 +952,7 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); if (!(self->flags & ASYNC_INITIALIZED)) return; @@ -998,7 +996,7 @@ { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - IRDA_DEBUG(0, __FUNCTION__"()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -1023,7 +1021,7 @@ */ static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch) { - IRDA_DEBUG(0, __FUNCTION__"(), not impl\n"); + IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__); } /* @@ -1067,7 +1065,7 @@ struct tty_struct *tty; int status; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -1080,17 +1078,15 @@ /*wake_up_interruptible(&self->delta_msr_wait);*/ } if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) { - IRDA_DEBUG(2, __FUNCTION__ - "(), ircomm%d CD now %s...\n", self->line, - (status & IRCOMM_CD) ? "on" : "off"); + IRDA_DEBUG(2, "%s(), ircomm%d CD now %s...\n", + __FUNCTION__, self->line, (status & IRCOMM_CD) ? "on" : "off"); if (status & IRCOMM_CD) { wake_up_interruptible(&self->open_wait); } else if (!((self->flags & ASYNC_CALLOUT_ACTIVE) && (self->flags & ASYNC_CALLOUT_NOHUP))) { - IRDA_DEBUG(2, __FUNCTION__ - "(), Doing serial hangup..\n"); + IRDA_DEBUG(2, "%s(), Doing serial hangup..\n", __FUNCTION__); if (tty) tty_hangup(tty); @@ -1101,8 +1097,7 @@ if (self->flags & ASYNC_CTS_FLOW) { if (tty->hw_stopped) { if (status & IRCOMM_CTS) { - IRDA_DEBUG(2, __FUNCTION__ - "(), CTS tx start...\n"); + IRDA_DEBUG(2, "%s(), CTS tx start...\n", __FUNCTION__); tty->hw_stopped = 0; /* Wake up processes blocked on open */ @@ -1114,8 +1109,7 @@ } } else { if (!(status & IRCOMM_CTS)) { - IRDA_DEBUG(2, __FUNCTION__ - "(), CTS tx stop...\n"); + IRDA_DEBUG(2, "%s(), CTS tx stop...\n", __FUNCTION__); tty->hw_stopped = 1; } } @@ -1133,14 +1127,14 @@ { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - IRDA_DEBUG(2, __FUNCTION__"()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); ASSERT(skb != NULL, return -1;); if (!self->tty) { - IRDA_DEBUG(0, __FUNCTION__ "(), no tty!\n"); + IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__); dev_kfree_skb(skb); return 0; } @@ -1152,7 +1146,7 @@ * params, we can just as well declare the hardware for running. */ if (self->tty->hw_stopped && (self->flow == FLOW_START)) { - IRDA_DEBUG(0, __FUNCTION__ "(), polling for line settings!\n"); + IRDA_DEBUG(0, "%s(), polling for line settings!\n", __FUNCTION__); ircomm_param_request(self, IRCOMM_POLL, TRUE); /* We can just as well declare the hardware for running */ @@ -1183,7 +1177,7 @@ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; int clen; - IRDA_DEBUG(4, __FUNCTION__"()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); @@ -1218,7 +1212,7 @@ switch (cmd) { case FLOW_START: - IRDA_DEBUG(2, __FUNCTION__ "(), hw start!\n"); + IRDA_DEBUG(2, "%s(), hw start!\n", __FUNCTION__); tty->hw_stopped = 0; /* ircomm_tty_do_softint will take care of the rest */ @@ -1227,7 +1221,7 @@ break; default: /* If we get here, something is very wrong, better stop */ case FLOW_STOP: - IRDA_DEBUG(2, __FUNCTION__ "(), hw stopped!\n"); + IRDA_DEBUG(2, "%s(), hw stopped!\n", __FUNCTION__); tty->hw_stopped = 1; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/irda/iriap.c linux.20pre2-ac1/net/irda/iriap.c --- linux.20pre2/net/irda/iriap.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/irda/iriap.c 2002-08-06 15:41:57.000000000 +0100 @@ -98,7 +98,7 @@ objects = hashbin_new(HB_LOCAL); if (!objects) { - WARNING(__FUNCTION__ "(), Can't allocate objects hashbin!\n"); + WARNING("%s(), Can't allocate objects hashbin!\n", __FUNCTION__); return -ENOMEM; } @@ -128,7 +128,7 @@ */ server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); if (!server) { - IRDA_DEBUG(0, __FUNCTION__ "(), unable to open server\n"); + IRDA_DEBUG(0, "%s(), unable to open server\n", __FUNCTION__); return -1; } iriap_register_lsap(server, LSAP_IAS, IAS_SERVER); @@ -160,11 +160,11 @@ { struct iriap_cb *self; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); self = kmalloc(sizeof(struct iriap_cb), GFP_ATOMIC); if (!self) { - WARNING(__FUNCTION__ "(), Unable to kmalloc!\n"); + WARNING("%s(), Unable to kmalloc!\n", __FUNCTION__); return NULL; } @@ -202,7 +202,7 @@ */ static void __iriap_close(struct iriap_cb *self) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); @@ -226,7 +226,7 @@ { struct iriap_cb *entry; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); @@ -246,7 +246,7 @@ { notify_t notify; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); irda_notify_init(¬ify); notify.connect_confirm = iriap_connect_confirm; @@ -261,7 +261,7 @@ self->lsap = irlmp_open_lsap(slsap_sel, ¬ify, 0); if (self->lsap == NULL) { - ERROR(__FUNCTION__ "(), Unable to allocated LSAP!\n"); + ERROR("%s(), Unable to allocated LSAP!\n", __FUNCTION__); return -1; } self->slsap_sel = self->lsap->slsap_sel; @@ -281,7 +281,7 @@ { struct iriap_cb *self; - IRDA_DEBUG(4, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]); + IRDA_DEBUG(4, "%s(), reason=%s\n", __FUNCTION__, lmp_reasons[reason]); self = (struct iriap_cb *) instance; @@ -293,7 +293,7 @@ del_timer(&self->watchdog_timer); if (self->mode == IAS_CLIENT) { - IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as client\n"); + IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__); iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION, @@ -306,7 +306,7 @@ if (self->confirm) self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); } else { - IRDA_DEBUG(4, __FUNCTION__ "(), disconnect as server\n"); + IRDA_DEBUG(4, "%s(), disconnect as server\n", __FUNCTION__); iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, NULL); iriap_close(self); @@ -326,15 +326,15 @@ { struct sk_buff *skb; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); skb = dev_alloc_skb(64); if (skb == NULL) { - IRDA_DEBUG(0, __FUNCTION__ - "(), Could not allocate an sk_buff of length %d\n", 64); + IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n", + __FUNCTION__, 64); return; } @@ -348,27 +348,27 @@ void iriap_getinfobasedetails_request(void) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n"); + IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__); } void iriap_getinfobasedetails_confirm(void) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n"); + IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__); } void iriap_getobjects_request(void) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n"); + IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__); } void iriap_getobjects_confirm(void) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n"); + IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__); } void iriap_getvalue(void) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented!\n"); + IRDA_DEBUG(0, "%s(), Not implemented!\n", __FUNCTION__); } /* @@ -458,13 +458,13 @@ /* Get length, MSB first */ len = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2; - IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len); + IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len); /* Get object ID, MSB first */ obj_id = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2; type = fp[n++]; - IRDA_DEBUG(4, __FUNCTION__ "(), Value type = %d\n", type); + IRDA_DEBUG(4, "%s(), Value type = %d\n", __FUNCTION__, type); switch (type) { case IAS_INTEGER: @@ -473,7 +473,7 @@ value = irias_new_integer_value(tmp_cpu32); /* Legal values restricted to 0x01-0x6f, page 15 irttp */ - IRDA_DEBUG(4, __FUNCTION__ "(), lsap=%d\n", value->t.integer); + IRDA_DEBUG(4, "%s(), lsap=%d\n", __FUNCTION__, value->t.integer); break; case IAS_STRING: charset = fp[n++]; @@ -492,9 +492,8 @@ /* case CS_ISO_8859_9: */ /* case CS_UNICODE: */ default: - IRDA_DEBUG(0, __FUNCTION__ - "(), charset %s, not supported\n", - ias_charset_types[charset]); + IRDA_DEBUG(0, "%s(), charset %s, not supported\n", + __FUNCTION__, ias_charset_types[charset]); /* Aborting, close connection! */ iriap_disconnect_request(self); @@ -503,7 +502,7 @@ /* break; */ } value_len = fp[n++]; - IRDA_DEBUG(4, __FUNCTION__ "(), strlen=%d\n", value_len); + IRDA_DEBUG(4, "%s(), strlen=%d\n", __FUNCTION__, value_len); /* Make sure the string is null-terminated */ fp[n+value_len] = 0x00; @@ -533,7 +532,7 @@ if (self->confirm) self->confirm(IAS_SUCCESS, obj_id, value, self->priv); else { - IRDA_DEBUG(0, __FUNCTION__ "(), missing handler!\n"); + IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__); irias_delete_value(value); } dev_kfree_skb(skb); @@ -553,7 +552,7 @@ __u32 tmp_be32, tmp_be16; __u8 *fp; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); @@ -614,12 +613,12 @@ memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len; break; case IAS_MISSING: - IRDA_DEBUG( 3, __FUNCTION__ ": sending IAS_MISSING\n"); + IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__); skb_put(skb, 1); fp[n++] = value->type; break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), type not implemented!\n"); + IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__); break; } iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb); @@ -643,7 +642,7 @@ __u8 *fp; int n; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); @@ -700,7 +699,7 @@ struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); @@ -731,7 +730,7 @@ self->saddr, self->daddr, NULL, NULL); if (ret < 0) { - IRDA_DEBUG(0, __FUNCTION__ "(), connect failed!\n"); + IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__); self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); } } @@ -776,7 +775,7 @@ { struct iriap_cb *self, *new; - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); self = (struct iriap_cb *) instance; @@ -786,7 +785,7 @@ /* Start new server */ new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); if (!new) { - IRDA_DEBUG(0, __FUNCTION__ "(), open failed\n"); + IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__); dev_kfree_skb(userdata); return; } @@ -794,7 +793,7 @@ /* Now attach up the new "socket" */ new->lsap = irlmp_dup(self->lsap, new); if (!new->lsap) { - IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n"); + IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); return; } @@ -820,7 +819,7 @@ __u8 *frame; __u8 opcode; - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); self = (struct iriap_cb *) instance; @@ -833,22 +832,22 @@ if (self->mode == IAS_SERVER) { /* Call server */ - IRDA_DEBUG(4, __FUNCTION__ "(), Calling server!\n"); + IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__); iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb); return 0; } opcode = frame[0]; if (~opcode & IAP_LST) { - WARNING(__FUNCTION__ "(), IrIAS multiframe commands or " - "results is not implemented yet!\n"); + WARNING("%s(), IrIAS multiframe commands or " + "results is not implemented yet!\n", __FUNCTION__); dev_kfree_skb(skb); return 0; } /* Check for ack frames since they don't contain any data */ if (opcode & IAP_ACK) { - IRDA_DEBUG(0, __FUNCTION__ "() Got ack frame!\n"); + IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__); dev_kfree_skb(skb); return 0; } @@ -868,7 +867,7 @@ iriap_getvaluebyclass_confirm(self, skb); break; case IAS_CLASS_UNKNOWN: - IRDA_DEBUG(1, __FUNCTION__ "(), No such class!\n"); + IRDA_DEBUG(1, "%s(), No such class!\n", __FUNCTION__); /* Finished, close connection! */ iriap_disconnect_request(self); @@ -882,7 +881,7 @@ dev_kfree_skb(skb); break; case IAS_ATTRIB_UNKNOWN: - IRDA_DEBUG(1, __FUNCTION__ "(), No such attribute!\n"); + IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__); /* Finished, close connection! */ iriap_disconnect_request(self); @@ -898,8 +897,7 @@ } break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown op-code: %02x\n", - opcode); + IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__, opcode); dev_kfree_skb(skb); break; } @@ -917,7 +915,7 @@ __u8 *fp; __u8 opcode; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == IAS_MAGIC, return;); @@ -927,16 +925,16 @@ opcode = fp[0]; if (~opcode & 0x80) { - WARNING(__FUNCTION__ "(), IrIAS multiframe commands or results" - "is not implemented yet!\n"); + WARNING("%s(), IrIAS multiframe commands or results" + "is not implemented yet!\n", __FUNCTION__); return; } opcode &= 0x7f; /* Mask away LST bit */ switch (opcode) { case GET_INFO_BASE: - WARNING(__FUNCTION__ - "(), GetInfoBaseDetails not implemented yet!\n"); + WARNING("%s(), GetInfoBaseDetails not implemented yet!\n", + __FUNCTION__); break; case GET_VALUE_BY_CLASS: iriap_getvaluebyclass_indication(self, skb); @@ -1020,8 +1018,7 @@ len += sprintf(buf+len, "missing\n"); break; default: - IRDA_DEBUG(0, __FUNCTION__ - "(), Unknown value type!\n"); + IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__); return -1; } len += sprintf(buf+len, "\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/irda/iriap_event.c linux.20pre2-ac1/net/irda/iriap_event.c --- linux.20pre2/net/irda/iriap_event.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/irda/iriap_event.c 2002-08-06 15:41:57.000000000 +0100 @@ -181,7 +181,7 @@ case IAP_LM_DISCONNECT_INDICATION: break; default: - IRDA_DEBUG(0, __FUNCTION__"(), Unknown event %d\n", event); + IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); break; } } @@ -213,7 +213,7 @@ iriap_next_client_state(self, S_DISCONNECT); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event); + IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); break; } } @@ -262,7 +262,7 @@ iriap_next_call_state(self, S_OUTSTANDING); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event); + IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); if (skb) dev_kfree_skb(skb); break; @@ -278,7 +278,7 @@ static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n"); + IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); } /* @@ -300,7 +300,7 @@ iriap_next_call_state(self, S_WAIT_FOR_CALL); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event); + IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); break; } } @@ -313,7 +313,7 @@ static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n"); + IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); } /* @@ -325,7 +325,7 @@ static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n"); + IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); } @@ -338,7 +338,7 @@ static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n"); + IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); } /************************************************************************** @@ -362,7 +362,7 @@ case IAP_LM_CONNECT_INDICATION: tx_skb = dev_alloc_skb(64); if (tx_skb == NULL) { - WARNING(__FUNCTION__ "(), unable to malloc!\n"); + WARNING("%s(), unable to malloc!\n", __FUNCTION__); return; } @@ -385,7 +385,7 @@ break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), unknown event %d\n", event); + IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event); break; } } @@ -399,7 +399,7 @@ static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); switch (event) { case IAP_LM_DISCONNECT_INDICATION: @@ -408,7 +408,7 @@ iriap_next_r_connect_state(self, R_WAITING); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n"); + IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); break; } } @@ -426,13 +426,13 @@ static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n"); + IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); } static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n"); + IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); } /* @@ -444,7 +444,7 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); switch (event) { case IAP_RECV_F_LST: @@ -453,7 +453,7 @@ iriap_call_indication(self, skb); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n"); + IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); break; } @@ -468,12 +468,12 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(skb != NULL, return;); if (!self || self->magic != IAS_MAGIC) { - IRDA_DEBUG(0, __FUNCTION__ "(), bad pointer self\n"); + IRDA_DEBUG(0, "%s(), bad pointer self\n", __FUNCTION__); return; } @@ -488,7 +488,7 @@ irlmp_data_request(self->lsap, skb); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), unknown event!\n"); + IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); break; } } @@ -496,7 +496,7 @@ static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, __FUNCTION__ "(), event=%d\n", event); + IRDA_DEBUG(0, "%s(), event=%d\n", __FUNCTION__, event); switch (event) { case IAP_RECV_F_LST: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/irda/irlap.c linux.20pre2-ac1/net/irda/irlap.c --- linux.20pre2/net/irda/irlap.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/irda/irlap.c 2002-08-06 15:41:57.000000000 +0100 @@ -82,7 +82,7 @@ /* Allocate master array */ irlap = hashbin_new(HB_LOCAL); if (irlap == NULL) { - ERROR(__FUNCTION__ "(), can't allocate irlap hashbin!\n"); + ERROR("%s(), can't allocate irlap hashbin!\n", __FUNCTION__); return -ENOMEM; } @@ -107,7 +107,7 @@ { struct irlap_cb *self; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); /* Initialize the irlap structure. */ self = kmalloc(sizeof(struct irlap_cb), GFP_KERNEL); @@ -202,7 +202,7 @@ { struct irlap_cb *lap; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -215,7 +215,7 @@ /* Be sure that we manage to remove ourself from the hash */ lap = hashbin_remove(irlap, self->saddr, NULL); if (!lap) { - IRDA_DEBUG(1, __FUNCTION__ "(), Didn't find myself!\n"); + IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __FUNCTION__); return; } __irlap_close(lap); @@ -229,7 +229,7 @@ */ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -249,7 +249,7 @@ */ void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); irlap_do_event(self, CONNECT_RESPONSE, skb, NULL); kfree_skb(skb); @@ -265,7 +265,7 @@ void irlap_connect_request(struct irlap_cb *self, __u32 daddr, struct qos_info *qos_user, int sniff) { - IRDA_DEBUG(3, __FUNCTION__ "(), daddr=0x%08x\n", daddr); + IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __FUNCTION__, daddr); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -292,7 +292,7 @@ */ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -331,7 +331,7 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), return;); @@ -375,7 +375,7 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), return;); @@ -399,7 +399,7 @@ #ifdef CONFIG_IRDA_ULTRA void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -420,7 +420,7 @@ */ void irlap_disconnect_request(struct irlap_cb *self) { - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -442,7 +442,7 @@ irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL); break; default: - IRDA_DEBUG(2, __FUNCTION__ "(), disconnect pending!\n"); + IRDA_DEBUG(2, "%s(), disconnect pending!\n", __FUNCTION__); self->disconnect_pending = TRUE; break; } @@ -456,7 +456,7 @@ */ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) { - IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); + IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lap_reasons[reason]); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -466,7 +466,7 @@ switch (reason) { case LAP_RESET_INDICATION: - IRDA_DEBUG(1, __FUNCTION__ "(), Sending reset request!\n"); + IRDA_DEBUG(1, "%s(), Sending reset request!\n", __FUNCTION__); irlap_do_event(self, RESET_REQUEST, NULL, NULL); break; case LAP_NO_RESPONSE: /* FALLTROUGH */ @@ -477,7 +477,7 @@ reason, NULL); break; default: - ERROR(__FUNCTION__ "(), Unknown reason %d\n", reason); + ERROR("%s(), Unknown reason %d\n", __FUNCTION__, reason); } } @@ -495,7 +495,7 @@ ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(discovery != NULL, return;); - IRDA_DEBUG(4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots); + IRDA_DEBUG(4, "%s(), nslots = %d\n", __FUNCTION__, discovery->nslots); ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) || (discovery->nslots == 8) || (discovery->nslots == 16), @@ -503,8 +503,8 @@ /* Discovery is only possible in NDM mode */ if (self->state != LAP_NDM) { - IRDA_DEBUG(4, __FUNCTION__ - "(), discovery only possible in NDM mode\n"); + IRDA_DEBUG(4, "%s(), discovery only possible in NDM mode\n", + __FUNCTION__); irlap_discovery_confirm(self, NULL); /* Note : in theory, if we are not in NDM, we could postpone * the discovery like we do for connection request. @@ -575,7 +575,7 @@ */ void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -627,7 +627,7 @@ */ void irlap_reset_indication(struct irlap_cb *self) { - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -646,7 +646,7 @@ */ void irlap_reset_confirm(void) { - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); } /* @@ -746,7 +746,7 @@ { /* nr as expected? */ if (nr == self->vs) { - IRDA_DEBUG(4, __FUNCTION__ "(), expected!\n"); + IRDA_DEBUG(4, "%s(), expected!\n", __FUNCTION__); return NR_EXPECTED; } @@ -774,7 +774,7 @@ */ void irlap_initiate_connection_state(struct irlap_cb *self) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -857,7 +857,7 @@ { struct sk_buff *skb; - IRDA_DEBUG(0, __FUNCTION__ "(), setting speed to %d\n", speed); + IRDA_DEBUG(0, "%s(), setting speed to %d\n", __FUNCTION__, speed); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -899,7 +899,7 @@ * user may not have set all of them. */ if (qos_user) { - IRDA_DEBUG(1, __FUNCTION__ "(), Found user specified QoS!\n"); + IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __FUNCTION__); if (qos_user->baud_rate.bits) self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits; @@ -930,7 +930,7 @@ */ void irlap_apply_default_connection_parameters(struct irlap_cb *self) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); @@ -993,7 +993,7 @@ */ void irlap_apply_connection_parameters(struct irlap_cb *self, int now) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/irda/irlmp.c linux.20pre2-ac1/net/irda/irlmp.c --- linux.20pre2/net/irda/irlmp.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/irda/irlmp.c 2002-08-13 14:58:28.000000000 +0100 @@ -76,7 +76,7 @@ */ int __init irlmp_init(void) { - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); /* Initialize the irlmp structure. */ irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL); if (irlmp == NULL) @@ -155,7 +155,7 @@ /* Allocate new instance of a LSAP connection */ self = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC); if (self == NULL) { - ERROR(__FUNCTION__ "(), can't allocate memory"); + ERROR("%s(), can't allocate memory", __FUNCTION__); return NULL; } memset(self, 0, sizeof(struct lsap_cb)); @@ -194,7 +194,7 @@ */ static void __irlmp_close_lsap(struct lsap_cb *self) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -245,8 +245,7 @@ NULL); } if (!lsap) { - IRDA_DEBUG(0, __FUNCTION__ - "(), Looks like somebody has removed me already!\n"); + IRDA_DEBUG(0, "%s(), Looks like somebody has removed me already!\n", __FUNCTION__); return; } __irlmp_close_lsap(self); @@ -272,7 +271,7 @@ */ lap = kmalloc(sizeof(struct lap_cb), GFP_KERNEL); if (lap == NULL) { - ERROR(__FUNCTION__ "(), unable to kmalloc\n"); + ERROR("%s(), unable to kmalloc\n", __FUNCTION__); return; } memset(lap, 0, sizeof(struct lap_cb)); @@ -310,7 +309,7 @@ { struct lap_cb *link; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); link = hashbin_remove(irlmp->links, saddr, NULL); if (link) { @@ -344,9 +343,8 @@ ASSERT(self != NULL, return -EBADR;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;); - IRDA_DEBUG(2, __FUNCTION__ - "(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", - self->slsap_sel, dlsap_sel, saddr, daddr); + IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", + __FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr); if (test_bit(0, &self->connected)) return -EISCONN; @@ -383,7 +381,7 @@ if (daddr != DEV_ADDR_ANY) discovery = hashbin_find(irlmp->cachelog, daddr, NULL); else { - IRDA_DEBUG(2, __FUNCTION__ "(), no daddr\n"); + IRDA_DEBUG(2, "%s(), no daddr\n", __FUNCTION__); discovery = (discovery_t *) hashbin_get_first(irlmp->cachelog); } @@ -395,7 +393,7 @@ } lap = hashbin_find(irlmp->links, saddr, NULL); if (lap == NULL) { - IRDA_DEBUG(1, __FUNCTION__ "(), Unable to find a usable link!\n"); + IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__); return -EHOSTUNREACH; } @@ -412,13 +410,13 @@ * disconnected yet (waiting for timeout in LAP). * Maybe we could give LAP a bit of help in this case. */ - IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but I'm waiting for LAP to timeout!\n"); + IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__); return -EAGAIN; } /* LAP is already connected to a different node, and LAP * can only talk to one node at a time */ - IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but link is busy!\n"); + IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__); return -EBUSY; } @@ -467,8 +465,8 @@ ASSERT(skb != NULL, return;); ASSERT(self->lap != NULL, return;); - IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", - self->slsap_sel, self->dlsap_sel); + IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", + __FUNCTION__, self->slsap_sel, self->dlsap_sel); /* Note : self->lap is set in irlmp_link_data_indication(), * (case CONNECT_CMD:) because we have no way to set it here. @@ -506,8 +504,8 @@ set_bit(0, &self->connected); /* TRUE */ - IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", - self->slsap_sel, self->dlsap_sel); + IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", + __FUNCTION__, self->slsap_sel, self->dlsap_sel); /* Make room for MUX control header (3 bytes) */ ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;); @@ -529,7 +527,7 @@ int lap_header_size; int max_seg_size; - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); ASSERT(skb != NULL, return;); ASSERT(self != NULL, return;); @@ -542,8 +540,8 @@ lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap); max_header_size = LMP_HEADER + lap_header_size; - IRDA_DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", - max_header_size); + IRDA_DEBUG(2, "%s(), max_header_size=%d\n", + __FUNCTION__, max_header_size); /* Hide LMP_CONTROL_HEADER header from layer above */ skb_pull(skb, LMP_CONTROL_HEADER); @@ -567,16 +565,16 @@ { struct lsap_cb *new; - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); /* Only allowed to duplicate unconnected LSAP's */ if (!hashbin_find(irlmp->unconnected_lsaps, (int) orig, NULL)) { - IRDA_DEBUG(0, __FUNCTION__ "(), unable to find LSAP\n"); + IRDA_DEBUG(0, "%s(), unable to find LSAP\n", __FUNCTION__); return NULL; } new = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC); if (!new) { - IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n"); + IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__); return NULL; } /* Dup */ @@ -617,7 +615,7 @@ * and us that might mess up the hashbins below. This fixes it. * Jean II */ if (! test_and_clear_bit(0, &self->connected)) { - IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n"); + IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__); dev_kfree_skb(userdata); return -1; } @@ -664,19 +662,19 @@ { struct lsap_cb *lsap; - IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]); + IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lmp_reasons[reason]); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", - self->slsap_sel, self->dlsap_sel); + IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", + __FUNCTION__, self->slsap_sel, self->dlsap_sel); /* Already disconnected ? * There is a race condition between irlmp_disconnect_request() * and us that might mess up the hashbins below. This fixes it. * Jean II */ if (! test_and_clear_bit(0, &self->connected)) { - IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n"); + IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__); if (userdata) dev_kfree_skb(userdata); return; @@ -709,7 +707,7 @@ self->notify.disconnect_indication(self->notify.instance, self, reason, userdata); else { - IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n"); + IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__); if (userdata) dev_kfree_skb(userdata); } @@ -762,8 +760,7 @@ /* Make sure the value is sane */ if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){ - WARNING(__FUNCTION__ - "(), invalid value for number of slots!\n"); + WARNING("%s(), invalid value for number of slots!\n", __FUNCTION__); nslots = sysctl_discovery_slots = 8; } @@ -914,7 +911,7 @@ { discovery_t *discovery; - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); /* Check if client wants or not partial/selective log (optimisation) */ if (!client->disco_callback) @@ -950,7 +947,7 @@ { irlmp_client_t *client; - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); ASSERT(log != NULL, return;); @@ -981,7 +978,7 @@ { irlmp_client_t *client; - IRDA_DEBUG(3, __FUNCTION__ "()\n"); + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); ASSERT(expiry != NULL, return;); @@ -1006,7 +1003,7 @@ */ discovery_t *irlmp_get_discovery_response() { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(irlmp != NULL, return NULL;); @@ -1069,7 +1066,7 @@ */ int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(skb != NULL, return -1;); @@ -1088,7 +1085,7 @@ */ void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -1116,7 +1113,7 @@ struct sk_buff *clone_skb; struct lap_cb *lap; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(skb != NULL, return -1;); @@ -1159,7 +1156,7 @@ #ifdef CONFIG_IRDA_ULTRA void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -1178,7 +1175,7 @@ void irlmp_status_request(void) { - IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n"); + IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); } /* @@ -1208,7 +1205,7 @@ curr->notify.status_indication(curr->notify.instance, link, lock); else - IRDA_DEBUG(2, __FUNCTION__ "(), no handler\n"); + IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__); } } @@ -1229,7 +1226,7 @@ */ service = kmalloc(16, GFP_ATOMIC); if (!service) { - IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n"); + IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__); return NULL; } @@ -1335,7 +1332,7 @@ hint.word = 0xffff; break; default: - IRDA_DEBUG( 1, __FUNCTION__ "(), Unknown service!\n"); + IRDA_DEBUG( 1, "%s(), Unknown service!\n", __FUNCTION__); break; } return hint.word; @@ -1352,7 +1349,7 @@ irlmp_service_t *service; __u32 handle; - IRDA_DEBUG(4, __FUNCTION__ "(), hints = %04x\n", hints); + IRDA_DEBUG(4, "%s(), hints = %04x\n", __FUNCTION__, hints); /* Get a unique handle for this service */ get_random_bytes(&handle, sizeof(handle)); @@ -1364,7 +1361,7 @@ /* Make a new registration */ service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC); if (!service) { - IRDA_DEBUG(1, __FUNCTION__ "(), Unable to kmalloc!\n"); + IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__); return 0; } service->hints = hints; @@ -1384,14 +1381,14 @@ { irlmp_service_t *service; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); if (!handle) return -1; service = hashbin_find(irlmp->services, handle, NULL); if (!service) { - IRDA_DEBUG(1, __FUNCTION__ "(), Unknown service!\n"); + IRDA_DEBUG(1, "%s(), Unknown service!\n", __FUNCTION__); return -1; } @@ -1427,7 +1424,7 @@ irlmp_client_t *client; __u32 handle; - IRDA_DEBUG(1, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, "%s()\n", __FUNCTION__); ASSERT(irlmp != NULL, return 0;); /* Get a unique handle for this client */ @@ -1438,7 +1435,7 @@ /* Make a new registration */ client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC); if (!client) { - IRDA_DEBUG( 1, __FUNCTION__ "(), Unable to kmalloc!\n"); + IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __FUNCTION__); return 0; } @@ -1472,7 +1469,7 @@ client = hashbin_find(irlmp->clients, handle, NULL); if (!client) { - IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n"); + IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__); return -1; } @@ -1494,18 +1491,18 @@ { struct irlmp_client *client; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); if (!handle) return -1; client = hashbin_find(irlmp->clients, handle, NULL); if (!client) { - IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n"); + IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__); return -1; } - IRDA_DEBUG( 4, __FUNCTION__ "(), removing client!\n"); + IRDA_DEBUG( 4, "%s(), removing client!\n", __FUNCTION__); client = hashbin_remove( irlmp->clients, handle, NULL); if (client) kfree(client); @@ -1527,7 +1524,7 @@ ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;); ASSERT(slsap_sel != LSAP_ANY, return TRUE;); - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); #ifdef CONFIG_IRDA_ULTRA /* Accept all bindings to the connectionless LSAP */ @@ -1593,7 +1590,7 @@ return 0; } } - IRDA_DEBUG(4, __FUNCTION__ "(), next free lsap_sel=%02x\n", lsap_sel); + IRDA_DEBUG(4, "%s(), next free lsap_sel=%02x\n", __FUNCTION__, lsap_sel); return lsap_sel; } @@ -1611,26 +1608,26 @@ switch (lap_reason) { case LAP_DISC_INDICATION: /* Received a disconnect request from peer */ - IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_DISC_INDICATION\n"); + IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __FUNCTION__); reason = LM_USER_REQUEST; break; case LAP_NO_RESPONSE: /* To many retransmits without response */ - IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_NO_RESPONSE\n"); + IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __FUNCTION__); reason = LM_LAP_DISCONNECT; break; case LAP_RESET_INDICATION: - IRDA_DEBUG( 1, __FUNCTION__ "(), LAP_RESET_INDICATION\n"); + IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __FUNCTION__); reason = LM_LAP_RESET; break; case LAP_FOUND_NONE: case LAP_MEDIA_BUSY: case LAP_PRIMARY_CONFLICT: - IRDA_DEBUG(1, __FUNCTION__ "(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n"); + IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __FUNCTION__); reason = LM_CONNECT_FAILURE; break; default: - IRDA_DEBUG(1, __FUNCTION__ - "(), Unknow IrLAP disconnect reason %d!\n", lap_reason); + IRDA_DEBUG(1, "%s(), Unknow IrLAP disconnect reason %d!\n", + __FUNCTION__, lap_reason); reason = LM_LAP_DISCONNECT; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/irda/irlmp_event.c linux.20pre2-ac1/net/irda/irlmp_event.c --- linux.20pre2/net/irda/irlmp_event.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/irda/irlmp_event.c 2002-08-13 14:58:28.000000000 +0100 @@ -121,7 +121,7 @@ IRLMP_STATE state) { /* - IRDA_DEBUG(4, __FUNCTION__ "(), LMP LAP = %s\n", irlmp_state[state]); + IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __FUNCTION__, irlmp_state[state]); */ self->lap_state = state; } @@ -131,7 +131,7 @@ { /* ASSERT(self != NULL, return;); - IRDA_DEBUG(4, __FUNCTION__ "(), LMP LSAP = %s\n", irlsap_state[state]); + IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __FUNCTION__, irlsap_state[state]); */ self->lsap_state = state; } @@ -143,8 +143,8 @@ ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n", - irlmp_event[event], irlsap_state[ self->lsap_state]); + IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", + __FUNCTION__, irlmp_event[event], irlsap_state[ self->lsap_state]); return (*lsap_state[self->lsap_state]) (self, event, skb); } @@ -161,16 +161,16 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LAP_MAGIC, return;); - IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n", - irlmp_event[event], - irlmp_state[self->lap_state]); + IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", + __FUNCTION__, irlmp_event[event], + irlmp_state[self->lap_state]); (*lap_state[self->lap_state]) (self, event, skb); } void irlmp_discovery_timer_expired(void *data) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); /* We always cleanup the log (active & passive discovery) */ irlmp_do_expiry(); @@ -187,7 +187,7 @@ { struct lsap_cb *self = (struct lsap_cb *) data; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -199,7 +199,7 @@ { struct lap_cb *self = (struct lap_cb *) data; - IRDA_DEBUG(2, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LAP_MAGIC, return;); @@ -222,7 +222,7 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self->irlap != NULL, return;); switch (event) { @@ -242,7 +242,7 @@ irlap_connect_response(self->irlap, skb); break; case LM_LAP_CONNECT_REQUEST: - IRDA_DEBUG(4, __FUNCTION__ "() LS_CONNECT_REQUEST\n"); + IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __FUNCTION__); irlmp_next_lap_state(self, LAP_U_CONNECT); @@ -250,14 +250,12 @@ irlap_connect_request(self->irlap, self->daddr, NULL, 0); break; case LM_LAP_DISCONNECT_INDICATION: - IRDA_DEBUG(4, __FUNCTION__ - "(), Error LM_LAP_DISCONNECT_INDICATION\n"); + IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n", __FUNCTION__); irlmp_next_lap_state(self, LAP_STANDBY); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(0, "%s(), Unknown event %s\n", __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; @@ -277,7 +275,7 @@ struct lsap_cb *lsap; struct lsap_cb *lsap_current; - IRDA_DEBUG(2, __FUNCTION__ "(), event=%s\n", irlmp_event[event]); + IRDA_DEBUG(2, "%s(), event=%s\n", __FUNCTION__, irlmp_event[event]); switch (event) { case LM_LAP_CONNECT_INDICATION: @@ -299,7 +297,7 @@ * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ if (HASHBIN_GET_SIZE(self->lsaps) == 0) { - IRDA_DEBUG(0, __FUNCTION__ "() NO LSAPs !\n"); + IRDA_DEBUG(0, "%s() NO LSAPs !\n", __FUNCTION__); irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); } break; @@ -319,12 +317,12 @@ * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ if (HASHBIN_GET_SIZE(self->lsaps) == 0) { - IRDA_DEBUG(0, __FUNCTION__ "() NO LSAPs !\n"); + IRDA_DEBUG(0, "%s() NO LSAPs !\n", __FUNCTION__); irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); } break; case LM_LAP_DISCONNECT_INDICATION: - IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_INDICATION\n"); + IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n", __FUNCTION__); irlmp_next_lap_state(self, LAP_STANDBY); /* Send disconnect event to all LSAPs using this link */ @@ -342,7 +340,7 @@ } break; case LM_LAP_DISCONNECT_REQUEST: - IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n"); + IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n", __FUNCTION__); /* One of the LSAP did timeout or was closed, if it was * the last one, try to get out of here - Jean II */ @@ -351,8 +349,8 @@ } break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(0, "%s(), Unknown event %s\n", + __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; @@ -371,11 +369,11 @@ struct lsap_cb *lsap; struct lsap_cb *lsap_current; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); switch (event) { case LM_LAP_CONNECT_REQUEST: - IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_REQUEST\n"); + IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __FUNCTION__); /* * LAP connection allready active, just bounce back! Since we @@ -470,8 +468,8 @@ irlmp_do_expiry(); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(0, "%s(), Unknown event %s\n", + __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; @@ -495,7 +493,7 @@ { int ret = 0; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); @@ -507,11 +505,10 @@ break; #endif /* CONFIG_IRDA_ULTRA */ case LM_CONNECT_REQUEST: - IRDA_DEBUG(4, __FUNCTION__ "(), LM_CONNECT_REQUEST\n"); + IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __FUNCTION__); if (self->conn_skb) { - WARNING(__FUNCTION__ - "(), busy with another request!\n"); + WARNING("%s(), busy with another request!\n", __FUNCTION__); return -EBUSY; } self->conn_skb = skb; @@ -525,8 +522,7 @@ break; case LM_CONNECT_INDICATION: if (self->conn_skb) { - WARNING(__FUNCTION__ - "(), busy with another request!\n"); + WARNING("%s(), busy with another request!\n", __FUNCTION__); return -EBUSY; } self->conn_skb = skb; @@ -549,8 +545,8 @@ irlmp_start_watchdog_timer(self, 1*HZ); break; default: - IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(2, "%s(), Unknown event %s\n", + __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; @@ -570,7 +566,7 @@ struct lsap_cb *lsap; int ret = 0; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); @@ -601,15 +597,15 @@ case LM_WATCHDOG_TIMEOUT: /* May happen, who knows... * Jean II */ - IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); + IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__); /* Disconnect, get out... - Jean II */ self->dlsap_sel = LSAP_ANY; irlmp_next_lsap_state(self, LSAP_DISCONNECTED); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(0, "%s(), Unknown event %s\n", + __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; @@ -628,7 +624,7 @@ { int ret = 0; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); @@ -638,17 +634,17 @@ /* Keep state */ break; case LM_CONNECT_RESPONSE: - IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " - "no indication issued yet\n"); + IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, " + "no indication issued yet\n", __FUNCTION__); /* Keep state */ break; case LM_DISCONNECT_REQUEST: - IRDA_DEBUG(0, __FUNCTION__ "(), LM_DISCONNECT_REQUEST, " - "not yet bound to IrLAP connection\n"); + IRDA_DEBUG(0, "%s(), LM_DISCONNECT_REQUEST, " + "not yet bound to IrLAP connection\n", __FUNCTION__); /* Keep state */ break; case LM_LAP_CONNECT_CONFIRM: - IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_CONFIRM\n"); + IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __FUNCTION__); irlmp_next_lsap_state(self, LSAP_CONNECT); skb = self->conn_skb; @@ -660,7 +656,7 @@ /* Will happen in some rare cases because of a race condition. * Just make sure we don't stay there forever... * Jean II */ - IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); + IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__); /* Go back to disconnected mode, keep the socket waiting */ self->dlsap_sel = LSAP_ANY; @@ -670,8 +666,8 @@ irlmp_next_lsap_state(self, LSAP_DISCONNECTED); break; default: - IRDA_DEBUG(0, __FUNCTION__ "Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(0, "%s() Unknown event %s\n", + __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; @@ -691,7 +687,7 @@ LM_REASON reason; int ret = 0; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); @@ -714,13 +710,13 @@ irlmp_udata_indication(self, skb); break; case LM_CONNECT_REQUEST: - IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_REQUEST, " - "error, LSAP already connected\n"); + IRDA_DEBUG(0, "%s(), LM_CONNECT_REQUEST, " + "error, LSAP already connected\n", __FUNCTION__); /* Keep state */ break; case LM_CONNECT_RESPONSE: - IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " - "error, LSAP allready connected\n"); + IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, " + "error, LSAP allready connected\n", __FUNCTION__); /* Keep state */ break; case LM_DISCONNECT_REQUEST: @@ -730,7 +726,7 @@ /* Try to close the LAP connection if its still there */ if (self->lap) { - IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n"); + IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __FUNCTION__); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); @@ -754,14 +750,14 @@ reason = skb->data[3]; /* Try to close the LAP connection */ - IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n"); + IRDA_DEBUG(4, "%ss(), trying to close IrLAP\n", __FUNCTION__); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); irlmp_disconnect_indication(self, reason, skb); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(0, "%s(), Unknown event %s\n", + __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; @@ -785,7 +781,7 @@ ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); switch (event) { case LM_CONNECT_CONFIRM: @@ -806,7 +802,7 @@ reason = skb->data[3]; /* Try to close the LAP connection */ - IRDA_DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n"); + IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __FUNCTION__); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); irlmp_disconnect_indication(self, reason, skb); @@ -824,7 +820,7 @@ irlmp_disconnect_indication(self, reason, skb); break; case LM_WATCHDOG_TIMEOUT: - IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); + IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__); ASSERT(self->lap != NULL, return -1;); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); @@ -833,8 +829,8 @@ irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(0, "%s(), Unknown event %s\n", + __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; @@ -856,7 +852,7 @@ LM_REASON reason; int ret = 0; - IRDA_DEBUG(4, __FUNCTION__ "()\n"); + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); ASSERT(self != NULL, return -1;); ASSERT(irlmp != NULL, return -1;); @@ -874,7 +870,7 @@ irlmp_next_lsap_state(self, LSAP_SETUP); break; case LM_WATCHDOG_TIMEOUT: - IRDA_DEBUG(0, __FUNCTION__ "() : WATCHDOG_TIMEOUT !\n"); + IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n", __FUNCTION__); ASSERT(self->lap != NULL, return -1;); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); @@ -892,8 +888,8 @@ irlmp_disconnect_indication(self, reason, NULL); break; default: - IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", - irlmp_event[event]); + IRDA_DEBUG(0, "%s(), Unknown event %s\n", + __FUNCTION__, irlmp_event[event]); if (skb) dev_kfree_skb(skb); break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/irda/irsyms.c linux.20pre2-ac1/net/irda/irsyms.c --- linux.20pre2/net/irda/irsyms.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/irda/irsyms.c 2002-08-06 15:41:57.000000000 +0100 @@ -171,7 +171,7 @@ int __init irda_init(void) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); irlmp_init(); irlap_init(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_actn.c linux.20pre2-ac1/net/llc/llc_actn.c --- linux.20pre2/net/llc/llc_actn.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_actn.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,147 @@ +/* + * llc_actn.c - Implementation of actions of station component of LLC + * + * Description : + * Functions in this module are implementation of station component actions. + * Details of actions can be found in IEEE-802.2 standard document. + * All functions have one station and one event as input argument. All of + * them return 0 On success and 1 otherwise. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include + +static void llc_station_ack_tmr_callback(unsigned long timeout_data); + +int llc_station_ac_start_ack_timer(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + del_timer(&station->ack_timer); + station->ack_timer.expires = jiffies + LLC_ACK_TIME * HZ; + station->ack_timer.data = (unsigned long)station; + station->ack_timer.function = llc_station_ack_tmr_callback; + add_timer(&station->ack_timer); + station->ack_tmr_running = 1; + return 0; +} + +int llc_station_ac_set_retry_cnt_0(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + station->retry_count = 0; + return 0; +} + +int llc_station_ac_inc_retry_cnt_by_1(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + station->retry_count++; + return 0; +} + +int llc_station_ac_set_xid_r_cnt_0(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + station->xid_r_count = 0; + return 0; +} + +int llc_station_ac_inc_xid_r_cnt_by_1(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + station->xid_r_count++; + return 0; +} + +int llc_station_ac_send_null_dsap_xid_c(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (!skb) + goto out; + rc = 0; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD); + llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 127); + lan_hdrs_init(skb, station->mac_sa, station->mac_sa); + llc_station_send_pdu(station, skb); +out: return rc; +} + +int llc_station_ac_send_xid_r(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + u8 mac_da[ETH_ALEN], dsap; + int rc = 1; + struct sk_buff *ev_skb; + struct sk_buff* skb = llc_alloc_frame(); + + if (!skb) + goto out; + rc = 0; + ev_skb = ev->data.pdu.skb; + skb->dev = ev_skb->dev; + llc_pdu_decode_sa(ev_skb, mac_da); + llc_pdu_decode_ssap(ev_skb, &dsap); + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP); + llc_pdu_init_as_xid_rsp(skb, LLC_XID_NULL_CLASS_2, 127); + lan_hdrs_init(skb, station->mac_sa, mac_da); + llc_station_send_pdu(station, skb); +out: return rc; +} + +int llc_station_ac_send_test_r(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + u8 mac_da[ETH_ALEN], dsap; + int rc = 1; + struct sk_buff *ev_skb; + struct sk_buff *skb = llc_alloc_frame(); + + if (!skb) + goto out; + rc = 0; + ev_skb = ev->data.pdu.skb; + skb->dev = ev_skb->dev; + llc_pdu_decode_sa(ev_skb, mac_da); + llc_pdu_decode_ssap(ev_skb, &dsap); + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP); + llc_pdu_init_as_test_rsp(skb, ev_skb); + lan_hdrs_init(skb, station->mac_sa, mac_da); + llc_station_send_pdu(station, skb); +out: return rc; +} + +int llc_station_ac_report_status(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + return 0; +} + +static void llc_station_ack_tmr_callback(unsigned long timeout_data) +{ + struct llc_station *station = (struct llc_station *)timeout_data; + struct llc_station_state_ev *ev; + + station->ack_tmr_running = 0; + ev = llc_station_alloc_ev(station); + if (ev) { + ev->type = LLC_STATION_EV_TYPE_ACK_TMR; + ev->data.tmr.timer_specific = NULL; + llc_station_send_ev(station, ev); + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_c_ac.c linux.20pre2-ac1/net/llc/llc_c_ac.c --- linux.20pre2/net/llc/llc_c_ac.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_c_ac.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,1645 @@ +/* + * llc_c_ac.c - actions performed during connection state transition. + * + * Description: + * Functions in this module are implementation of connection component actions + * Details of actions can be found in IEEE-802.2 standard document. + * All functions have one connection and one event as input argument. All of + * them return 0 On success and 1 otherwise. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data); +static void llc_conn_ack_tmr_cb(unsigned long timeout_data); +static void llc_conn_rej_tmr_cb(unsigned long timeout_data); +static void llc_conn_busy_tmr_cb(unsigned long timeout_data); +static int llc_conn_ac_inc_vs_by_1(struct sock *sk, + struct llc_conn_state_ev *ev); +static void llc_process_tmr_ev(struct sock *sk, struct llc_conn_state_ev *ev); +static int llc_conn_ac_data_confirm(struct sock *sk, + struct llc_conn_state_ev *ev); + +#define INCORRECT 0 + +int llc_conn_ac_clear_remote_busy(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + if (llc->remote_busy_flag) { + u8 nr; + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + llc->remote_busy_flag = 0; + del_timer(&llc->busy_state_timer.timer); + llc->busy_state_timer.running = 0; + nr = LLC_I_GET_NR(rx_pdu); + llc_conn_resend_i_pdu_as_cmd(sk, nr, 0); + } + return 0; +} + +int llc_conn_ac_conn_ind(struct sock *sk, struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = ev->data.pdu.skb; + union llc_u_prim_data *prim_data = llc_ind_prim.data; + struct llc_prim_if_block *prim = &llc_ind_prim; + struct llc_sap *sap; + struct llc_opt *llc = llc_sk(sk); + + llc_pdu_decode_dsap(skb, &prim_data->conn.daddr.lsap); + sap = llc_sap_find(prim_data->conn.daddr.lsap); + if (sap) { + llc_pdu_decode_sa(skb, llc->daddr.mac); + llc_pdu_decode_da(skb, llc->laddr.mac); + llc->dev = skb->dev; + prim_data->conn.pri = 0; + prim_data->conn.sk = sk; + prim_data->conn.dev = skb->dev; + memcpy(&prim_data->conn.daddr, &llc->laddr, sizeof(llc->laddr)); + memcpy(&prim_data->conn.saddr, &llc->daddr, sizeof(llc->daddr)); + prim->data = prim_data; + prim->prim = LLC_CONN_PRIM; + prim->sap = llc->sap; + ev->flag = 1; + ev->ind_prim = prim; + rc = 0; + } + return rc; +} + +int llc_conn_ac_conn_confirm(struct sock *sk, struct llc_conn_state_ev *ev) +{ + union llc_u_prim_data *prim_data = llc_cfm_prim.data; + struct sk_buff *skb = ev->data.pdu.skb; + /* FIXME: wtf, this is global, so the whole thing is really non + * reentrant... */ + struct llc_prim_if_block *prim = &llc_cfm_prim; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + prim_data->conn.sk = sk; + prim_data->conn.pri = 0; + prim_data->conn.status = ev->status; + prim_data->conn.link = llc->link; + if (skb) + prim_data->conn.dev = skb->dev; + else + printk(KERN_ERR __FUNCTION__ "ev->data.pdu.skb == NULL\n"); + prim->data = prim_data; + prim->prim = LLC_CONN_PRIM; + prim->sap = sap; + ev->flag = 1; + ev->cfm_prim = prim; + return 0; +} + +static int llc_conn_ac_data_confirm(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + struct llc_prim_if_block *prim = &llc_cfm_prim; + union llc_u_prim_data *prim_data = llc_cfm_prim.data; + + prim_data->data.sk = sk; + prim_data->data.pri = 0; + prim_data->data.link = llc_sk(sk)->link; + prim_data->data.status = LLC_STATUS_RECEIVED; + prim_data->data.skb = NULL; + prim->data = prim_data; + prim->prim = LLC_DATA_PRIM; + prim->sap = llc_sk(sk)->sap; + ev->flag = 1; + ev->cfm_prim = prim; + return 0; +} + +int llc_conn_ac_data_ind(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_conn_rtn_pdu(sk, ev->data.pdu.skb, ev); + return 0; +} + +int llc_conn_ac_disc_ind(struct sock *sk, struct llc_conn_state_ev *ev) +{ + u8 reason = 0; + int rc = 1; + union llc_u_prim_data *prim_data = llc_ind_prim.data; + struct llc_prim_if_block *prim = &llc_ind_prim; + + if (ev->type == LLC_CONN_EV_TYPE_PDU) { + llc_pdu_un_t *rx_pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + if (!LLC_PDU_IS_RSP(rx_pdu) && + !LLC_PDU_TYPE_IS_U(rx_pdu) && + LLC_U_PDU_RSP(rx_pdu) == LLC_2_PDU_RSP_DM) { + reason = LLC_DISC_REASON_RX_DM_RSP_PDU; + rc = 0; + } else if (!LLC_PDU_IS_CMD(rx_pdu) && + !LLC_PDU_TYPE_IS_U(rx_pdu) && + LLC_U_PDU_CMD(rx_pdu) == LLC_2_PDU_CMD_DISC) { + reason = LLC_DISC_REASON_RX_DISC_CMD_PDU; + rc = 0; + } + } else if (ev->type == LLC_CONN_EV_TYPE_ACK_TMR) { + reason = LLC_DISC_REASON_ACK_TMR_EXP; + rc = 0; + } else { + reason = 0; + rc = 1; + } + if (!rc) { + prim_data->disc.sk = sk; + prim_data->disc.reason = reason; + prim_data->disc.link = llc_sk(sk)->link; + prim->data = prim_data; + prim->prim = LLC_DISC_PRIM; + prim->sap = llc_sk(sk)->sap; + ev->flag = 1; + ev->ind_prim = prim; + } + return rc; +} + +int llc_conn_ac_disc_confirm(struct sock *sk, struct llc_conn_state_ev *ev) +{ + union llc_u_prim_data *prim_data = llc_cfm_prim.data; + struct llc_prim_if_block *prim = &llc_cfm_prim; + + prim_data->disc.sk = sk; + prim_data->disc.reason = ev->status; + prim_data->disc.link = llc_sk(sk)->link; + prim->data = prim_data; + prim->prim = LLC_DISC_PRIM; + prim->sap = llc_sk(sk)->sap; + ev->flag = 1; + ev->cfm_prim = prim; + return 0; +} + +int llc_conn_ac_rst_ind(struct sock *sk, struct llc_conn_state_ev *ev) +{ + u8 reason = 0; + int rc = 1; + llc_pdu_un_t *rx_pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + union llc_u_prim_data *prim_data = llc_ind_prim.data; + struct llc_prim_if_block *prim = &llc_ind_prim; + struct llc_opt *llc = llc_sk(sk); + + switch (ev->type) { + case LLC_CONN_EV_TYPE_PDU: + if (!LLC_PDU_IS_RSP(rx_pdu) && + !LLC_PDU_TYPE_IS_U(rx_pdu) && + LLC_U_PDU_RSP(rx_pdu) == LLC_2_PDU_RSP_FRMR) { + reason = LLC_RESET_REASON_LOCAL; + rc = 0; + } else if (!LLC_PDU_IS_CMD(rx_pdu) && + !LLC_PDU_TYPE_IS_U(rx_pdu) && + LLC_U_PDU_CMD(rx_pdu) == + LLC_2_PDU_CMD_SABME) { + reason = LLC_RESET_REASON_REMOTE; + rc = 0; + } else { + reason = 0; + rc = 1; + } + break; + case LLC_CONN_EV_TYPE_ACK_TMR: + case LLC_CONN_EV_TYPE_P_TMR: + case LLC_CONN_EV_TYPE_REJ_TMR: + case LLC_CONN_EV_TYPE_BUSY_TMR: + if (llc->retry_count > llc->n2) { + reason = LLC_RESET_REASON_LOCAL; + rc = 0; + } else + rc = 1; + break; + } + if (!rc) { + prim_data->res.sk = sk; + prim_data->res.reason = reason; + prim_data->res.link = llc->link; + prim->data = prim_data; + prim->prim = LLC_RESET_PRIM; + prim->sap = llc->sap; + ev->flag = 1; + ev->ind_prim = prim; + } + return rc; +} + +int llc_conn_ac_rst_confirm(struct sock *sk, struct llc_conn_state_ev *ev) +{ + union llc_u_prim_data *prim_data = llc_cfm_prim.data; + struct llc_prim_if_block *prim = &llc_cfm_prim; + + prim_data->res.sk = sk; + prim_data->res.link = llc_sk(sk)->link; + prim->data = prim_data; + prim->prim = LLC_RESET_PRIM; + prim->sap = llc_sk(sk)->sap; + ev->flag = 1; + ev->cfm_prim = prim; + return 0; +} + +int llc_conn_ac_report_status(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return 0; +} + +int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + if (!LLC_PDU_IS_RSP(rx_pdu) && + !LLC_PDU_TYPE_IS_I(rx_pdu) && + !LLC_I_PF_IS_1(rx_pdu) && llc_sk(sk)->ack_pf) + llc_conn_ac_clear_remote_busy(sk, ev); + return 0; +} + +int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + if (llc_sk(sk)->data_flag == 2) { + del_timer(&llc_sk(sk)->rej_sent_timer.timer); + llc_sk(sk)->rej_sent_timer.running = 0; + } + return 0; +} + +int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + u8 p_bit = 1; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_disc_cmd(skb, p_bit); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + llc_conn_ac_set_p_flag_1(sk, ev); + return rc; +} + +int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + struct sk_buff *rx_skb = ev->data.pdu.skb; + u8 f_bit; + + skb->dev = llc->dev; + llc_pdu_decode_pf_bit(rx_skb, &f_bit); + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_dm_rsp(skb, f_bit); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = 1; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_dm_rsp(skb, f_bit); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = llc->f_flag; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_dm_rsp(skb, f_bit); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u8 f_bit; + int rc = 1; + struct sk_buff *skb, *ev_skb = ev->data.pdu.skb; + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev_skb->nh.raw; + struct llc_opt *llc = llc_sk(sk); + + llc->rx_pdu_hdr = (u32)*((u32 *)rx_pdu); + if (!LLC_PDU_IS_CMD(rx_pdu)) + llc_pdu_decode_pf_bit(ev_skb, &f_bit); + else + f_bit = 0; + skb = llc_alloc_frame(); + if (skb) { + struct llc_sap *sap = llc->sap; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_frmr_rsp(skb, rx_pdu, f_bit, llc->vS, + llc->vR, INCORRECT); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + u8 f_bit = 0; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)&llc->rx_pdu_hdr; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_frmr_rsp(skb, rx_pdu, f_bit, llc->vS, + llc->vR, INCORRECT); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u8 f_bit; + int rc = 1; + struct sk_buff *skb; + + llc_pdu_decode_pf_bit(ev->data.pdu.skb, &f_bit); + skb = llc_alloc_frame(); + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_frmr_rsp(skb, rx_pdu, f_bit, llc->vS, + llc->vR, INCORRECT); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u8 p_bit = 1; + struct sk_buff *skb = ev->data.prim.data->data->data.skb; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + llc_conn_send_pdu(sk, skb); + llc_conn_ac_inc_vs_by_1(sk, ev); + return 0; +} + +int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u8 p_bit = 0; + struct sk_buff *skb = ev->data.prim.data->data->data.skb; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + llc_conn_send_pdu(sk, skb); + llc_conn_ac_inc_vs_by_1(sk, ev); + return 0; +} + +int llc_conn_ac_resend_i_cmd_p_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + u8 nr = LLC_I_GET_NR(rx_pdu); + + llc_conn_resend_i_pdu_as_cmd(sk, nr, 1); + return 0; +} + +int llc_conn_ac_resend_i_cmd_p_set_1_or_send_rr(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + u8 nr = LLC_I_GET_NR(rx_pdu); + int rc = llc_conn_ac_send_rr_cmd_p_set_1(sk, ev); + + if (!rc) + llc_conn_resend_i_pdu_as_cmd(sk, nr, 0); + return rc; +} + +int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u8 p_bit = 0; + struct sk_buff *skb = ev->data.prim.data->data->data.skb; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + llc_conn_send_pdu(sk, skb); + llc_conn_ac_inc_vs_by_1(sk, ev); + return 0; +} + +int llc_conn_ac_resend_i_xxx_x_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 nr = LLC_I_GET_NR(rx_pdu); + + llc_conn_resend_i_pdu_as_cmd(sk, nr, 0); + return 0; +} + +int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u8 nr; + u8 f_bit = 0; + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + if (rc) { + nr = LLC_I_GET_NR(rx_pdu); + rc = 0; + llc_conn_resend_i_pdu_as_cmd(sk, nr, f_bit); + } + return rc; +} + +int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 nr = LLC_I_GET_NR(rx_pdu); + + llc_conn_resend_i_pdu_as_rsp(sk, nr, 1); + return 0; +} + +int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 p_bit = 1; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_rej_cmd(skb, p_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + u8 f_bit = 1; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rej_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = 0; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rej_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 p_bit = 1; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_rnr_cmd(skb, p_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = 1; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + u8 f_bit = 0; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_set_remote_busy(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + if (!llc->remote_busy_flag) { + llc->remote_busy_flag = 1; + llc->busy_state_timer.timer.expires = jiffies + + llc->busy_state_timer.expire * HZ; + llc->busy_state_timer.timer.data = (unsigned long)sk; + llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb; + add_timer(&llc->busy_state_timer.timer); + llc->busy_state_timer.running = 1; + } + return 0; +} + +int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = 0; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + u8 p_bit = 1; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_rr_cmd(skb, p_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_ack_cmd_p_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + u8 p_bit = 1; + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_rr_cmd(skb, p_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = 1; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = 1; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = 0; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = 0; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + struct llc_opt *llc = llc_sk(sk); + u8 p_bit = 1; + + if (skb) { + struct llc_sap *sap = llc->sap; + u8 *dmac = llc->daddr.mac; + + if (llc->dev->flags & IFF_LOOPBACK) + dmac = llc->dev->dev_addr; + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_CMD); + llc_pdu_init_as_sabme_cmd(skb, p_bit); + lan_hdrs_init(skb, llc->dev->dev_addr, dmac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + llc->p_flag = p_bit; + return rc; +} + +int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = llc->f_flag; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_ua_rsp(skb, f_bit); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u8 f_bit; + int rc = 1; + struct sk_buff *rx_skb = ev->data.pdu.skb; + struct sk_buff *skb; + + llc_pdu_decode_pf_bit(rx_skb, &f_bit); + skb = llc_alloc_frame(); + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_ua_rsp(skb, f_bit); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +int llc_conn_ac_set_s_flag_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->s_flag = 0; + return 0; +} + +int llc_conn_ac_set_s_flag_1(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->s_flag = 1; + return 0; +} + +int llc_conn_ac_start_p_timer(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + llc->p_flag = 1; + del_timer(&llc->pf_cycle_timer.timer); + llc->pf_cycle_timer.timer.expires = jiffies + + llc->pf_cycle_timer.expire * HZ; + llc->pf_cycle_timer.timer.data = (unsigned long)sk; + llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb; + add_timer(&llc->pf_cycle_timer.timer); + llc->pf_cycle_timer.running = 1; + return 0; +} + +/** + * llc_conn_ac_send_ack_if_needed - check if ack is needed + * @sk: current connection structure + * @ev: current event + * + * Checks number of received PDUs which have not been acknowledged, yet, + * If number of them reaches to "npta"(Number of PDUs To Acknowledge) then + * sends an RR response as acknowledgement for them. Returns 0 for + * success, 1 otherwise. + */ +int llc_conn_ac_send_ack_if_needed(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u8 pf_bit; + struct sk_buff *skb = ev->data.pdu.skb; + struct llc_opt *llc = llc_sk(sk); + + llc_pdu_decode_pf_bit(skb, &pf_bit); + llc->ack_pf |= pf_bit & 1; + if (!llc->ack_must_be_send) { + llc->first_pdu_Ns = llc->vR; + llc->ack_must_be_send = 1; + llc->ack_pf = pf_bit & 1; + } + if (((llc->vR - llc->first_pdu_Ns + 129) % 128) >= llc->npta) { + llc_conn_ac_send_rr_rsp_f_set_ackpf(sk, ev); + llc->ack_must_be_send = 0; + llc->ack_pf = 0; + llc_conn_ac_inc_npta_value(sk, ev); + } + return 0; +} + +/** + * llc_conn_ac_rst_sendack_flag - resets ack_must_be_send flag + * @sk: current connection structure + * @ev: current event + * + * This action resets ack_must_be_send flag of given connection, this flag + * indicates if there is any PDU which has not been acknowledged yet. + * Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_rst_sendack_flag(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->ack_must_be_send = llc_sk(sk)->ack_pf = 0; + return 0; +} + +/** + * llc_conn_ac_send_i_rsp_f_set_ackpf - acknowledge received PDUs + * @sk: current connection structure + * @ev: current event + * + * Sends an I response PDU with f-bit set to ack_pf flag as acknowledge to + * all received PDUs which have not been acknowledged, yet. ack_pf flag is + * set to one if one PDU with p-bit set to one is received. Returns 0 for + * success, 1 otherwise. + */ +int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + struct sk_buff *skb = ev->data.prim.data->data->data.skb; + struct llc_opt *llc = llc_sk(sk); + u8 p_bit = llc->ack_pf; + struct llc_sap *sap = llc->sap; + + llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + llc_conn_send_pdu(sk, skb); + llc_conn_ac_inc_vs_by_1(sk, ev); + return 0; +} + +/** + * llc_conn_ac_send_i_as_ack - sends an I-format PDU to acknowledge rx PDUs + * @sk: current connection structure. + * @ev: current event. + * + * This action sends an I-format PDU as acknowledge to received PDUs which + * have not been acknowledged, yet, if there is any. By using of this + * action number of acknowledgements decreases, this technic is called + * piggy backing. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_send_i_as_ack(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + if (llc->ack_must_be_send) { + llc_conn_ac_send_i_rsp_f_set_ackpf(sk, ev); + llc->ack_must_be_send = 0 ; + llc->ack_pf = 0; + } else + llc_conn_ac_send_i_cmd_p_set_0(sk, ev); + return 0; +} + +/** + * llc_conn_ac_send_rr_rsp_f_set_ackpf - ack all rx PDUs not yet acked + * @sk: current connection structure. + * @ev: current event. + * + * This action sends an RR response with f-bit set to ack_pf flag as + * acknowledge to all received PDUs which have not been acknowledged, yet, + * if there is any. ack_pf flag indicates if a PDU has been received with + * p-bit set to one. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct sk_buff *skb = llc_alloc_frame(); + + if (skb) { + struct llc_opt *llc = llc_sk(sk); + struct llc_sap *sap = llc->sap; + u8 f_bit = llc->ack_pf; + + skb->dev = llc->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap, + llc->daddr.lsap, LLC_PDU_RSP); + llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR); + lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); + rc = 0; + llc_conn_send_pdu(sk, skb); + } + return rc; +} + +/** + * llc_conn_ac_inc_npta_value - tries to make value of npta greater + * @sk: current connection structure. + * @ev: current event. + * + * After "inc_cntr" times calling of this action, "npta" increase by one. + * this action tries to make vale of "npta" greater as possible; number of + * acknowledgements decreases by increasing of "npta". Returns 0 for + * success, 1 otherwise. + */ +int llc_conn_ac_inc_npta_value(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + if (!llc->inc_cntr) { + llc->dec_step = 0; + llc->dec_cntr = llc->inc_cntr = 2; + ++llc->npta; + if (llc->npta > 127) + llc->npta = 127 ; + } else + --llc->inc_cntr; + return 0; +} + +/** + * llc_conn_ac_adjust_npta_by_rr - decreases "npta" by one + * @sk: current connection structure. + * @ev: current event. + * + * After receiving "dec_cntr" times RR command, this action decreases + * "npta" by one. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_adjust_npta_by_rr(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + if (!llc->connect_step && !llc->remote_busy_flag) { + if (!llc->dec_step) { + if (!llc->dec_cntr) { + llc->inc_cntr = llc->dec_cntr = 2; + if (llc->npta > 0) + llc->npta = llc->npta - 1; + } else + llc->dec_cntr -=1; + } + } else + llc->connect_step = 0 ; + return 0; +} + +/** + * llc_conn_ac_adjust_npta_by_rnr - decreases "npta" by one + * @sk: current connection structure. + * @ev: current event. + * + * After receiving "dec_cntr" times RNR command, this action decreases + * "npta" by one. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_adjust_npta_by_rnr(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + if (llc->remote_busy_flag) + if (!llc->dec_step) { + if (!llc->dec_cntr) { + llc->inc_cntr = llc->dec_cntr = 2; + if (llc->npta > 0) + --llc->npta; + } else + --llc->dec_cntr; + } + return 0; +} + +/** + * llc_conn_ac_dec_tx_win_size - decreases tx window size + * @sk: current connection structure. + * @ev: current event. + * + * After receiving of a REJ command or response, transmit window size is + * decreased by number of PDUs which are outstanding yet. Returns 0 for + * success, 1 otherwise. + */ +int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + u8 unacked_pdu = skb_queue_len(&llc->pdu_unack_q); + + llc->k -= unacked_pdu; + if (llc->k < 2) + llc->k = 2; + return 0; +} + +/** + * llc_conn_ac_inc_tx_win_size - tx window size is inc by 1 + * @sk: current connection structure. + * @ev: current event. + * + * After receiving an RR response with f-bit set to one, transmit window + * size is increased by one. Returns 0 for success, 1 otherwise. + */ +int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + llc->k += 1; + if (llc->k > 128) + llc->k = 128 ; + return 0; +} + +int llc_conn_ac_stop_all_timers(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + del_timer(&llc->pf_cycle_timer.timer); + llc->pf_cycle_timer.running = 0; + del_timer(&llc->ack_timer.timer); + llc->ack_timer.running = 0; + del_timer(&llc->rej_sent_timer.timer); + llc->rej_sent_timer.running = 0; + del_timer(&llc->busy_state_timer.timer); + llc->busy_state_timer.running = 0; + llc->ack_must_be_send = 0; + llc->ack_pf = 0; + return 0; +} + +int llc_conn_ac_stop_other_timers(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + del_timer(&llc->rej_sent_timer.timer); + llc->rej_sent_timer.running = 0; + del_timer(&llc->pf_cycle_timer.timer); + llc->pf_cycle_timer.running = 0; + del_timer(&llc->busy_state_timer.timer); + llc->busy_state_timer.running = 0; + llc->ack_must_be_send = 0; + llc->ack_pf = 0; + return 0; +} + +int llc_conn_ac_start_ack_timer(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + del_timer(&llc->ack_timer.timer); + llc->ack_timer.timer.expires = jiffies + llc->ack_timer.expire * HZ; + llc->ack_timer.timer.data = (unsigned long)sk; + llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; + add_timer(&llc->ack_timer.timer); + llc->ack_timer.running = 1; + return 0; +} + +int llc_conn_ac_start_rej_timer(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + del_timer(&llc->rej_sent_timer.timer); + llc->rej_sent_timer.timer.expires = jiffies + + llc->rej_sent_timer.expire * HZ; + llc->rej_sent_timer.timer.data = (unsigned long)sk; + llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb; + add_timer(&llc->rej_sent_timer.timer); + llc->rej_sent_timer.running = 1; + return 0; +} + +int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + if (!llc->ack_timer.running) { + llc->ack_timer.timer.expires = jiffies + + llc->ack_timer.expire * HZ; + llc->ack_timer.timer.data = (unsigned long)sk; + llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; + add_timer(&llc->ack_timer.timer); + llc->ack_timer.running = 1; + } + return 0; +} + +int llc_conn_ac_stop_ack_timer(struct sock *sk, struct llc_conn_state_ev *ev) +{ + del_timer(&llc_sk(sk)->ack_timer.timer); + llc_sk(sk)->ack_timer.running = 0; + return 0; +} + +int llc_conn_ac_stop_p_timer(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_opt *llc = llc_sk(sk); + + del_timer(&llc->pf_cycle_timer.timer); + llc->pf_cycle_timer.running = 0; + llc->p_flag = 0; + return 0; +} + +int llc_conn_ac_stop_rej_timer(struct sock *sk, struct llc_conn_state_ev *ev) +{ + del_timer(&llc_sk(sk)->rej_sent_timer.timer); + llc_sk(sk)->rej_sent_timer.running = 0; + return 0; +} + +int llc_conn_ac_upd_nr_received(struct sock *sk, struct llc_conn_state_ev *ev) +{ + int acked; + u16 unacked = 0; + u8 fbit; + struct sk_buff *skb = ev->data.pdu.skb; + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)skb->nh.raw; + struct llc_opt *llc = llc_sk(sk); + + llc->last_nr = PDU_SUPV_GET_Nr(rx_pdu); + acked = llc_conn_remove_acked_pdus(sk, llc->last_nr, &unacked); + /* On loopback we don't queue I frames in unack_pdu_q queue. */ + if (acked > 0 || (llc->dev->flags & IFF_LOOPBACK)) { + llc->retry_count = 0; + del_timer(&llc->ack_timer.timer); + llc->ack_timer.running = 0; + if (llc->failed_data_req) { + /* already, we did not accept data from upper + * layer(tx_window full or unacceptable state). now, we + * can send data and must inform to upper layer. */ + llc->failed_data_req = 0; + llc_conn_ac_data_confirm(sk, ev); + } + if (unacked) { + llc->ack_timer.timer.expires = jiffies + + llc->ack_timer.expire * HZ; + llc->ack_timer.timer.data = (unsigned long)sk; + llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; + add_timer(&llc->ack_timer.timer); + llc->ack_timer.running = 1; + } + } else if (llc->failed_data_req) { + llc_pdu_decode_pf_bit(skb, &fbit); + if (fbit == 1) { + llc->failed_data_req = 0; + llc_conn_ac_data_confirm(sk, ev); + } + } + return 0; +} + +int llc_conn_ac_upd_p_flag(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct sk_buff *skb = ev->data.pdu.skb; + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)skb->nh.raw; + u8 f_bit; + + if (!LLC_PDU_IS_RSP(rx_pdu) && + !llc_pdu_decode_pf_bit(skb, &f_bit) && f_bit) { + llc_sk(sk)->p_flag = 0; + llc_conn_ac_stop_p_timer(sk, ev); + } + return 0; +} + +int llc_conn_ac_set_data_flag_2(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->data_flag = 2; + return 0; +} + +int llc_conn_ac_set_data_flag_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->data_flag = 0; + return 0; +} + +int llc_conn_ac_set_data_flag_1(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->data_flag = 1; + return 0; +} + +int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + if (!llc_sk(sk)->data_flag) + llc_sk(sk)->data_flag = 1; + return 0; +} + +int llc_conn_ac_set_p_flag_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->p_flag = 0; + return 0; +} + +int llc_conn_ac_set_p_flag_1(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->p_flag = 1; + return 0; +} + +int llc_conn_ac_set_remote_busy_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->remote_busy_flag = 0; + return 0; +} + +int llc_conn_ac_set_cause_flag_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->cause_flag = 0; + return 0; +} + +int llc_conn_ac_set_cause_flag_1(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->cause_flag = 1; + return 0; +} + +int llc_conn_ac_set_retry_cnt_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->retry_count = 0; + return 0; +} + +int llc_conn_ac_inc_retry_cnt_by_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->retry_count++; + return 0; +} + +int llc_conn_ac_set_vr_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->vR = 0; + return 0; +} + +int llc_conn_ac_inc_vr_by_1(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->vR = PDU_GET_NEXT_Vr(llc_sk(sk)->vR); + return 0; +} + +int llc_conn_ac_set_vs_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->vS = 0; + return 0; +} + +int llc_conn_ac_set_vs_nr(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->vS = llc_sk(sk)->last_nr; + return 0; +} + +int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % 128; + return 0; +} + +int llc_conn_ac_set_f_flag_p(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_pdu_decode_pf_bit(ev->data.pdu.skb, &llc_sk(sk)->f_flag); + return 0; +} + +void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data) +{ + struct sock *sk = (struct sock *)timeout_data; + struct llc_conn_state_ev *ev; + + llc_sk(sk)->pf_cycle_timer.running = 0; + ev = llc_conn_alloc_ev(sk); + if (ev) { + ev->type = LLC_CONN_EV_TYPE_P_TMR; + ev->data.tmr.timer_specific = NULL; + llc_process_tmr_ev(sk, ev); + } +} + +static void llc_conn_busy_tmr_cb(unsigned long timeout_data) +{ + struct sock *sk = (struct sock *)timeout_data; + struct llc_conn_state_ev *ev; + + llc_sk(sk)->busy_state_timer.running = 0; + ev = llc_conn_alloc_ev(sk); + if (ev) { + ev->type = LLC_CONN_EV_TYPE_BUSY_TMR; + ev->data.tmr.timer_specific = NULL; + llc_process_tmr_ev(sk, ev); + } +} + +void llc_conn_ack_tmr_cb(unsigned long timeout_data) +{ + struct sock* sk = (struct sock *)timeout_data; + struct llc_conn_state_ev *ev; + + llc_sk(sk)->ack_timer.running = 0; + ev = llc_conn_alloc_ev(sk); + if (ev) { + ev->type = LLC_CONN_EV_TYPE_ACK_TMR; + ev->data.tmr.timer_specific = NULL; + llc_process_tmr_ev(sk, ev); + } +} + +static void llc_conn_rej_tmr_cb(unsigned long timeout_data) +{ + struct sock *sk = (struct sock *)timeout_data; + struct llc_conn_state_ev *ev; + + llc_sk(sk)->rej_sent_timer.running = 0; + ev = llc_conn_alloc_ev(sk); + if (ev) { + ev->type = LLC_CONN_EV_TYPE_REJ_TMR; + ev->data.tmr.timer_specific = NULL; + llc_process_tmr_ev(sk, ev); + } +} + +int llc_conn_ac_rst_vs(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sk(sk)->X = llc_sk(sk)->vS; + llc_conn_ac_set_vs_nr(sk, ev); + return 0; +} + +int llc_conn_ac_upd_vs(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 nr = PDU_SUPV_GET_Nr(rx_pdu); + + if (llc_circular_between(llc_sk(sk)->vS, nr, llc_sk(sk)->X)) + llc_conn_ac_set_vs_nr(sk, ev); + return 0; +} + +/* + * Non-standard actions; these not contained in IEEE specification; for + * our own usage + */ +/** + * llc_conn_disc - removes connection from SAP list and frees it + * @sk: closed connection + * @ev: occurred event + * + * Returns 2, to indicate the state machine that the connection was freed. + */ +int llc_conn_disc(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sap_unassign_sock(llc_sk(sk)->sap, sk); + llc_sock_free(sk); + return 2; +} + +/** + * llc_conn_reset - resets connection + * @sk : reseting connection. + * @ev: occurred event. + * + * Stop all timers, empty all queues and reset all flags. + */ +int llc_conn_reset(struct sock *sk, struct llc_conn_state_ev *ev) +{ + llc_sock_reset(sk); + return 0; +} + +/** + * llc_circular_between - designates that b is between a and c or not + * @a: lower bound + * @b: element to see if is between a and b + * @c: upper bound + * + * This function designates that b is between a and c or not (for example, + * 0 is between 127 and 1). Returns 1 if b is between a and c, 0 + * otherwise. + */ +u8 llc_circular_between(u8 a, u8 b, u8 c) +{ + b = b - a; + c = c - a; + return b <= c; +} + +/** + * llc_process_tmr_ev - timer backend + * @sk: active connection + * @ev: occurred event + * + * This function is called from timer callback functions. When connection + * is busy (during sending a data frame) timer expiration event must be + * queued. Otherwise this event can be sent to connection state machine. + * Queued events will process by process_rxframes_events function after + * sending data frame. Returns 0 for success, 1 otherwise. + */ +static void llc_process_tmr_ev(struct sock *sk, struct llc_conn_state_ev *ev) +{ + bh_lock_sock(sk); + if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) { + printk(KERN_WARNING "timer called on closed connection\n"); + llc_conn_free_ev(ev); + goto out; + } + if (!sk->lock.users) + llc_conn_send_ev(sk, ev); + else { + struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); + + if (skb) { + skb->cb[0] = LLC_EVENT; + skb->data = (void *)ev; + sk_add_backlog(sk, skb); + } else + llc_conn_free_ev(ev); + } +out: bh_unlock_sock(sk); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_c_ev.c linux.20pre2-ac1/net/llc/llc_c_ev.c --- linux.20pre2/net/llc/llc_c_ev.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_c_ev.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,872 @@ +/* + * llc_c_ev.c - Connection component state transition event qualifiers + * + * A 'state' consists of a number of possible event matching functions, + * the actions associated with each being executed when that event is + * matched; a 'state machine' accepts events in a serial fashion from an + * event queue. Each event is passed to each successive event matching + * function until a match is made (the event matching function returns + * success, or '0') or the list of event matching functions is exhausted. + * If a match is made, the actions associated with the event are executed + * and the state is changed to that event's transition state. Before some + * events are recognized, even after a match has been made, a certain + * number of 'event qualifier' functions must also be executed. If these + * all execute successfully, then the event is finally executed. + * + * These event functions must return 0 for success, to show a matched + * event, of 1 if the event does not match. Event qualifier functions + * must return a 0 for success or a non-zero for failure. Each function + * is simply responsible for verifying one single thing and returning + * either a success or failure. + * + * All of followed event functions are described in 802.2 LLC Protocol + * standard document except two functions that we added that will explain + * in their comments, at below. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include + +#if 0 +#define dprintk(args...) printk(KERN_DEBUG args) +#else +#define dprintk(args...) +#endif + +extern u16 llc_circular_between(u8 a, u8 b, u8 c); + +/** + * llc_util_ns_inside_rx_window - check if sequence number is in rx window + * @ns: sequence number of received pdu. + * @vr: sequence number which receiver expects to receive. + * @rw: receive window size of receiver. + * + * Checks if sequence number of received PDU is in range of receive + * window. Returns 0 for success, 1 otherwise + */ +static u16 llc_util_ns_inside_rx_window(u8 ns, u8 vr, u8 rw) +{ + return !llc_circular_between(vr, ns, + (vr + rw - 1) % LLC_2_SEQ_NBR_MODULO); +} + +/** + * llc_util_nr_inside_tx_window - check if sequence number is in tx window + * @sk: current connection. + * @nr: N(R) of received PDU. + * + * This routine checks if N(R) of received PDU is in range of transmit + * window; on the other hand checks if received PDU acknowledges some + * outstanding PDUs that are in transmit window. Returns 0 for success, 1 + * otherwise. + */ +static u16 llc_util_nr_inside_tx_window(struct sock *sk, u8 nr) +{ + u8 nr1, nr2; + struct sk_buff *skb; + llc_pdu_sn_t *pdu; + struct llc_opt *llc = llc_sk(sk); + int rc = 0; + + if (llc->dev->flags & IFF_LOOPBACK) + goto out; + rc = 1; + if (!skb_queue_len(&llc->pdu_unack_q)) + goto out; + skb = skb_peek(&llc->pdu_unack_q); + pdu = (llc_pdu_sn_t *)skb->nh.raw; + nr1 = LLC_I_GET_NS(pdu); + skb = skb_peek_tail(&llc->pdu_unack_q); + pdu = (llc_pdu_sn_t *)skb->nh.raw; + nr2 = LLC_I_GET_NS(pdu); + rc = !llc_circular_between(nr1, nr, (nr2 + 1) % LLC_2_SEQ_NBR_MODULO); +out: return rc; +} + +int llc_conn_ev_conn_req(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->data.prim.prim == LLC_CONN_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_conn_ev_conn_resp(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->data.prim.prim == LLC_CONN_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_RESP ? 0 : 1; +} + +int llc_conn_ev_data_req(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->data.prim.prim == LLC_DATA_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_conn_ev_disc_req(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->data.prim.prim == LLC_DISC_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_conn_ev_rst_req(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->data.prim.prim == LLC_RESET_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_conn_ev_rst_resp(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->data.prim.prim == LLC_RESET_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_RESP ? 0 : 1; +} + +int llc_conn_ev_local_busy_detected(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return ev->type == LLC_CONN_EV_TYPE_SIMPLE && + ev->data.a.ev == LLC_CONN_EV_LOCAL_BUSY_DETECTED ? 0 : 1; +} + +int llc_conn_ev_local_busy_cleared(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return ev->type == LLC_CONN_EV_TYPE_SIMPLE && + ev->data.a.ev == LLC_CONN_EV_LOCAL_BUSY_CLEARED ? 0 : 1; +} + +int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return 1; +} + +int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC ? 0 : 1; +} + +int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM ? 0 : 1; +} + +int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + !LLC_I_PF_IS_0(pdu) && + LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + !LLC_I_PF_IS_1(pdu) && + LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vr = llc_sk(sk)->vR; + u8 ns = LLC_I_GET_NS(pdu); + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + !LLC_I_PF_IS_0(pdu) && ns != vr && + !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vr = llc_sk(sk)->vR; + u8 ns = LLC_I_GET_NS(pdu); + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + !LLC_I_PF_IS_1(pdu) && ns != vr && + !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t * pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vr = llc_sk(sk)->vR; + u8 ns = LLC_I_GET_NS(pdu); + u16 rc = !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; + if (!rc) + dprintk(KERN_WARNING "rx_i_cmd_p_bit_set_x_inval_ns matched," + "state = %d, ns = %d, vr = %d\n", + llc_sk(sk)->state, ns, vr); + return rc; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + !LLC_I_PF_IS_0(pdu) && + LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + !LLC_I_PF_IS_1(pdu) && + LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vr = llc_sk(sk)->vR; + u8 ns = LLC_I_GET_NS(pdu); + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + !LLC_I_PF_IS_0(pdu) && ns != vr && + !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vr = llc_sk(sk)->vR; + u8 ns = LLC_I_GET_NS(pdu); + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + !LLC_I_PF_IS_1(pdu) && ns != vr && + !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vr = llc_sk(sk)->vR; + u8 ns = LLC_I_GET_NS(pdu); + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; +} + +int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vr = llc_sk(sk)->vR; + u8 ns = LLC_I_GET_NS(pdu); + u16 rc = !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; + if (!rc) + dprintk(KERN_WARNING "conn_ev_rx_i_rsp_fbit_set_x_inval_ns " + "matched : state = %d, ns = %d, vr = %d\n", + llc_sk(sk)->state, ns, vr); + return rc; +} + +int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_0(pdu) && + LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_1(pdu) && + LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_0(pdu) && + LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_1(pdu) && + LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; +} + +int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_0(pdu) && + LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1; +} + +int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_1(pdu) && + LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1; +} + +int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_0(pdu) && + LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1; +} + +int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_1(pdu) && + LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1; +} + +int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_0(pdu) && + LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1; +} + +int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_1(pdu) && + LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1; +} + +int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_0(pdu) && + LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; +} + +int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + !LLC_S_PF_IS_1(pdu) && + LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; +} + +int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME ? 0 : 1; +} + +int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_UA ? 0 : 1; +} + +int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u16 rc = 1; + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + if (!LLC_PDU_IS_CMD(pdu)) { + if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { + if (!LLC_I_PF_IS_1(pdu)) + rc = 0; + } else if (!LLC_PDU_TYPE_IS_U(pdu) && !LLC_U_PF_IS_1(pdu)) + rc = 0; + } + return rc; +} + +int llc_conn_ev_rx_xxx_cmd_pbit_set_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u16 rc = 1; + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + if (!LLC_PDU_IS_CMD(pdu)) { + if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { + if (!LLC_I_PF_IS_0(pdu)) + rc = 0; + } else if (!LLC_PDU_TYPE_IS_U(pdu)) + switch (LLC_U_PDU_CMD(pdu)) { + case LLC_2_PDU_CMD_SABME: + case LLC_2_PDU_CMD_DISC: + if (!LLC_U_PF_IS_0(pdu)) + rc = 0; + break; + } + } + return rc; +} + +int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u16 rc = 1; + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + if (!LLC_PDU_IS_CMD(pdu)) { + if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + rc = 0; + else if (!LLC_PDU_TYPE_IS_U(pdu)) + switch (LLC_U_PDU_CMD(pdu)) { + case LLC_2_PDU_CMD_SABME: + case LLC_2_PDU_CMD_DISC: + rc = 0; + break; + } + } + return rc; +} + +int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u16 rc = 1; + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + if (!LLC_PDU_IS_RSP(pdu)) { + if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { + if (!LLC_I_PF_IS_1(pdu)) + rc = 0; + } else if (!LLC_PDU_TYPE_IS_U(pdu)) + switch (LLC_U_PDU_RSP(pdu)) { + case LLC_2_PDU_RSP_UA: + case LLC_2_PDU_RSP_DM: + case LLC_2_PDU_RSP_FRMR: + if (!LLC_U_PF_IS_1(pdu)) + rc = 0; + break; + } + } + return rc; +} + +int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u16 rc = 1; + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + if (!LLC_PDU_IS_RSP(pdu)) { + if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + rc = 0; + else if (!LLC_PDU_TYPE_IS_U(pdu)) + switch (LLC_U_PDU_RSP(pdu)) { + case LLC_2_PDU_RSP_UA: + case LLC_2_PDU_RSP_DM: + case LLC_2_PDU_RSP_FRMR: + rc = 0; + break; + } + } + + return rc; +} + +int llc_conn_ev_rx_xxx_yyy(struct sock *sk, struct llc_conn_state_ev *ev) +{ + u16 rc = 1; + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + rc = 0; + else if (!LLC_PDU_TYPE_IS_U(pdu)) + switch (LLC_U_PDU_CMD(pdu)) { + case LLC_2_PDU_CMD_SABME: + case LLC_2_PDU_CMD_DISC: + case LLC_2_PDU_RSP_UA: + case LLC_2_PDU_RSP_DM: + case LLC_2_PDU_RSP_FRMR: + rc = 0; + break; + } + return rc; +} + +int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u16 rc = 1; + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vs = llc_sk(sk)->vS; + u8 nr = LLC_I_GET_NR(pdu); + + if (!LLC_PDU_IS_CMD(pdu)) { + if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { + if (nr != vs && + llc_util_nr_inside_tx_window(sk, nr)) { + dprintk(KERN_ERR "conn_ev_rx_zzz_cmd_inv_nr " + "matched, state = %d, vs = %d, " + "nr = %d\n", llc_sk(sk)->state, vs, nr); + rc = 0; + } + } + } + return rc; +} + +int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + u16 rc = 1; + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + u8 vs = llc_sk(sk)->vS; + u8 nr = LLC_I_GET_NR(pdu); + + if (!LLC_PDU_IS_RSP(pdu)) { + if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { + if (nr != vs && + llc_util_nr_inside_tx_window(sk, nr)) { + rc = 0; + dprintk(KERN_ERR "conn_ev_rx_zzz_fbit_set" + "_x_inval_nr matched, state = %d, " + "vs = %d, nr = %d\n", + llc_sk(sk)->state, vs, nr); + } + } + } + return rc; +} + +int llc_conn_ev_rx_any_frame(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return 0; +} + +int llc_conn_ev_p_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->type != LLC_CONN_EV_TYPE_P_TMR; +} + +int llc_conn_ev_ack_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->type != LLC_CONN_EV_TYPE_ACK_TMR; +} + +int llc_conn_ev_rej_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->type != LLC_CONN_EV_TYPE_REJ_TMR; +} + +int llc_conn_ev_busy_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->type != LLC_CONN_EV_TYPE_BUSY_TMR; +} + +int llc_conn_ev_any_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev) +{ + + return ev->type == LLC_CONN_EV_TYPE_P_TMR || + ev->type == LLC_CONN_EV_TYPE_ACK_TMR || + ev->type == LLC_CONN_EV_TYPE_REJ_TMR || + ev->type == LLC_CONN_EV_TYPE_BUSY_TMR ? 0 : 1; +} + +int llc_conn_ev_init_p_f_cycle(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return 1; +} + +int llc_conn_ev_tx_buffer_full(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return ev->type == LLC_CONN_EV_TYPE_SIMPLE && + ev->data.a.ev == LLC_CONN_EV_TX_BUFF_FULL ? 0 : 1; +} + +/* --------------------- EVENT QUALIFIER FUNCTIONS ----------------------- * + * these functions simply verify the value of a state flag associated with + * the connection and return either a 0 for success or a non-zero value + * for not-success; verify the event is the type we expect + * ----------------------------------------------------------------------- */ + +int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return llc_sk(sk)->data_flag != 1; +} + +int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return llc_sk(sk)->data_flag; +} + +int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return llc_sk(sk)->data_flag != 2; +} + +int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return llc_sk(sk)->p_flag != 1; +} + +/** + * conn_ev_qlfy_last_frame_eq_1 - checks if frame is last in tx window + * @sk: current connection structure. + * @ev: current event. + * + * This function determines when frame which is sent, is last frame of + * transmit window, if it is then this function return zero else return + * one. This function is used for sending last frame of transmit window + * as I-format command with p-bit set to one. Returns 0 if frame is last + * frame, 1 otherwise. + */ +int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return !(skb_queue_len(&llc_sk(sk)->pdu_unack_q) + 1 == llc_sk(sk)->k); +} + +/** + * conn_ev_qlfy_last_frame_eq_0 - checks if frame isn't last in tx window + * @sk: current connection structure. + * @ev: current event. + * + * This function determines when frame which is sent, isn't last frame of + * transmit window, if it isn't then this function return zero else return + * one. Returns 0 if frame isn't last frame, 1 otherwise. + */ +int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return skb_queue_len(&llc_sk(sk)->pdu_unack_q) + 1 == llc_sk(sk)->k; +} + +int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return llc_sk(sk)->p_flag; +} + +int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk, struct llc_conn_state_ev *ev) +{ + u8 f_bit; + struct sk_buff *skb; + + if (ev->type == LLC_CONN_EV_TYPE_PDU) + skb = ev->data.pdu.skb; + else + skb = ev->data.prim.data->data->conn.skb; + llc_pdu_decode_pf_bit(skb, &f_bit); + return llc_sk(sk)->p_flag == f_bit ? 0 : 1; +} + +int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return llc_sk(sk)->remote_busy_flag; +} + +int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return !llc_sk(sk)->remote_busy_flag; +} + +int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return !(llc_sk(sk)->retry_count < llc_sk(sk)->n2); +} + +int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return !(llc_sk(sk)->retry_count >= llc_sk(sk)->n2); +} + +int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return !llc_sk(sk)->s_flag; +} + +int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk, struct llc_conn_state_ev *ev) +{ + return llc_sk(sk)->s_flag; +} + +int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return !llc_sk(sk)->cause_flag; +} + +int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return llc_sk(sk)->cause_flag; +} + +int llc_conn_ev_qlfy_init_p_f_cycle(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + return 0; +} + +int llc_conn_ev_qlfy_set_status_conn(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_CONN; + return 0; +} + +int llc_conn_ev_qlfy_set_status_disc(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_DISC; + return 0; +} + +int llc_conn_ev_qlfy_set_status_impossible(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_IMPOSSIBLE; + return 0; +} + +int llc_conn_ev_qlfy_set_status_failed(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_FAILED; + return 0; +} + +int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_REMOTE_BUSY; + return 0; +} + +int llc_conn_ev_qlfy_set_status_received(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_RECEIVED; + return 0; +} + +int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_REFUSE; + return 0; +} + +int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_CONFLICT; + return 0; +} + +int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk, + struct llc_conn_state_ev *ev) +{ + ev->status = LLC_STATUS_RESET_DONE; + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_conn.c linux.20pre2-ac1/net/llc/llc_conn.c --- linux.20pre2/net/llc/llc_conn.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_conn.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,520 @@ +/* + * llc_conn.c - Driver routines for connection component. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int llc_find_offset(int state, int ev_type); +static void llc_conn_send_pdus(struct sock *sk); +static int llc_conn_service(struct sock *sk, struct llc_conn_state_ev *ev); +static int llc_exec_conn_trans_actions(struct sock *sk, + struct llc_conn_state_trans *trans, + struct llc_conn_state_ev *ev); +static struct llc_conn_state_trans * + llc_qualify_conn_ev(struct sock *sk, struct llc_conn_state_ev *ev); + +/* Offset table on connection states transition diagram */ +static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV]; + +/** + * llc_conn_alloc_event: allocates an event + * @sk: socket that event is associated + * + * Returns pointer to allocated connection on success, %NULL on failure. + */ +struct llc_conn_state_ev *llc_conn_alloc_ev(struct sock *sk) +{ + struct llc_conn_state_ev *ev = NULL; + + /* verify connection is valid, active and open */ + if (llc_sk(sk)->state != LLC_CONN_OUT_OF_SVC) { + /* get event structure to build a station event */ + ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + if (ev) + memset(ev, 0, sizeof(*ev)); + } + return ev; +} + +/** + * llc_conn_send_event - sends event to connection state machine + * @sk: connection + * @ev: occurred event + * + * Sends an event to connection state machine. after processing event + * (executing it's actions and changing state), upper layer will be + * indicated or confirmed, if needed. Returns 0 for success, 1 for + * failure. The socket lock has to be held before calling this function. + */ +int llc_conn_send_ev(struct sock *sk, struct llc_conn_state_ev *ev) +{ + /* sending event to state machine */ + int rc = llc_conn_service(sk, ev); + struct llc_opt *llc = llc_sk(sk); + u8 flag = ev->flag; + struct llc_prim_if_block *ind_prim = ev->ind_prim; + struct llc_prim_if_block *cfm_prim = ev->cfm_prim; + + llc_conn_free_ev(ev); +#ifdef THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY + /* check if the connection was freed by the state machine by + * means of llc_conn_disc */ + if (rc == 2) { + printk(KERN_INFO __FUNCTION__ ": rc == 2\n"); + rc = -ECONNABORTED; + goto out; + } +#endif /* THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY */ + if (!flag) /* indicate or confirm not required */ + goto out; + rc = 0; + if (ind_prim) /* indication required */ + llc->sap->ind(ind_prim); + if (!cfm_prim) /* confirmation not required */ + goto out; + /* data confirm has preconditions */ + if (cfm_prim->prim != LLC_DATA_PRIM) { + llc->sap->conf(cfm_prim); + goto out; + } + if (!llc_data_accept_state(llc->state)) { + /* In this state, we can send I pdu */ + /* FIXME: check if we don't need to see if sk->lock.users != 0 + * is needed here */ + rc = llc->sap->conf(cfm_prim); + if (rc) /* confirmation didn't accept by upper layer */ + llc->failed_data_req = 1; + } else + llc->failed_data_req = 1; +out: return rc; +} + +void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) +{ + llc_sock_assert(sk); + /* queue PDU to send to MAC layer */ + skb_queue_tail(&sk->write_queue, skb); + llc_conn_send_pdus(sk); +} + +/** + * llc_conn_rtn_pdu - sends received data pdu to upper layer + * @sk: Active connection + * @skb: Received data frame + * @ev: Occurred event + * + * Sends received data pdu to upper layer (by using indicate function). + * Prepares service parameters (prim and prim_data). calling indication + * function will be done in llc_conn_send_ev. + */ +void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb, + struct llc_conn_state_ev *ev) +{ + struct llc_prim_if_block *prim = &llc_ind_prim; + union llc_u_prim_data *prim_data = llc_ind_prim.data; + + prim_data->data.sk = sk; + prim_data->data.pri = 0; + prim_data->data.skb = skb; + prim_data->data.link = llc_sk(sk)->link; + prim->data = prim_data; + prim->prim = LLC_DATA_PRIM; + prim->sap = llc_sk(sk)->sap; + ev->flag = 1; + /* saving prepd prim in event for future use in llc_conn_send_ev */ + ev->ind_prim = prim; +} + +/** + * llc_conn_resend_i_pdu_as_cmd - resend all all unacknowledged I PDUs + * @sk: active connection + * @nr: NR + * @first_p_bit: p_bit value of first pdu + * + * Resend all unacknowledged I PDUs, starting with the NR; send first as + * command PDU with P bit equal first_p_bit; if more than one send + * subsequent as command PDUs with P bit equal zero (0). + */ +void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit) +{ + struct sk_buff *skb; + llc_pdu_sn_t *pdu; + u16 nbr_unack_pdus; + u8 howmany_resend = 0; + + llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus); + if (!nbr_unack_pdus) + goto out; + /* process unack PDUs only if unack queue is not empty; remove + * appropriate PDUs, fix them up, and put them on mac_pdu_q. */ + while ((skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q)) != NULL) { + pdu = (llc_pdu_sn_t *)skb->nh.raw; + llc_pdu_set_cmd_rsp(skb, LLC_PDU_CMD); + llc_pdu_set_pf_bit(skb, first_p_bit); + skb_queue_tail(&sk->write_queue, skb); + first_p_bit = 0; + llc_sk(sk)->vS = LLC_I_GET_NS(pdu); + howmany_resend++; + } + if (howmany_resend > 0) + llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO; + /* any PDUs to re-send are queued up; start sending to MAC */ + llc_conn_send_pdus(sk); +out:; +} + +/** + * llc_conn_resend_i_pdu_as_rsp - Resend all unacknowledged I PDUs + * @sk: active connection. + * @nr: NR + * @first_f_bit: f_bit value of first pdu. + * + * Resend all unacknowledged I PDUs, starting with the NR; send first as + * response PDU with F bit equal first_f_bit; if more than one send + * subsequent as response PDUs with F bit equal zero (0). + */ +void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit) +{ + struct sk_buff *skb; + llc_pdu_sn_t *pdu; + u16 nbr_unack_pdus; + u8 howmany_resend = 0; + + llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus); + if (!nbr_unack_pdus) + goto out; + /* process unack PDUs only if unack queue is not empty; remove + * appropriate PDUs, fix them up, and put them on mac_pdu_q */ + while ((skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q)) != NULL) { + pdu = (llc_pdu_sn_t *)skb->nh.raw; + llc_pdu_set_cmd_rsp(skb, LLC_PDU_RSP); + llc_pdu_set_pf_bit(skb, first_f_bit); + skb_queue_tail(&sk->write_queue, skb); + first_f_bit = 0; + llc_sk(sk)->vS = LLC_I_GET_NS(pdu); + howmany_resend++; + } + if (howmany_resend > 0) + llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO; + /* any PDUs to re-send are queued up; start sending to MAC */ + llc_conn_send_pdus(sk); +out:; +} + +/** + * llc_conn_remove_acked_pdus - Removes acknowledged pdus from tx queue + * @sk: active connection + * nr: NR + * how_many_unacked: size of pdu_unack_q after removing acked pdus + * + * Removes acknowledged pdus from transmit queue (pdu_unack_q). Returns + * the number of pdus that removed from queue. + */ +int llc_conn_remove_acked_pdus(struct sock *sk, u8 nr, u16 *how_many_unacked) +{ + int pdu_pos, i; + struct sk_buff *skb; + llc_pdu_sn_t *pdu; + int nbr_acked = 0; + int q_len = skb_queue_len(&llc_sk(sk)->pdu_unack_q); + + if (!q_len) + goto out; + skb = skb_peek(&llc_sk(sk)->pdu_unack_q); + pdu = (llc_pdu_sn_t *)skb->nh.raw; + + /* finding position of last acked pdu in queue */ + pdu_pos = ((int)LLC_2_SEQ_NBR_MODULO + (int)nr - + (int)LLC_I_GET_NS(pdu)) % LLC_2_SEQ_NBR_MODULO; + + for (i = 0; i < pdu_pos && i < q_len; i++) { + skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q); + if (skb) + kfree_skb(skb); + nbr_acked++; + } +out: *how_many_unacked = skb_queue_len(&llc_sk(sk)->pdu_unack_q); + return nbr_acked; +} + +/** + * llc_conn_send_pdus - Sends queued PDUs + * @sk: active connection + * + * Sends queued pdus to MAC layer for transmition. + */ +static void llc_conn_send_pdus(struct sock *sk) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&sk->write_queue)) != NULL) { + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + if (!LLC_PDU_TYPE_IS_I(pdu) && + !(skb->dev->flags & IFF_LOOPBACK)) + skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb); + mac_send_pdu(skb); + if (LLC_PDU_TYPE_IS_I(pdu) || + (skb->dev && skb->dev->flags & IFF_LOOPBACK)) + kfree_skb(skb); + } +} + +/** + * llc_conn_free_ev - free event + * @ev: event to free + * + * Free allocated event. + */ +void llc_conn_free_ev(struct llc_conn_state_ev *ev) +{ + if (ev->type == LLC_CONN_EV_TYPE_PDU) { + /* free the frame that binded to this event */ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw; + + if (LLC_PDU_TYPE_IS_I(pdu) || !ev->flag || !ev->ind_prim) + kfree_skb(ev->data.pdu.skb); + } + /* free event structure to free list of the same */ + kfree(ev); +} + +/** + * llc_conn_service - finds transition and changes state of connection + * @sk: connection + * @ev: happened event + * + * This function finds transition that matches with happened event, then + * executes related actions and finally changes state of connection. + * Returns 0 for success, 1 for failure. + */ +static int llc_conn_service(struct sock *sk, struct llc_conn_state_ev *ev) +{ + int rc = 1; + struct llc_conn_state_trans *trans; + + if (llc_sk(sk)->state > NBR_CONN_STATES) + goto out; + rc = 0; + trans = llc_qualify_conn_ev(sk, ev); + if (trans) { + rc = llc_exec_conn_trans_actions(sk, trans, ev); + if (!rc && trans->next_state != NO_STATE_CHANGE) + llc_sk(sk)->state = trans->next_state; + } +out: return rc; +} + +/** + * llc_qualify_conn_ev - finds transition for event + * @sk: connection + * @ev: happened event + * + * This function finds transition that matches with happened event. + * Returns pointer to found transition on success, %NULL otherwise. + */ +static struct llc_conn_state_trans * + llc_qualify_conn_ev(struct sock *sk, struct llc_conn_state_ev *ev) +{ + struct llc_conn_state_trans **next_trans; + llc_conn_ev_qfyr_t *next_qualifier; + struct llc_conn_state *curr_state = + &llc_conn_state_table[llc_sk(sk)->state - 1]; + + /* search thru events for this state until list exhausted or until + no more */ + for (next_trans = curr_state->transitions + + llc_find_offset(llc_sk(sk)->state - 1, ev->type); + (*next_trans)->ev; next_trans++) { + if (!((*next_trans)->ev)(sk, ev)) { + /* got POSSIBLE event match; the event may require + * qualification based on the values of a number of + * state flags; if all qualifications are met (i.e., + * if all qualifying functions return success, or 0, + * then this is THE event we're looking for */ + for (next_qualifier = (*next_trans)->ev_qualifiers; + next_qualifier && *next_qualifier && + !(*next_qualifier)(sk, ev); next_qualifier++) + /* nothing */; + if (!next_qualifier || !*next_qualifier) + /* all qualifiers executed successfully; this is + * our transition; return it so we can perform + * the associated actions & change the state */ + return *next_trans; + } + } + return NULL; +} + +/** + * llc_exec_conn_trans_actions - executes related actions + * @sk: connection + * @trans: transition that it's actions must be performed + * @ev: happened event + * + * Executes actions that is related to happened event. Returns 0 for + * success, 1 to indicate failure of at least one action or 2 if the + * connection was freed (llc_conn_disc was called) + */ +static int llc_exec_conn_trans_actions(struct sock *sk, + struct llc_conn_state_trans *trans, + struct llc_conn_state_ev *ev) +{ + int rc = 0; + llc_conn_action_t *next_action; + + for (next_action = trans->ev_actions; + next_action && *next_action; next_action++) { + int rc2 = (*next_action)(sk, ev); + + if (rc2 == 2) { + rc = rc2; + break; + } else if (rc2) + rc = 1; + } + return rc; +} + +/** + * llc_find_sock - Finds connection in sap for the remote/local sap/mac + * @sap: SAP + * @daddr: address of remote LLC (MAC + SAP) + * @laddr: address of local LLC (MAC + SAP) + * + * Search connection list of the SAP and finds connection using the remote + * mac, remote sap, local mac, and local sap. Returns pointer for + * connection found, %NULL otherwise. + */ +struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, + struct llc_addr *laddr) +{ + struct sock *rc = NULL; + struct list_head *entry; + + spin_lock_bh(&sap->sk_list.lock); + if (list_empty(&sap->sk_list.list)) + goto out; + list_for_each(entry, &sap->sk_list.list) { + struct llc_opt *llc = list_entry(entry, struct llc_opt, node); + + if (llc->laddr.lsap == laddr->lsap && + llc->daddr.lsap == daddr->lsap && + !memcmp(llc->laddr.mac, laddr->mac, ETH_ALEN) && + !memcmp(llc->daddr.mac, daddr->mac, ETH_ALEN)) { + rc = llc->sk; + break; + } + } + if (rc) + sock_hold(rc); +out: spin_unlock_bh(&sap->sk_list.lock); + return rc; +} + +/** + * llc_data_accept_state - designates if in this state data can be sent. + * @state: state of connection. + * + * Returns 0 if data can be sent, 1 otherwise. + */ +u8 llc_data_accept_state(u8 state) +{ + if (state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY && + state != LLC_CONN_STATE_REJ) + return 1; /* data_conn_refuse */ + return 0; +} + +/** + * find_next_offset - finds offset for next category of transitions + * @state: state table. + * @offset: start offset. + * + * Finds offset of next category of transitions in transition table. + * Returns the start index of next category. + */ +u16 find_next_offset(struct llc_conn_state *state, u16 offset) +{ + u16 cnt = 0; + struct llc_conn_state_trans **next_trans; + + for (next_trans = state->transitions + offset; + (*next_trans)->ev; next_trans++) + ++cnt; + return cnt; +} + +/** + * llc_build_offset_table - builds offset table of connection + * + * Fills offset table of connection state transition table + * (llc_offset_table). + */ +void __init llc_build_offset_table(void) +{ + struct llc_conn_state *curr_state; + int state, ev_type, next_offset; + + memset(llc_offset_table, 0, sizeof(llc_offset_table)); + for (state = 0; state < NBR_CONN_STATES; state++) { + curr_state = &llc_conn_state_table[state]; + next_offset = 0; + for (ev_type = 0; ev_type < NBR_CONN_EV; ev_type++) { + llc_offset_table[state][ev_type] = next_offset; + next_offset += find_next_offset(curr_state, + next_offset) + 1; + } + } +} + +/** + * llc_find_offset - finds start offset of category of transitions + * @state: state of connection + * @ev_type: type of happened event + * + * Finds start offset of desired category of transitions. Returns the + * desired start offset. + */ +static int llc_find_offset(int state, int ev_type) +{ + int rc = 0; + /* at this stage, llc_offset_table[..][2] is not important. it is for + * init_pf_cycle and I don't know what is it. */ + switch (ev_type) { + case LLC_CONN_EV_TYPE_PRIM: + rc = llc_offset_table[state][0]; break; + case LLC_CONN_EV_TYPE_PDU: + rc = llc_offset_table[state][4]; break; + case LLC_CONN_EV_TYPE_SIMPLE: + rc = llc_offset_table[state][1]; break; + case LLC_CONN_EV_TYPE_P_TMR: + case LLC_CONN_EV_TYPE_ACK_TMR: + case LLC_CONN_EV_TYPE_REJ_TMR: + case LLC_CONN_EV_TYPE_BUSY_TMR: + rc = llc_offset_table[state][3]; break; + } + return rc; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_c_st.c linux.20pre2-ac1/net/llc/llc_c_st.c --- linux.20pre2/net/llc/llc_c_st.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_c_st.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,4897 @@ +/* + * llc_c_st.c - This module contains state transition of connection component. + * + * Description of event functions and actions there is in 802.2 LLC standard, + * or in "llc_c_ac.c" and "llc_c_ev.c" modules. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include + +#define LLC_NO_EVENT_QUALIFIERS NULL +#define LLC_NO_TRANSITION_ACTIONS NULL + +/* ----------------- COMMON CONNECTION STATE transitions ----------------- * + * Common transitions for + * LLC_CONN_STATE_NORMAL, + * LLC_CONN_STATE_BUSY, + * LLC_CONN_STATE_REJ, + * LLC_CONN_STATE_AWAIT, + * LLC_CONN_STATE_AWAIT_BUSY and + * LLC_CONN_STATE_AWAIT_REJ states + */ +/* State transitions for LLC_CONN_EV_DISC_REQ event */ +static llc_conn_action_t llc_common_actions_1[] = { + llc_conn_ac_send_disc_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_cause_flag_1, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_1 = { + llc_conn_ev_disc_req, + LLC_CONN_STATE_D_CONN, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_1 +}; + +/* State transitions for LLC_CONN_EV_RESET_REQ event */ +static llc_conn_action_t llc_common_actions_2[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_cause_flag_1, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_2 = { + llc_conn_ev_rst_req, + LLC_CONN_STATE_RESET, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_2 +}; + +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_common_actions_3[] = { + llc_conn_ac_stop_all_timers, + llc_conn_ac_set_vs_0, + llc_conn_ac_set_vr_0, + llc_conn_ac_send_ua_rsp_f_set_p, + llc_conn_ac_rst_ind, + llc_conn_ac_set_p_flag_0, + llc_conn_ac_set_remote_busy_0, + llc_conn_reset, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_3 = { + llc_conn_ev_rx_sabme_cmd_pbit_set_x, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_3 +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_common_actions_4[] = { + llc_conn_ac_stop_all_timers, + llc_conn_ac_send_ua_rsp_f_set_p, + llc_conn_ac_disc_ind, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_4 = { + llc_conn_ev_rx_disc_cmd_pbit_set_x, + LLC_CONN_STATE_ADM, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_common_actions_5[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_rst_ind, + llc_conn_ac_set_cause_flag_0, + llc_conn_reset, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_5 = { + llc_conn_ev_rx_frmr_rsp_fbit_set_x, + LLC_CONN_STATE_RESET, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_5 +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_common_actions_6[] = { + llc_conn_ac_disc_ind, + llc_conn_ac_stop_all_timers, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_6 = { + llc_conn_ev_rx_dm_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_6 +}; + +/* State transitions for LLC_CONN_EV_RX_ZZZ_CMD_Pbit_SET_X_INVAL_Nr event */ +static llc_conn_action_t llc_common_actions_7a[] = { + llc_conn_ac_send_frmr_rsp_f_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_7a = { + llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr, + LLC_CONN_STATE_ERROR, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_7a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_INVAL_Ns event */ +static llc_conn_action_t llc_common_actions_7b[] = { + llc_conn_ac_send_frmr_rsp_f_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_7b = { + llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns, + LLC_CONN_STATE_ERROR, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_7b +}; + +/* State transitions for LLC_CONN_EV_RX_ZZZ_RSP_Fbit_SET_X_INVAL_Nr event */ +static llc_conn_action_t llc_common_actions_8a[] = { + llc_conn_ac_send_frmr_rsp_f_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_8a = { + llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr, + LLC_CONN_STATE_ERROR, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_8a +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_INVAL_Ns event */ +static llc_conn_action_t llc_common_actions_8b[] = { + llc_conn_ac_send_frmr_rsp_f_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_8b = { + llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns, + LLC_CONN_STATE_ERROR, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_8b +}; + +/* State transitions for LLC_CONN_EV_RX_BAD_PDU event */ +static llc_conn_action_t llc_common_actions_8c[] = { + llc_conn_ac_send_frmr_rsp_f_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_8c = { + llc_conn_ev_rx_bad_pdu, + LLC_CONN_STATE_ERROR, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_8c +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_common_actions_9[] = { + llc_conn_ac_send_frmr_rsp_f_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_9 = { + llc_conn_ev_rx_ua_rsp_fbit_set_x, + LLC_CONN_STATE_ERROR, + LLC_NO_EVENT_QUALIFIERS, + llc_common_actions_9 +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_1 event */ +#if 0 +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_10[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_common_actions_10[] = { + llc_conn_ac_send_frmr_rsp_f_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_10 = { + llc_conn_ev_rx_xxx_rsp_fbit_set_1, + LLC_CONN_STATE_ERROR, + llc_common_ev_qfyrs_10, + llc_common_actions_10 +}; +#endif + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11a[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + NULL +}; + +static llc_conn_action_t llc_common_actions_11a[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_cause_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_11a = { + llc_conn_ev_p_tmr_exp, + LLC_CONN_STATE_RESET, + llc_common_ev_qfyrs_11a, + llc_common_actions_11a +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11b[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + NULL +}; + +static llc_conn_action_t llc_common_actions_11b[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_cause_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_11b = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_RESET, + llc_common_ev_qfyrs_11b, + llc_common_actions_11b +}; + +/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11c[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + NULL +}; + +static llc_conn_action_t llc_common_actions_11c[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_cause_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_11c = { + llc_conn_ev_rej_tmr_exp, + LLC_CONN_STATE_RESET, + llc_common_ev_qfyrs_11c, + llc_common_actions_11c +}; + +/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11d[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + NULL +}; + +static llc_conn_action_t llc_common_actions_11d[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_stop_other_timers, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_cause_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_common_state_trans_11d = { + llc_conn_ev_busy_tmr_exp, + LLC_CONN_STATE_RESET, + llc_common_ev_qfyrs_11d, + llc_common_actions_11d +}; + +/* + * Common dummy state transition; must be last entry for all state + * transition groups - it'll be on .bss, so will be zeroed. + */ +static struct llc_conn_state_trans llc_common_state_trans_n; + +/* --------------------- LLC_CONN_STATE_ADM transitions -------------------- */ +/* State transitions for LLC_CONN_EV_CONN_REQ event */ +static llc_conn_action_t llc_adm_actions_1[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_s_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_adm_state_trans_1 = { + llc_conn_ev_conn_req, + LLC_CONN_STATE_SETUP, + LLC_NO_EVENT_QUALIFIERS, + llc_adm_actions_1 +}; + +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_adm_actions_2[] = { + llc_conn_ac_send_ua_rsp_f_set_p, + llc_conn_ac_set_vs_0, + llc_conn_ac_set_vr_0, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_p_flag_0, + llc_conn_ac_set_remote_busy_0, + llc_conn_ac_conn_ind, + NULL +}; + +static struct llc_conn_state_trans llc_adm_state_trans_2 = { + llc_conn_ev_rx_sabme_cmd_pbit_set_x, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_adm_actions_2 +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_adm_actions_3[] = { + llc_conn_ac_send_dm_rsp_f_set_p, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_adm_state_trans_3 = { + llc_conn_ev_rx_disc_cmd_pbit_set_x, + LLC_CONN_STATE_ADM, + LLC_NO_EVENT_QUALIFIERS, + llc_adm_actions_3 +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_adm_actions_4[] = { + llc_conn_ac_send_dm_rsp_f_set_1, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_adm_state_trans_4 = { + llc_conn_ev_rx_xxx_cmd_pbit_set_1, + LLC_CONN_STATE_ADM, + LLC_NO_EVENT_QUALIFIERS, + llc_adm_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_YYY event */ +static llc_conn_action_t llc_adm_actions_5[] = { + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_adm_state_trans_5 = { + llc_conn_ev_rx_any_frame, + LLC_CONN_OUT_OF_SVC, + LLC_NO_EVENT_QUALIFIERS, + llc_adm_actions_5 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_adm_state_transitions[] = { + &llc_adm_state_trans_1, /* Request */ + &llc_common_state_trans_n, + &llc_common_state_trans_n, /* local_busy */ + &llc_common_state_trans_n, /* init_pf_cycle */ + &llc_common_state_trans_n, /* timer */ + &llc_adm_state_trans_2, /* Receive frame */ + &llc_adm_state_trans_3, + &llc_adm_state_trans_4, + &llc_adm_state_trans_5, + &llc_common_state_trans_n +}; + +/* --------------------- LLC_CONN_STATE_SETUP transitions ----------------- */ +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_setup_actions_1[] = { + llc_conn_ac_send_ua_rsp_f_set_p, + llc_conn_ac_set_vs_0, + llc_conn_ac_set_vr_0, + llc_conn_ac_set_s_flag_1, + NULL +}; + +static struct llc_conn_state_trans llc_setup_state_trans_1 = { + llc_conn_ev_rx_sabme_cmd_pbit_set_x, + LLC_CONN_STATE_SETUP, + LLC_NO_EVENT_QUALIFIERS, + llc_setup_actions_1 +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_2[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + llc_conn_ev_qlfy_set_status_conn, + NULL +}; + +static llc_conn_action_t llc_setup_actions_2[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_ac_set_vs_0, + llc_conn_ac_set_vr_0, + llc_conn_ac_upd_p_flag, + llc_conn_ac_set_remote_busy_0, + llc_conn_ac_conn_confirm, + NULL +}; + +static struct llc_conn_state_trans llc_setup_state_trans_2 = { + llc_conn_ev_rx_ua_rsp_fbit_set_x, + LLC_CONN_STATE_NORMAL, + llc_setup_ev_qfyrs_2, + llc_setup_actions_2 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_3[] = { + llc_conn_ev_qlfy_s_flag_eq_1, + llc_conn_ev_qlfy_set_status_conn, + NULL +}; + +static llc_conn_action_t llc_setup_actions_3[] = { + llc_conn_ac_set_p_flag_0, + llc_conn_ac_set_remote_busy_0, + llc_conn_ac_conn_confirm, + NULL +}; + +static struct llc_conn_state_trans llc_setup_state_trans_3 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_NORMAL, + llc_setup_ev_qfyrs_3, + llc_setup_actions_3 +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_4[] = { + llc_conn_ev_qlfy_set_status_disc, + NULL +}; + +static llc_conn_action_t llc_setup_actions_4[] = { + llc_conn_ac_send_dm_rsp_f_set_p, + llc_conn_ac_stop_ack_timer, + llc_conn_ac_conn_confirm, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_setup_state_trans_4 = { + llc_conn_ev_rx_disc_cmd_pbit_set_x, + LLC_CONN_STATE_ADM, + llc_setup_ev_qfyrs_4, + llc_setup_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_5[] = { + llc_conn_ev_qlfy_set_status_disc, + NULL +}; + +static llc_conn_action_t llc_setup_actions_5[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_ac_conn_confirm, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_setup_state_trans_5 = { + llc_conn_ev_rx_dm_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + llc_setup_ev_qfyrs_5, + llc_setup_actions_5 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_7[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + llc_conn_ev_qlfy_s_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_setup_actions_7[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_setup_state_trans_7 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_SETUP, + llc_setup_ev_qfyrs_7, + llc_setup_actions_7 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_8[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + llc_conn_ev_qlfy_s_flag_eq_0, + llc_conn_ev_qlfy_set_status_failed, + NULL +}; + +static llc_conn_action_t llc_setup_actions_8[] = { + llc_conn_ac_conn_confirm, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_setup_state_trans_8 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_ADM, + llc_setup_ev_qfyrs_8, + llc_setup_actions_8 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_setup_state_transitions[] = { + &llc_common_state_trans_n, /* Request */ + &llc_common_state_trans_n, /* local busy */ + &llc_common_state_trans_n, /* init_pf_cycle */ + &llc_setup_state_trans_3, /* Timer */ + &llc_setup_state_trans_7, + &llc_setup_state_trans_8, + &llc_common_state_trans_n, + &llc_setup_state_trans_1, /* Receive frame */ + &llc_setup_state_trans_2, + &llc_setup_state_trans_4, + &llc_setup_state_trans_5, + &llc_common_state_trans_n +}; + +/* -------------------- LLC_CONN_STATE_NORMAL transitions ------------------ */ +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_1[] = { + llc_conn_ev_qlfy_remote_busy_eq_0, + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_last_frame_eq_0, + NULL +}; + +static llc_conn_action_t llc_normal_actions_1[] = { + llc_conn_ac_send_i_as_ack, + llc_conn_ac_start_ack_tmr_if_not_running, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_1 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_1, + llc_normal_actions_1 +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_2[] = { + llc_conn_ev_qlfy_remote_busy_eq_0, + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_last_frame_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_2[] = { + llc_conn_ac_send_i_cmd_p_set_1, + llc_conn_ac_start_p_timer, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_2 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_2, + llc_normal_actions_2 +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_2_1[] = { + llc_conn_ev_qlfy_remote_busy_eq_1, + llc_conn_ev_qlfy_set_status_remote_busy, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_normal_actions_2_1[1]; + +static struct llc_conn_state_trans llc_normal_state_trans_2_1 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_2_1, + llc_normal_actions_2_1 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_3[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_normal_actions_3[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rnr_xxx_x_set_0, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_3 = { + llc_conn_ev_local_busy_detected, + LLC_CONN_STATE_BUSY, + llc_normal_ev_qfyrs_3, + llc_normal_actions_3 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_4[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_4[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rnr_xxx_x_set_0, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_4 = { + llc_conn_ev_local_busy_detected, + LLC_CONN_STATE_BUSY, + llc_normal_ev_qfyrs_4, + llc_normal_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5a[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_normal_actions_5a[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_start_rej_timer, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_5a = { + llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, + LLC_CONN_STATE_REJ, + llc_normal_ev_qfyrs_5a, + llc_normal_actions_5a +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5b[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_normal_actions_5b[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_start_rej_timer, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_5b = { + llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, + LLC_CONN_STATE_REJ, + llc_normal_ev_qfyrs_5b, + llc_normal_actions_5b +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5c[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_5c[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_start_rej_timer, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_5c = { + llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, + LLC_CONN_STATE_REJ, + llc_normal_ev_qfyrs_5c, + llc_normal_actions_5c +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_6a[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_6a[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_start_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_6a = { + llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, + LLC_CONN_STATE_REJ, + llc_normal_ev_qfyrs_6a, + llc_normal_actions_6a +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_6b[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_6b[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_start_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_6b = { + llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, + LLC_CONN_STATE_REJ, + llc_normal_ev_qfyrs_6b, + llc_normal_actions_6b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_normal_actions_7[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rej_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_start_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_7 = { + llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_7 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_8a[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + NULL +}; + +static llc_conn_action_t llc_normal_actions_8[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + llc_conn_ac_send_ack_if_needed, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_8a = { + llc_conn_ev_rx_i_rsp_fbit_set_x, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_8a, + llc_normal_actions_8 +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_8b[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_8b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_8b, + llc_normal_actions_8 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_9a[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_9a[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_data_ind, + llc_conn_ac_send_ack_if_needed, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_9a = { + llc_conn_ev_rx_i_rsp_fbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_9a, + llc_normal_actions_9a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_9b[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_9b[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_data_ind, + llc_conn_ac_send_ack_if_needed, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_9b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_9b, + llc_normal_actions_9b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_normal_actions_10[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_send_ack_rsp_f_set_1, + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_data_ind, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_10 = { + llc_conn_ev_rx_i_cmd_pbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_10 +}; + +/* State transitions for * LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_normal_actions_11a[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_11a = { + llc_conn_ev_rx_rr_cmd_pbit_set_0, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_11a +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_normal_actions_11b[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_11b = { + llc_conn_ev_rx_rr_rsp_fbit_set_0, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_11b +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_11c[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_11c[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_inc_tx_win_size, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_11c = { + llc_conn_ev_rx_rr_rsp_fbit_set_1, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_11c, + llc_normal_actions_11c +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_normal_actions_12[] = { + llc_conn_ac_send_ack_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_adjust_npta_by_rr, + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_12 = { + llc_conn_ev_rx_rr_cmd_pbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_12 +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_normal_actions_13a[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_13a = { + llc_conn_ev_rx_rnr_cmd_pbit_set_0, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_13a +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_normal_actions_13b[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_13b = { + llc_conn_ev_rx_rnr_rsp_fbit_set_0, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_13b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_13c[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_13c[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_13c = { + llc_conn_ev_rx_rnr_rsp_fbit_set_1, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_13c, + llc_normal_actions_13c +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_normal_actions_14[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_adjust_npta_by_rnr, + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_14 = { + llc_conn_ev_rx_rnr_cmd_pbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_14 +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_15a[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_normal_actions_15a[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_dec_tx_win_size, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_15a = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_15a, + llc_normal_actions_15a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_15b[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + NULL +}; + +static llc_conn_action_t llc_normal_actions_15b[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_dec_tx_win_size, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_15b = { + llc_conn_ev_rx_rej_rsp_fbit_set_x, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_15b, + llc_normal_actions_15b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_16a[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_16a[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_dec_tx_win_size, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_16a = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_16a, + llc_normal_actions_16a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_16b[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_normal_actions_16b[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_dec_tx_win_size, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_16b = { + llc_conn_ev_rx_rej_rsp_fbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_16b, + llc_normal_actions_16b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_normal_actions_17[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_dec_tx_win_size, + llc_conn_ac_resend_i_rsp_f_set_1, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_17 = { + llc_conn_ev_rx_rej_cmd_pbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_normal_actions_17 +}; + +/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_18[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_normal_actions_18[] = { + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_18 = { + llc_conn_ev_init_p_f_cycle, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_18, + llc_normal_actions_18 +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_19[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_normal_actions_19[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_rst_vs, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_19 = { + llc_conn_ev_p_tmr_exp, + LLC_CONN_STATE_AWAIT, + llc_normal_ev_qfyrs_19, + llc_normal_actions_19 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_20a[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_normal_actions_20a[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_rst_vs, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_20a = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_AWAIT, + llc_normal_ev_qfyrs_20a, + llc_normal_actions_20a +}; + +/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_20b[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_normal_actions_20b[] = { + llc_conn_ac_rst_sendack_flag, + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_rst_vs, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_20b = { + llc_conn_ev_busy_tmr_exp, + LLC_CONN_STATE_AWAIT, + llc_normal_ev_qfyrs_20b, + llc_normal_actions_20b +}; + +/* State transitions for LLC_CONN_EV_TX_BUFF_FULL event */ +static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_21[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_normal_actions_21[] = { + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + NULL +}; + +static struct llc_conn_state_trans llc_normal_state_trans_21 = { + llc_conn_ev_tx_buffer_full, + LLC_CONN_STATE_NORMAL, + llc_normal_ev_qfyrs_21, + llc_normal_actions_21 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_normal_state_transitions[] = { + &llc_normal_state_trans_1, /* Requests */ + &llc_normal_state_trans_2, + &llc_normal_state_trans_2_1, + &llc_common_state_trans_1, + &llc_common_state_trans_2, + &llc_common_state_trans_n, + &llc_normal_state_trans_21, + &llc_normal_state_trans_3, /* Local busy */ + &llc_normal_state_trans_4, + &llc_common_state_trans_n, + &llc_normal_state_trans_18, /* Init pf cycle */ + &llc_common_state_trans_n, + &llc_common_state_trans_11a, /* Timers */ + &llc_common_state_trans_11b, + &llc_common_state_trans_11c, + &llc_common_state_trans_11d, + &llc_normal_state_trans_19, + &llc_normal_state_trans_20a, + &llc_normal_state_trans_20b, + &llc_common_state_trans_n, + &llc_normal_state_trans_8b, /* Receive frames */ + &llc_normal_state_trans_9b, + &llc_normal_state_trans_10, + &llc_normal_state_trans_11b, + &llc_normal_state_trans_11c, + &llc_normal_state_trans_5a, + &llc_normal_state_trans_5b, + &llc_normal_state_trans_5c, + &llc_normal_state_trans_6a, + &llc_normal_state_trans_6b, + &llc_normal_state_trans_7, + &llc_normal_state_trans_8a, + &llc_normal_state_trans_9a, + &llc_normal_state_trans_11a, + &llc_normal_state_trans_12, + &llc_normal_state_trans_13a, + &llc_normal_state_trans_13b, + &llc_normal_state_trans_13c, + &llc_normal_state_trans_14, + &llc_normal_state_trans_15a, + &llc_normal_state_trans_15b, + &llc_normal_state_trans_16a, + &llc_normal_state_trans_16b, + &llc_normal_state_trans_17, + &llc_common_state_trans_3, + &llc_common_state_trans_4, + &llc_common_state_trans_5, + &llc_common_state_trans_6, + &llc_common_state_trans_7a, + &llc_common_state_trans_7b, + &llc_common_state_trans_8a, + &llc_common_state_trans_8b, + &llc_common_state_trans_8c, + &llc_common_state_trans_9, + /*&llc_common_state_trans_10, */ + &llc_common_state_trans_n +}; + +/* --------------------- LLC_CONN_STATE_BUSY transitions ------------------- */ +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_1[] = { + llc_conn_ev_qlfy_remote_busy_eq_0, + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_busy_actions_1[] = { + llc_conn_ac_send_i_xxx_x_set_0, + llc_conn_ac_start_ack_tmr_if_not_running, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_1 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_1, + llc_busy_actions_1 +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_2[] = { + llc_conn_ev_qlfy_remote_busy_eq_0, + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_2[] = { + llc_conn_ac_send_i_xxx_x_set_0, + llc_conn_ac_start_ack_tmr_if_not_running, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_2 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_2, + llc_busy_actions_2 +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_2_1[] = { + llc_conn_ev_qlfy_remote_busy_eq_1, + llc_conn_ev_qlfy_set_status_remote_busy, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_busy_actions_2_1[1]; + +static struct llc_conn_state_trans llc_busy_state_trans_2_1 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_2_1, + llc_busy_actions_2_1 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_3[] = { + llc_conn_ev_qlfy_data_flag_eq_1, + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_busy_actions_3[] = { + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_start_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_3 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_REJ, + llc_busy_ev_qfyrs_3, + llc_busy_actions_3 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_4[] = { + llc_conn_ev_qlfy_data_flag_eq_1, + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_4[] = { + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_start_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_4 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_REJ, + llc_busy_ev_qfyrs_4, + llc_busy_actions_4 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_5[] = { + llc_conn_ev_qlfy_data_flag_eq_0, + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_busy_actions_5[] = { + llc_conn_ac_send_rr_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_5 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_NORMAL, + llc_busy_ev_qfyrs_5, + llc_busy_actions_5 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_6[] = { + llc_conn_ev_qlfy_data_flag_eq_0, + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_6[] = { + llc_conn_ac_send_rr_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_6 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_NORMAL, + llc_busy_ev_qfyrs_6, + llc_busy_actions_6 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_7[] = { + llc_conn_ev_qlfy_data_flag_eq_2, + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_busy_actions_7[] = { + llc_conn_ac_send_rr_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_7 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_REJ, + llc_busy_ev_qfyrs_7, + llc_busy_actions_7 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_8[] = { + llc_conn_ev_qlfy_data_flag_eq_2, + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_8[] = { + llc_conn_ac_send_rr_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_8 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_REJ, + llc_busy_ev_qfyrs_8, + llc_busy_actions_8 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_9a[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + NULL +}; + +static llc_conn_action_t llc_busy_actions_9a[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_9a = { + llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_9a, + llc_busy_actions_9a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_9b[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_busy_actions_9b[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_9b = { + llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_9b, + llc_busy_actions_9b +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_10a[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_10a[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_10a = { + llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_10a, + llc_busy_actions_10a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_10b[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_10b[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_10b = { + llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_10b, + llc_busy_actions_10b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_busy_actions_11[] = { + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_data_flag_1_if_data_flag_eq_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_11 = { + llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_11 +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_busy_actions_12[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_12 = { + llc_conn_ev_rx_i_cmd_pbit_set_1, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_12 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_13a[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + NULL +}; + +static llc_conn_action_t llc_busy_actions_13a[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_upd_p_flag, + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, + llc_conn_ac_set_data_flag_0, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_13a = { + llc_conn_ev_rx_i_rsp_fbit_set_x, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_13a, + llc_busy_actions_13a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_13b[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_busy_actions_13b[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_upd_p_flag, + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, + llc_conn_ac_set_data_flag_0, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_13b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_13b, + llc_busy_actions_13b +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_14a[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_14a[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_14a = { + llc_conn_ev_rx_i_rsp_fbit_set_0, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_14a, + llc_busy_actions_14a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_14b[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_14b[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_14b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_14b, + llc_busy_actions_14b +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_busy_actions_15a[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_15a = { + llc_conn_ev_rx_rr_cmd_pbit_set_0, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_15a +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_busy_actions_15b[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_15b = { + llc_conn_ev_rx_rr_rsp_fbit_set_0, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_15b +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_15c[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_15c[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_15c = { + llc_conn_ev_rx_rr_rsp_fbit_set_1, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_15c, + llc_busy_actions_15c +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_busy_actions_16[] = { + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_16 = { + llc_conn_ev_rx_rr_cmd_pbit_set_1, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_16 +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_busy_actions_17a[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_17a = { + llc_conn_ev_rx_rnr_cmd_pbit_set_0, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_17a +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_busy_actions_17b[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_17b = { + llc_conn_ev_rx_rnr_rsp_fbit_set_0, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_17b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_17c[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_17c[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_17c = { + llc_conn_ev_rx_rnr_rsp_fbit_set_1, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_17c, + llc_busy_actions_17c +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_busy_actions_18[] = { + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_18 = { + llc_conn_ev_rx_rnr_cmd_pbit_set_1, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_18 +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_19a[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_busy_actions_19a[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_19a = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_19a, + llc_busy_actions_19a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_19b[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + NULL +}; + +static llc_conn_action_t llc_busy_actions_19b[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_19b = { + llc_conn_ev_rx_rej_rsp_fbit_set_x, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_19b, + llc_busy_actions_19b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_20a[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_20a[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_20a = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_20a, + llc_busy_actions_20a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_20b[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_busy_actions_20b[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_20b = { + llc_conn_ev_rx_rej_rsp_fbit_set_0, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_20b, + llc_busy_actions_20b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_busy_actions_21[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_21 = { + llc_conn_ev_rx_rej_cmd_pbit_set_1, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_busy_actions_21 +}; + +/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_22[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_busy_actions_22[] = { + llc_conn_ac_send_rnr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_22 = { + llc_conn_ev_init_p_f_cycle, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_22, + llc_busy_actions_22 +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_23[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_busy_actions_23[] = { + llc_conn_ac_send_rnr_cmd_p_set_1, + llc_conn_ac_rst_vs, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_23 = { + llc_conn_ev_p_tmr_exp, + LLC_CONN_STATE_AWAIT_BUSY, + llc_busy_ev_qfyrs_23, + llc_busy_actions_23 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_24a[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_busy_actions_24a[] = { + llc_conn_ac_send_rnr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + llc_conn_ac_rst_vs, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_24a = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_AWAIT_BUSY, + llc_busy_ev_qfyrs_24a, + llc_busy_actions_24a +}; + +/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_24b[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_busy_actions_24b[] = { + llc_conn_ac_send_rnr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + llc_conn_ac_rst_vs, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_24b = { + llc_conn_ev_busy_tmr_exp, + LLC_CONN_STATE_AWAIT_BUSY, + llc_busy_ev_qfyrs_24b, + llc_busy_actions_24b +}; + +/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_25[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_busy_actions_25[] = { + llc_conn_ac_send_rnr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + llc_conn_ac_rst_vs, + llc_conn_ac_set_data_flag_1, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_25 = { + llc_conn_ev_rej_tmr_exp, + LLC_CONN_STATE_AWAIT_BUSY, + llc_busy_ev_qfyrs_25, + llc_busy_actions_25 +}; + +/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_26[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_busy_actions_26[] = { + llc_conn_ac_set_data_flag_1, + NULL +}; + +static struct llc_conn_state_trans llc_busy_state_trans_26 = { + llc_conn_ev_rej_tmr_exp, + LLC_CONN_STATE_BUSY, + llc_busy_ev_qfyrs_26, + llc_busy_actions_26 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_busy_state_transitions[] = { + &llc_common_state_trans_1, /* Request */ + &llc_common_state_trans_2, + &llc_busy_state_trans_1, + &llc_busy_state_trans_2, + &llc_busy_state_trans_2_1, + &llc_common_state_trans_n, + &llc_busy_state_trans_3, /* Local busy */ + &llc_busy_state_trans_4, + &llc_busy_state_trans_5, + &llc_busy_state_trans_6, + &llc_busy_state_trans_7, + &llc_busy_state_trans_8, + &llc_common_state_trans_n, + &llc_busy_state_trans_22, /* Initiate PF cycle */ + &llc_common_state_trans_n, + &llc_common_state_trans_11a, /* Timer */ + &llc_common_state_trans_11b, + &llc_common_state_trans_11c, + &llc_common_state_trans_11d, + &llc_busy_state_trans_23, + &llc_busy_state_trans_24a, + &llc_busy_state_trans_24b, + &llc_busy_state_trans_25, + &llc_busy_state_trans_26, + &llc_common_state_trans_n, + &llc_busy_state_trans_9a, /* Receive frame */ + &llc_busy_state_trans_9b, + &llc_busy_state_trans_10a, + &llc_busy_state_trans_10b, + &llc_busy_state_trans_11, + &llc_busy_state_trans_12, + &llc_busy_state_trans_13a, + &llc_busy_state_trans_13b, + &llc_busy_state_trans_14a, + &llc_busy_state_trans_14b, + &llc_busy_state_trans_15a, + &llc_busy_state_trans_15b, + &llc_busy_state_trans_15c, + &llc_busy_state_trans_16, + &llc_busy_state_trans_17a, + &llc_busy_state_trans_17b, + &llc_busy_state_trans_17c, + &llc_busy_state_trans_18, + &llc_busy_state_trans_19a, + &llc_busy_state_trans_19b, + &llc_busy_state_trans_20a, + &llc_busy_state_trans_20b, + &llc_busy_state_trans_21, + &llc_common_state_trans_3, + &llc_common_state_trans_4, + &llc_common_state_trans_5, + &llc_common_state_trans_6, + &llc_common_state_trans_7a, + &llc_common_state_trans_7b, + &llc_common_state_trans_8a, + &llc_common_state_trans_8b, + &llc_common_state_trans_8c, + &llc_common_state_trans_9, + /* &llc_common_state_trans_10, */ + &llc_common_state_trans_n +}; + +/* -------------------- LLC_CONN_STATE_REJ transitions ------------------ */ +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_1[] = { + llc_conn_ev_qlfy_remote_busy_eq_0, + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_reject_actions_1[] = { + llc_conn_ac_send_i_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_1 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_1, + llc_reject_actions_1 +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_2[] = { + llc_conn_ev_qlfy_remote_busy_eq_0, + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_2[] = { + llc_conn_ac_send_i_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_2 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_2, + llc_reject_actions_2 +}; + +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_2_1[] = { + llc_conn_ev_qlfy_remote_busy_eq_1, + llc_conn_ev_qlfy_set_status_remote_busy, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_reject_actions_2_1[1]; + +static struct llc_conn_state_trans llc_reject_state_trans_2_1 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_2_1, + llc_reject_actions_2_1 +}; + + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_3[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_reject_actions_3[] = { + llc_conn_ac_send_rnr_xxx_x_set_0, + llc_conn_ac_set_data_flag_2, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_3 = { + llc_conn_ev_local_busy_detected, + LLC_CONN_STATE_BUSY, + llc_reject_ev_qfyrs_3, + llc_reject_actions_3 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_4[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_4[] = { + llc_conn_ac_send_rnr_xxx_x_set_0, + llc_conn_ac_set_data_flag_2, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_4 = { + llc_conn_ev_local_busy_detected, + LLC_CONN_STATE_BUSY, + llc_reject_ev_qfyrs_4, + llc_reject_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_reject_actions_5a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_5a = { + llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_5a +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_reject_actions_5b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_5b = { + llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_5b +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_5c[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_5c[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_5c = { + llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_5c, + llc_reject_actions_5c +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_reject_actions_6[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_6 = { + llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_6 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_7a[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + NULL +}; + +static llc_conn_action_t llc_reject_actions_7a[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_upd_p_flag, + llc_conn_ac_send_ack_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + llc_conn_ac_stop_rej_timer, + NULL + +}; + +static struct llc_conn_state_trans llc_reject_state_trans_7a = { + llc_conn_ev_rx_i_rsp_fbit_set_x, + LLC_CONN_STATE_NORMAL, + llc_reject_ev_qfyrs_7a, + llc_reject_actions_7a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_7b[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_reject_actions_7b[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_upd_p_flag, + llc_conn_ac_send_ack_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy_if_f_eq_1, + llc_conn_ac_stop_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_7b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_reject_ev_qfyrs_7b, + llc_reject_actions_7b +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_8a[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_8a[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_ack_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_stop_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_8a = { + llc_conn_ev_rx_i_rsp_fbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_reject_ev_qfyrs_8a, + llc_reject_actions_8a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_8b[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_8b[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_ack_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_stop_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_8b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, + LLC_CONN_STATE_NORMAL, + llc_reject_ev_qfyrs_8b, + llc_reject_actions_8b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_reject_actions_9[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_ack_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_stop_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_9 = { + llc_conn_ev_rx_i_cmd_pbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_9 +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_reject_actions_10a[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_10a = { + llc_conn_ev_rx_rr_cmd_pbit_set_0, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_10a +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_reject_actions_10b[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_10b = { + llc_conn_ev_rx_rr_rsp_fbit_set_0, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_10b +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_10c[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_10c[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_10c = { + llc_conn_ev_rx_rr_rsp_fbit_set_1, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_10c, + llc_reject_actions_10c +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_reject_actions_11[] = { + llc_conn_ac_send_ack_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_11 = { + llc_conn_ev_rx_rr_cmd_pbit_set_1, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_11 +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_reject_actions_12a[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_12a = { + llc_conn_ev_rx_rnr_cmd_pbit_set_0, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_12a +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_reject_actions_12b[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_12b = { + llc_conn_ev_rx_rnr_rsp_fbit_set_0, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_12b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_12c[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_12c[] = { + llc_conn_ac_upd_p_flag, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_12c = { + llc_conn_ev_rx_rnr_rsp_fbit_set_1, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_12c, + llc_reject_actions_12c +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_reject_actions_13[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_13 = { + llc_conn_ev_rx_rnr_cmd_pbit_set_1, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_13 +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_14a[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_reject_actions_14a[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_14a = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_14a, + llc_reject_actions_14a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_14b[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + NULL +}; + +static llc_conn_action_t llc_reject_actions_14b[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_p_flag, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_14b = { + llc_conn_ev_rx_rej_rsp_fbit_set_x, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_14b, + llc_reject_actions_14b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_15a[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_15a[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_15a = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_15a, + llc_reject_actions_15a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_15b[] = { + llc_conn_ev_qlfy_p_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_reject_actions_15b[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_15b = { + llc_conn_ev_rx_rej_rsp_fbit_set_0, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_15b, + llc_reject_actions_15b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_reject_actions_16[] = { + llc_conn_ac_set_vs_nr, + llc_conn_ac_upd_nr_received, + llc_conn_ac_resend_i_rsp_f_set_1, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_16 = { + llc_conn_ev_rx_rej_cmd_pbit_set_1, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_reject_actions_16 +}; + +/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_17[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_reject_actions_17[] = { + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_17 = { + llc_conn_ev_init_p_f_cycle, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_17, + llc_reject_actions_17 +}; + +/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_18[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_reject_actions_18[] = { + llc_conn_ac_send_rej_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_start_rej_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_18 = { + llc_conn_ev_rej_tmr_exp, + LLC_CONN_STATE_REJ, + llc_reject_ev_qfyrs_18, + llc_reject_actions_18 +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_19[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_reject_actions_19[] = { + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_start_rej_timer, + llc_conn_ac_inc_retry_cnt_by_1, + llc_conn_ac_rst_vs, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_19 = { + llc_conn_ev_p_tmr_exp, + LLC_CONN_STATE_AWAIT_REJ, + llc_reject_ev_qfyrs_19, + llc_reject_actions_19 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_20a[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_reject_actions_20a[] = { + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_start_rej_timer, + llc_conn_ac_inc_retry_cnt_by_1, + llc_conn_ac_rst_vs, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_20a = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_AWAIT_REJ, + llc_reject_ev_qfyrs_20a, + llc_reject_actions_20a +}; + +/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_20b[] = { + llc_conn_ev_qlfy_p_flag_eq_0, + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_reject_actions_20b[] = { + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_start_rej_timer, + llc_conn_ac_inc_retry_cnt_by_1, + llc_conn_ac_rst_vs, + NULL +}; + +static struct llc_conn_state_trans llc_reject_state_trans_20b = { + llc_conn_ev_busy_tmr_exp, + LLC_CONN_STATE_AWAIT_REJ, + llc_reject_ev_qfyrs_20b, + llc_reject_actions_20b +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_reject_state_transitions[] = { + &llc_common_state_trans_1, /* Request */ + &llc_common_state_trans_2, + &llc_common_state_trans_n, + &llc_reject_state_trans_1, + &llc_reject_state_trans_2, + &llc_reject_state_trans_2_1, + &llc_reject_state_trans_3, /* Local busy */ + &llc_reject_state_trans_4, + &llc_common_state_trans_n, + &llc_reject_state_trans_17, /* Initiate PF cycle */ + &llc_common_state_trans_n, + &llc_common_state_trans_11a, /* Timer */ + &llc_common_state_trans_11b, + &llc_common_state_trans_11c, + &llc_common_state_trans_11d, + &llc_reject_state_trans_18, + &llc_reject_state_trans_19, + &llc_reject_state_trans_20a, + &llc_reject_state_trans_20b, + &llc_common_state_trans_n, + &llc_common_state_trans_3, /* Receive frame */ + &llc_common_state_trans_4, + &llc_common_state_trans_5, + &llc_common_state_trans_6, + &llc_common_state_trans_7a, + &llc_common_state_trans_7b, + &llc_common_state_trans_8a, + &llc_common_state_trans_8b, + &llc_common_state_trans_8c, + &llc_common_state_trans_9, + /* &llc_common_state_trans_10, */ + &llc_reject_state_trans_5a, + &llc_reject_state_trans_5b, + &llc_reject_state_trans_5c, + &llc_reject_state_trans_6, + &llc_reject_state_trans_7a, + &llc_reject_state_trans_7b, + &llc_reject_state_trans_8a, + &llc_reject_state_trans_8b, + &llc_reject_state_trans_9, + &llc_reject_state_trans_10a, + &llc_reject_state_trans_10b, + &llc_reject_state_trans_10c, + &llc_reject_state_trans_11, + &llc_reject_state_trans_12a, + &llc_reject_state_trans_12b, + &llc_reject_state_trans_12c, + &llc_reject_state_trans_13, + &llc_reject_state_trans_14a, + &llc_reject_state_trans_14b, + &llc_reject_state_trans_15a, + &llc_reject_state_trans_15b, + &llc_reject_state_trans_16, + &llc_common_state_trans_n +}; + +/* -------------------- LLC_CONN_STATE_AWAIT transitions ------------------- */ +/* State transitions for LLC_CONN_EV_DATA_REQ event */ +static llc_conn_ev_qfyr_t llc_await_ev_qfyrs_1_0[] = { + llc_conn_ev_qlfy_set_status_refuse, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_await_actions_1_0[1]; + +static struct llc_conn_state_trans llc_await_state_trans_1_0 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_AWAIT, + llc_await_ev_qfyrs_1_0, + llc_await_actions_1_0 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_action_t llc_await_actions_1[] = { + llc_conn_ac_send_rnr_xxx_x_set_0, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_1 = { + llc_conn_ev_local_busy_detected, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_1 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_actions_2[] = { + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_start_rej_timer, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_2 = { + llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_2 +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_actions_3a[] = { + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_start_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_3a = { + llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_3a +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_actions_3b[] = { + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_start_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_3b = { + llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_3b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_actions_4[] = { + llc_conn_ac_send_rej_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_start_rej_timer, + llc_conn_ac_start_p_timer, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_4 = { + llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_5[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_stop_p_timer, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_5 = { + llc_conn_ev_rx_i_rsp_fbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_5 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_6a[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_rr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_6a = { + llc_conn_ev_rx_i_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_6a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_6b[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_rr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_6b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_6b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_7[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_7 = { + llc_conn_ev_rx_i_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_7 +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_8a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_8a = { + llc_conn_ev_rx_rr_rsp_fbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_8a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_8b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_8b = { + llc_conn_ev_rx_rej_rsp_fbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_8b +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_9a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_9a = { + llc_conn_ev_rx_rr_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_9a +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_9b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_9b = { + llc_conn_ev_rx_rr_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_9b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_9c[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_9c = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_9c +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_9d[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_9d = { + llc_conn_ev_rx_rej_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_9d +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_10a[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_10a = { + llc_conn_ev_rx_rr_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_10a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_10b[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_10b = { + llc_conn_ev_rx_rej_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_10b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_11[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_11 = { + llc_conn_ev_rx_rnr_rsp_fbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_11 +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_12a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_12a = { + llc_conn_ev_rx_rnr_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_12a +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_actions_12b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_12b = { + llc_conn_ev_rx_rnr_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_12b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_actions_13[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_13 = { + llc_conn_ev_rx_rnr_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_actions_13 +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_await_ev_qfyrs_14[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_await_actions_14[] = { + llc_conn_ac_send_rr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_await_state_trans_14 = { + llc_conn_ev_p_tmr_exp, + LLC_CONN_STATE_AWAIT, + llc_await_ev_qfyrs_14, + llc_await_actions_14 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_await_state_transitions[] = { + &llc_common_state_trans_1, /* Request */ + &llc_common_state_trans_2, + &llc_await_state_trans_1_0, + &llc_common_state_trans_n, + &llc_await_state_trans_1, /* Local busy */ + &llc_common_state_trans_n, + &llc_common_state_trans_n, /* Initiate PF Cycle */ + &llc_common_state_trans_11a, /* Timer */ + &llc_common_state_trans_11b, + &llc_common_state_trans_11c, + &llc_common_state_trans_11d, + &llc_await_state_trans_14, + &llc_common_state_trans_n, + &llc_common_state_trans_3, /* Receive frame */ + &llc_common_state_trans_4, + &llc_common_state_trans_5, + &llc_common_state_trans_6, + &llc_common_state_trans_7a, + &llc_common_state_trans_7b, + &llc_common_state_trans_8a, + &llc_common_state_trans_8b, + &llc_common_state_trans_8c, + &llc_common_state_trans_9, + /* &llc_common_state_trans_10, */ + &llc_await_state_trans_2, + &llc_await_state_trans_3a, + &llc_await_state_trans_3b, + &llc_await_state_trans_4, + &llc_await_state_trans_5, + &llc_await_state_trans_6a, + &llc_await_state_trans_6b, + &llc_await_state_trans_7, + &llc_await_state_trans_8a, + &llc_await_state_trans_8b, + &llc_await_state_trans_9a, + &llc_await_state_trans_9b, + &llc_await_state_trans_9c, + &llc_await_state_trans_9d, + &llc_await_state_trans_10a, + &llc_await_state_trans_10b, + &llc_await_state_trans_11, + &llc_await_state_trans_12a, + &llc_await_state_trans_12b, + &llc_await_state_trans_13, + &llc_common_state_trans_n +}; + +/* ------------------ LLC_CONN_STATE_AWAIT_BUSY transitions ---------------- */ +/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_1_0[] = { + llc_conn_ev_qlfy_set_status_refuse, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_await_busy_actions_1_0[1]; + +static struct llc_conn_state_trans llc_await_busy_state_trans_1_0 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_AWAIT_BUSY, + llc_await_busy_ev_qfyrs_1_0, + llc_await_busy_actions_1_0 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_1[] = { + llc_conn_ev_qlfy_data_flag_eq_1, + NULL +}; + +static llc_conn_action_t llc_await_busy_actions_1[] = { + llc_conn_ac_send_rej_xxx_x_set_0, + llc_conn_ac_start_rej_timer, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_1 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_AWAIT_REJ, + llc_await_busy_ev_qfyrs_1, + llc_await_busy_actions_1 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_2[] = { + llc_conn_ev_qlfy_data_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_await_busy_actions_2[] = { + llc_conn_ac_send_rr_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_2 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_AWAIT, + llc_await_busy_ev_qfyrs_2, + llc_await_busy_actions_2 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_3[] = { + llc_conn_ev_qlfy_data_flag_eq_2, + NULL +}; + +static llc_conn_action_t llc_await_busy_actions_3[] = { + llc_conn_ac_send_rr_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_3 = { + llc_conn_ev_local_busy_cleared, + LLC_CONN_STATE_AWAIT_REJ, + llc_await_busy_ev_qfyrs_3, + llc_await_busy_actions_3 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_busy_actions_4[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_set_data_flag_1, + llc_conn_ac_clear_remote_busy, + llc_conn_ac_resend_i_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_4 = { + llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_busy_actions_5a[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_data_flag_1, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_5a = { + llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_5a +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_busy_actions_5b[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_data_flag_1, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_5b = { + llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_5b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_busy_actions_6[] = { + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_data_flag_1, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_6 = { + llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_6 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_7[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_stop_p_timer, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_data_flag_0, + llc_conn_ac_clear_remote_busy, + llc_conn_ac_resend_i_xxx_x_set_0, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_7 = { + llc_conn_ev_rx_i_rsp_fbit_set_1, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_7 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_8a[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_8a = { + llc_conn_ev_rx_i_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_8a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_8b[] = { + llc_conn_ac_opt_send_rnr_xxx_x_set_0, + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_8b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_8b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_9[] = { + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_data_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_9 = { + llc_conn_ev_rx_i_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_9 +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_10a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_10a = { + llc_conn_ev_rx_rr_rsp_fbit_set_1, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_10a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_10b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_10b = { + llc_conn_ev_rx_rej_rsp_fbit_set_1, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_10b +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_11a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_11a = { + llc_conn_ev_rx_rr_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_11a +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_11b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_11b = { + llc_conn_ev_rx_rr_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_11b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_11c[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_11c = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_11c +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_11d[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_11d = { + llc_conn_ev_rx_rej_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_11d +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_12a[] = { + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_12a = { + llc_conn_ev_rx_rr_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_12a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_12b[] = { + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_12b = { + llc_conn_ev_rx_rej_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_12b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_13[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_13 = { + llc_conn_ev_rx_rnr_rsp_fbit_set_1, + LLC_CONN_STATE_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_13 +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_14a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_14a = { + llc_conn_ev_rx_rnr_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_14a +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_busy_actions_14b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_14b = { + llc_conn_ev_rx_rnr_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_14b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_busy_actions_15[] = { + llc_conn_ac_send_rnr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_15 = { + llc_conn_ev_rx_rnr_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_busy_actions_15 +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_16[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_await_busy_actions_16[] = { + llc_conn_ac_send_rnr_cmd_p_set_1, + llc_conn_ac_start_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_await_busy_state_trans_16 = { + llc_conn_ev_p_tmr_exp, + LLC_CONN_STATE_AWAIT_BUSY, + llc_await_busy_ev_qfyrs_16, + llc_await_busy_actions_16 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_await_busy_state_transitions[] = { + &llc_common_state_trans_1, /* Request */ + &llc_common_state_trans_2, + &llc_await_busy_state_trans_1_0, + &llc_common_state_trans_n, + &llc_await_busy_state_trans_1, /* Local busy */ + &llc_await_busy_state_trans_2, + &llc_await_busy_state_trans_3, + &llc_common_state_trans_n, + &llc_common_state_trans_n, /* Initiate PF cycle */ + &llc_common_state_trans_11a, /* Timer */ + &llc_common_state_trans_11b, + &llc_common_state_trans_11c, + &llc_common_state_trans_11d, + &llc_await_busy_state_trans_16, + &llc_common_state_trans_n, + &llc_await_busy_state_trans_4, /* Receive frame */ + &llc_await_busy_state_trans_5a, + &llc_await_busy_state_trans_5b, + &llc_await_busy_state_trans_6, + &llc_await_busy_state_trans_7, + &llc_await_busy_state_trans_8a, + &llc_await_busy_state_trans_8b, + &llc_await_busy_state_trans_9, + &llc_await_busy_state_trans_10a, + &llc_await_busy_state_trans_10b, + &llc_await_busy_state_trans_11a, + &llc_await_busy_state_trans_11b, + &llc_await_busy_state_trans_11c, + &llc_await_busy_state_trans_11d, + &llc_await_busy_state_trans_12a, + &llc_await_busy_state_trans_12b, + &llc_await_busy_state_trans_13, + &llc_await_busy_state_trans_14a, + &llc_await_busy_state_trans_14b, + &llc_await_busy_state_trans_15, + &llc_common_state_trans_3, + &llc_common_state_trans_4, + &llc_common_state_trans_5, + &llc_common_state_trans_6, + &llc_common_state_trans_7a, + &llc_common_state_trans_7b, + &llc_common_state_trans_8a, + &llc_common_state_trans_8b, + &llc_common_state_trans_8c, + &llc_common_state_trans_9, + /* &llc_common_state_trans_10, */ + &llc_common_state_trans_n +}; + +/* ----------------- LLC_CONN_STATE_AWAIT_REJ transitions --------------- */ +/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */ +static llc_conn_ev_qfyr_t llc_await_reject_ev_qfyrs_1_0[] = { + llc_conn_ev_qlfy_set_status_refuse, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_await_reject_actions_1_0[1]; + +static struct llc_conn_state_trans llc_await_reject_state_trans_1_0 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_AWAIT_REJ, + llc_await_reject_ev_qfyrs_1_0, + llc_await_reject_actions_1_0 +}; + +/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */ +static llc_conn_action_t llc_await_rejct_actions_1[] = { + llc_conn_ac_send_rnr_xxx_x_set_0, + llc_conn_ac_set_data_flag_2, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_1 = { + llc_conn_ev_local_busy_detected, + LLC_CONN_STATE_AWAIT_BUSY, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_1 +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_rejct_actions_2a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_2a = { + llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_2a +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_rejct_actions_2b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_2b = { + llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_2b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_rejct_actions_3[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_3 = { + llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_3 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_4[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_stop_p_timer, + llc_conn_ac_stop_rej_timer, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_4 = { + llc_conn_ev_rx_i_rsp_fbit_set_1, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_5a[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_rr_xxx_x_set_0, + llc_conn_ac_stop_rej_timer, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_5a = { + llc_conn_ev_rx_i_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_5a +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_5b[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_rr_xxx_x_set_0, + llc_conn_ac_stop_rej_timer, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_5b = { + llc_conn_ev_rx_i_cmd_pbit_set_0, LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, llc_await_rejct_actions_5b +}; + +/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_6[] = { + llc_conn_ac_inc_vr_by_1, + llc_conn_ac_data_ind, + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_stop_rej_timer, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_6 = { + llc_conn_ev_rx_i_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_6 +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_7a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_7a = { + llc_conn_ev_rx_rr_rsp_fbit_set_1, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_7a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_7b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_7b = { + llc_conn_ev_rx_rej_rsp_fbit_set_1, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_7b +}; + +/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */ +static llc_conn_action_t llc_await_rejct_actions_7c[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_resend_i_xxx_x_set_0, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_7c = { + llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_7c +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_8a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_8a = { + llc_conn_ev_rx_rr_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_8a +}; + +/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_8b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_8b = { + llc_conn_ev_rx_rr_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_8b +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_8c[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_8c = { + llc_conn_ev_rx_rej_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_8c +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_8d[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_8d = { + llc_conn_ev_rx_rej_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_8d +}; + +/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_9a[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_9a = { + llc_conn_ev_rx_rr_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_9a +}; + +/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_9b[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_clear_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_9b = { + llc_conn_ev_rx_rej_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_9b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_10[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_stop_p_timer, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_10 = { + llc_conn_ev_rx_rnr_rsp_fbit_set_1, + LLC_CONN_STATE_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_10 +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_11a[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_11a = { + llc_conn_ev_rx_rnr_cmd_pbit_set_0, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_11a +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */ +static llc_conn_action_t llc_await_rejct_actions_11b[] = { + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_11b = { + llc_conn_ev_rx_rnr_rsp_fbit_set_0, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_11b +}; + +/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */ +static llc_conn_action_t llc_await_rejct_actions_12[] = { + llc_conn_ac_send_rr_rsp_f_set_1, + llc_conn_ac_upd_nr_received, + llc_conn_ac_upd_vs, + llc_conn_ac_set_remote_busy, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_12 = { + llc_conn_ev_rx_rnr_cmd_pbit_set_1, + LLC_CONN_STATE_AWAIT_REJ, + LLC_NO_EVENT_QUALIFIERS, + llc_await_rejct_actions_12 +}; + +/* State transitions for LLC_CONN_EV_P_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_await_rejct_ev_qfyrs_13[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_await_rejct_actions_13[] = { + llc_conn_ac_send_rej_cmd_p_set_1, + llc_conn_ac_stop_p_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_await_rejct_state_trans_13 = { + llc_conn_ev_p_tmr_exp, + LLC_CONN_STATE_AWAIT_REJ, + llc_await_rejct_ev_qfyrs_13, + llc_await_rejct_actions_13 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_await_rejct_state_transitions[] = { + &llc_await_reject_state_trans_1_0, + &llc_common_state_trans_1, /* requests */ + &llc_common_state_trans_2, + &llc_common_state_trans_n, + &llc_await_rejct_state_trans_1, /* local busy */ + &llc_common_state_trans_n, + &llc_common_state_trans_n, /* Initiate PF cycle */ + &llc_await_rejct_state_trans_13, /* timers */ + &llc_common_state_trans_11a, + &llc_common_state_trans_11b, + &llc_common_state_trans_11c, + &llc_common_state_trans_11d, + &llc_common_state_trans_n, + &llc_await_rejct_state_trans_2a, /* receive frames */ + &llc_await_rejct_state_trans_2b, + &llc_await_rejct_state_trans_3, + &llc_await_rejct_state_trans_4, + &llc_await_rejct_state_trans_5a, + &llc_await_rejct_state_trans_5b, + &llc_await_rejct_state_trans_6, + &llc_await_rejct_state_trans_7a, + &llc_await_rejct_state_trans_7b, + &llc_await_rejct_state_trans_7c, + &llc_await_rejct_state_trans_8a, + &llc_await_rejct_state_trans_8b, + &llc_await_rejct_state_trans_8c, + &llc_await_rejct_state_trans_8d, + &llc_await_rejct_state_trans_9a, + &llc_await_rejct_state_trans_9b, + &llc_await_rejct_state_trans_10, + &llc_await_rejct_state_trans_11a, + &llc_await_rejct_state_trans_11b, + &llc_await_rejct_state_trans_12, + &llc_common_state_trans_3, + &llc_common_state_trans_4, + &llc_common_state_trans_5, + &llc_common_state_trans_6, + &llc_common_state_trans_7a, + &llc_common_state_trans_7b, + &llc_common_state_trans_8a, + &llc_common_state_trans_8b, + &llc_common_state_trans_8c, + &llc_common_state_trans_9, + /* &llc_common_state_trans_10, */ + &llc_common_state_trans_n +}; + +/* -------------------- LLC_CONN_STATE_D_CONN transitions ------------------ */ +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event, + * cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_1[] = { + llc_conn_ev_qlfy_cause_flag_eq_1, + llc_conn_ev_qlfy_set_status_conflict, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_1[] = { + llc_conn_ac_send_dm_rsp_f_set_p, + llc_conn_ac_stop_ack_timer, + llc_conn_ac_disc_confirm, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_1 = { + llc_conn_ev_rx_sabme_cmd_pbit_set_x, + LLC_CONN_STATE_ADM, + llc_d_conn_ev_qfyrs_1, + llc_d_conn_actions_1 +}; + +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event, + * cause_flag = 0 + */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_1_1[] = { + llc_conn_ev_qlfy_cause_flag_eq_0, + llc_conn_ev_qlfy_set_status_conflict, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_1_1[] = { + llc_conn_ac_send_dm_rsp_f_set_p, + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_1_1 = { + llc_conn_ev_rx_sabme_cmd_pbit_set_x, + LLC_CONN_STATE_ADM, + llc_d_conn_ev_qfyrs_1_1, + llc_d_conn_actions_1_1 +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event, + * cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_2[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + llc_conn_ev_qlfy_cause_flag_eq_1, + llc_conn_ev_qlfy_set_status_disc, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_2[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_ac_disc_confirm, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_2 = { + llc_conn_ev_rx_ua_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + llc_d_conn_ev_qfyrs_2, + llc_d_conn_actions_2 +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event, + * cause_flag = 0 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_2_1[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + llc_conn_ev_qlfy_cause_flag_eq_0, + llc_conn_ev_qlfy_set_status_disc, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_2_1[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_2_1 = { + llc_conn_ev_rx_ua_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + llc_d_conn_ev_qfyrs_2_1, + llc_d_conn_actions_2_1 +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_d_conn_actions_3[] = { + llc_conn_ac_send_ua_rsp_f_set_p, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_3 = { + llc_conn_ev_rx_disc_cmd_pbit_set_x, + LLC_CONN_STATE_D_CONN, + LLC_NO_EVENT_QUALIFIERS, + llc_d_conn_actions_3 +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event, + * cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_4[] = { + llc_conn_ev_qlfy_cause_flag_eq_1, + llc_conn_ev_qlfy_set_status_disc, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_4[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_ac_disc_confirm, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_4 = { + llc_conn_ev_rx_dm_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + llc_d_conn_ev_qfyrs_4, + llc_d_conn_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event, + * cause_flag = 0 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_4_1[] = { + llc_conn_ev_qlfy_cause_flag_eq_0, + llc_conn_ev_qlfy_set_status_disc, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_4_1[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_4_1 = { + llc_conn_ev_rx_dm_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + llc_d_conn_ev_qfyrs_4_1, + llc_d_conn_actions_4_1 +}; + +/* + * State transition for + * LLC_CONN_EV_DATA_CONN_REQ event + */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_5[] = { + llc_conn_ev_qlfy_set_status_refuse, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_d_conn_actions_5[1]; + +static struct llc_conn_state_trans llc_d_conn_state_trans_5 = { + llc_conn_ev_data_req, LLC_CONN_STATE_D_CONN, + llc_d_conn_ev_qfyrs_5, llc_d_conn_actions_5 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_6[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_6[] = { + llc_conn_ac_send_disc_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_6 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_D_CONN, + llc_d_conn_ev_qfyrs_6, + llc_d_conn_actions_6 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event, cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_7[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + llc_conn_ev_qlfy_cause_flag_eq_1, + llc_conn_ev_qlfy_set_status_failed, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_7[] = { + llc_conn_ac_disc_confirm, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_7 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_ADM, + llc_d_conn_ev_qfyrs_7, + llc_d_conn_actions_7 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event, cause_flag = 0 */ +static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_8[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + llc_conn_ev_qlfy_cause_flag_eq_0, + llc_conn_ev_qlfy_set_status_failed, + NULL +}; + +static llc_conn_action_t llc_d_conn_actions_8[] = { + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_d_conn_state_trans_8 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_ADM, + llc_d_conn_ev_qfyrs_8, + llc_d_conn_actions_8 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_d_conn_state_transitions[] = { + &llc_d_conn_state_trans_5, /* Request */ + &llc_common_state_trans_n, + &llc_common_state_trans_n, /* Local busy */ + &llc_common_state_trans_n, /* Initiate PF cycle */ + &llc_d_conn_state_trans_6, /* Timer */ + &llc_d_conn_state_trans_7, + &llc_d_conn_state_trans_8, + &llc_common_state_trans_n, + &llc_d_conn_state_trans_1, /* Receive frame */ + &llc_d_conn_state_trans_1_1, + &llc_d_conn_state_trans_2, + &llc_d_conn_state_trans_2_1, + &llc_d_conn_state_trans_3, + &llc_d_conn_state_trans_4, + &llc_d_conn_state_trans_4_1, + &llc_common_state_trans_n +}; + +/* -------------------- LLC_CONN_STATE_RESET transitions ------------------- */ +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_rst_actions_1[] = { + llc_conn_ac_set_vs_0, + llc_conn_ac_set_vr_0, + llc_conn_ac_set_s_flag_1, + llc_conn_ac_send_ua_rsp_f_set_p, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_1 = { + llc_conn_ev_rx_sabme_cmd_pbit_set_x, + LLC_CONN_STATE_RESET, + LLC_NO_EVENT_QUALIFIERS, + llc_rst_actions_1 +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event, + * cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_2[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + llc_conn_ev_qlfy_cause_flag_eq_1, + llc_conn_ev_qlfy_set_status_conn, + NULL +}; + +static llc_conn_action_t llc_rst_actions_2[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_ac_set_vs_0, + llc_conn_ac_set_vr_0, + llc_conn_ac_upd_p_flag, + llc_conn_ac_rst_confirm, + llc_conn_ac_set_remote_busy_0, + llc_conn_reset, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_2 = { + llc_conn_ev_rx_ua_rsp_fbit_set_x, + LLC_CONN_STATE_NORMAL, + llc_rst_ev_qfyrs_2, + llc_rst_actions_2 +}; + +/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event, + * cause_flag = 0 */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_2_1[] = { + llc_conn_ev_qlfy_p_flag_eq_f, + llc_conn_ev_qlfy_cause_flag_eq_0, + llc_conn_ev_qlfy_set_status_rst_done, + NULL +}; + +static llc_conn_action_t llc_rst_actions_2_1[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_ac_set_vs_0, + llc_conn_ac_set_vr_0, + llc_conn_ac_upd_p_flag, + llc_conn_ac_rst_confirm, + llc_conn_ac_set_remote_busy_0, + llc_conn_reset, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_2_1 = { + llc_conn_ev_rx_ua_rsp_fbit_set_x, + LLC_CONN_STATE_NORMAL, + llc_rst_ev_qfyrs_2_1, + llc_rst_actions_2_1 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_3[] = { + llc_conn_ev_qlfy_s_flag_eq_1, + llc_conn_ev_qlfy_set_status_rst_done, + NULL +}; + +static llc_conn_action_t llc_rst_actions_3[] = { + llc_conn_ac_set_p_flag_0, + llc_conn_ac_set_remote_busy_0, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_3 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_NORMAL, + llc_rst_ev_qfyrs_3, + llc_rst_actions_3 +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event, + * cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_4[] = { + llc_conn_ev_qlfy_cause_flag_eq_1, + llc_conn_ev_qlfy_set_status_disc, + NULL +}; +static llc_conn_action_t llc_rst_actions_4[] = { + llc_conn_ac_send_dm_rsp_f_set_p, + llc_conn_ac_disc_ind, + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_4 = { + llc_conn_ev_rx_disc_cmd_pbit_set_x, + LLC_CONN_STATE_ADM, + llc_rst_ev_qfyrs_4, + llc_rst_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event, + * cause_flag = 0 */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_4_1[] = { + llc_conn_ev_qlfy_cause_flag_eq_0, + llc_conn_ev_qlfy_set_status_refuse, + NULL +}; + +static llc_conn_action_t llc_rst_actions_4_1[] = { + llc_conn_ac_send_dm_rsp_f_set_p, + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_4_1 = { + llc_conn_ev_rx_disc_cmd_pbit_set_x, + LLC_CONN_STATE_ADM, + llc_rst_ev_qfyrs_4_1, + llc_rst_actions_4_1 +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event, + * cause_flag = 1 */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_5[] = { + llc_conn_ev_qlfy_cause_flag_eq_1, + llc_conn_ev_qlfy_set_status_disc, + NULL +}; + +static llc_conn_action_t llc_rst_actions_5[] = { + llc_conn_ac_disc_ind, + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_5 = { + llc_conn_ev_rx_dm_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + llc_rst_ev_qfyrs_5, + llc_rst_actions_5 +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event, + * cause_flag = 0 */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_5_1[] = { + llc_conn_ev_qlfy_cause_flag_eq_0, + llc_conn_ev_qlfy_set_status_refuse, + NULL +}; + +static llc_conn_action_t llc_rst_actions_5_1[] = { + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_5_1 = { + llc_conn_ev_rx_dm_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + llc_rst_ev_qfyrs_5_1, + llc_rst_actions_5_1 +}; + +/* State transitions for DATA_CONN_REQ event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_6[] = { + llc_conn_ev_qlfy_set_status_refuse, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_rst_actions_6[1]; + +static struct llc_conn_state_trans llc_rst_state_trans_6 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_RESET, + llc_rst_ev_qfyrs_6, + llc_rst_actions_6 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_7[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + llc_conn_ev_qlfy_s_flag_eq_0, + NULL +}; + +static llc_conn_action_t llc_rst_actions_7[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_7 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_RESET, + llc_rst_ev_qfyrs_7, + llc_rst_actions_7 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_8[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + llc_conn_ev_qlfy_s_flag_eq_0, + llc_conn_ev_qlfy_cause_flag_eq_1, + llc_conn_ev_qlfy_set_status_failed, + NULL +}; +static llc_conn_action_t llc_rst_actions_8[] = { + llc_conn_ac_disc_ind, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_8 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_ADM, + llc_rst_ev_qfyrs_8, + llc_rst_actions_8 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_8_1[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + llc_conn_ev_qlfy_s_flag_eq_0, + llc_conn_ev_qlfy_cause_flag_eq_0, + llc_conn_ev_qlfy_set_status_failed, + NULL +}; +static llc_conn_action_t llc_rst_actions_8_1[] = { + llc_conn_ac_disc_ind, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_rst_state_trans_8_1 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_ADM, + llc_rst_ev_qfyrs_8_1, + llc_rst_actions_8_1 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_rst_state_transitions[] = { + &llc_rst_state_trans_6, /* Request */ + &llc_common_state_trans_n, + &llc_common_state_trans_n, /* Local busy */ + &llc_common_state_trans_n, /* Initiate PF cycle */ + &llc_rst_state_trans_3, /* Timer */ + &llc_rst_state_trans_7, + &llc_rst_state_trans_8, + &llc_rst_state_trans_8_1, + &llc_common_state_trans_n, + &llc_rst_state_trans_1, /* Receive frame */ + &llc_rst_state_trans_2, + &llc_rst_state_trans_2_1, + &llc_rst_state_trans_4, + &llc_rst_state_trans_4_1, + &llc_rst_state_trans_5, + &llc_rst_state_trans_5_1, + &llc_common_state_trans_n +}; + +/* -------------------- LLC_CONN_STATE_ERROR transitions ------------------- */ +/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_error_actions_1[] = { + llc_conn_ac_set_vs_0, + llc_conn_ac_set_vr_0, + llc_conn_ac_send_ua_rsp_f_set_p, + llc_conn_ac_rst_ind, + llc_conn_ac_set_p_flag_0, + llc_conn_ac_set_remote_busy_0, + llc_conn_ac_stop_ack_timer, + llc_conn_reset, + NULL +}; + +static struct llc_conn_state_trans llc_error_state_trans_1 = { + llc_conn_ev_rx_sabme_cmd_pbit_set_x, + LLC_CONN_STATE_NORMAL, + LLC_NO_EVENT_QUALIFIERS, + llc_error_actions_1 +}; + +/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_error_actions_2[] = { + llc_conn_ac_send_ua_rsp_f_set_p, + llc_conn_ac_disc_ind, + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_error_state_trans_2 = { + llc_conn_ev_rx_disc_cmd_pbit_set_x, + LLC_CONN_STATE_ADM, + LLC_NO_EVENT_QUALIFIERS, + llc_error_actions_2 +}; + +/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_error_actions_3[] = { + llc_conn_ac_disc_ind, + llc_conn_ac_stop_ack_timer, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_error_state_trans_3 = { + llc_conn_ev_rx_dm_rsp_fbit_set_x, + LLC_CONN_STATE_ADM, + LLC_NO_EVENT_QUALIFIERS, + llc_error_actions_3 +}; + +/* State transitions for LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X event */ +static llc_conn_action_t llc_error_actions_4[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_start_ack_timer, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_cause_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_error_state_trans_4 = { + llc_conn_ev_rx_frmr_rsp_fbit_set_x, + LLC_CONN_STATE_RESET, + LLC_NO_EVENT_QUALIFIERS, + llc_error_actions_4 +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_X event */ +static llc_conn_action_t llc_error_actions_5[] = { + llc_conn_ac_resend_frmr_rsp_f_set_p, + NULL +}; + +static struct llc_conn_state_trans llc_error_state_trans_5 = { + llc_conn_ev_rx_xxx_cmd_pbit_set_x, + LLC_CONN_STATE_ERROR, + LLC_NO_EVENT_QUALIFIERS, + llc_error_actions_5 +}; + +/* State transitions for LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_X event */ +static struct llc_conn_state_trans llc_error_state_trans_6 = { + llc_conn_ev_rx_xxx_rsp_fbit_set_x, + LLC_CONN_STATE_ERROR, + LLC_NO_EVENT_QUALIFIERS, + LLC_NO_TRANSITION_ACTIONS +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_7[] = { + llc_conn_ev_qlfy_retry_cnt_lt_n2, + NULL +}; + +static llc_conn_action_t llc_error_actions_7[] = { + llc_conn_ac_resend_frmr_rsp_f_set_0, + llc_conn_ac_start_ack_timer, + llc_conn_ac_inc_retry_cnt_by_1, + NULL +}; + +static struct llc_conn_state_trans llc_error_state_trans_7 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_ERROR, + llc_error_ev_qfyrs_7, + llc_error_actions_7 +}; + +/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */ +static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_8[] = { + llc_conn_ev_qlfy_retry_cnt_gte_n2, + NULL +}; + +static llc_conn_action_t llc_error_actions_8[] = { + llc_conn_ac_send_sabme_cmd_p_set_x, + llc_conn_ac_set_s_flag_0, + llc_conn_ac_start_ack_timer, + llc_conn_ac_set_retry_cnt_0, + llc_conn_ac_set_cause_flag_0, + NULL +}; + +static struct llc_conn_state_trans llc_error_state_trans_8 = { + llc_conn_ev_ack_tmr_exp, + LLC_CONN_STATE_RESET, + llc_error_ev_qfyrs_8, + llc_error_actions_8 +}; + +/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */ +static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_9[] = { + llc_conn_ev_qlfy_set_status_refuse, + NULL +}; + +/* just one member, NULL, .bss zeroes it */ +static llc_conn_action_t llc_error_actions_9[1]; + +static struct llc_conn_state_trans llc_error_state_trans_9 = { + llc_conn_ev_data_req, + LLC_CONN_STATE_ERROR, + llc_error_ev_qfyrs_9, + llc_error_actions_9 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_error_state_transitions[] = { + &llc_error_state_trans_9, /* Request */ + &llc_common_state_trans_n, + &llc_common_state_trans_n, /* Local busy */ + &llc_common_state_trans_n, /* Initiate PF cycle */ + &llc_error_state_trans_7, /* Timer */ + &llc_error_state_trans_8, + &llc_common_state_trans_n, + &llc_error_state_trans_1, /* Receive frame */ + &llc_error_state_trans_2, + &llc_error_state_trans_3, + &llc_error_state_trans_4, + &llc_error_state_trans_5, + &llc_error_state_trans_6, + &llc_common_state_trans_n +}; + +/* ------------------- LLC_CONN_STATE_TEMP transitions ----------------- */ +/* State transitions for LLC_CONN_EV_DISC_REQ event */ +static llc_conn_action_t llc_temp_actions_1[] = { + llc_conn_ac_stop_all_timers, + llc_conn_ac_send_disc_cmd_p_set_x, + llc_conn_disc, + NULL +}; + +static struct llc_conn_state_trans llc_temp_state_trans_1 = { + llc_conn_ev_disc_req, + LLC_CONN_STATE_ADM, + LLC_NO_EVENT_QUALIFIERS, + llc_temp_actions_1 +}; + +/* + * Array of pointers; + * one to each transition + */ +static struct llc_conn_state_trans *llc_temp_state_transitions[] = { + &llc_temp_state_trans_1, /* requests */ + &llc_common_state_trans_n, + &llc_common_state_trans_n, /* local busy */ + &llc_common_state_trans_n, /* init_pf_cycle */ + &llc_common_state_trans_n, /* timer */ + &llc_common_state_trans_n /* recieve */ +}; + +/* Connection State Transition Table */ +struct llc_conn_state llc_conn_state_table[] = { + { LLC_CONN_STATE_ADM, llc_adm_state_transitions }, + { LLC_CONN_STATE_SETUP, llc_setup_state_transitions }, + { LLC_CONN_STATE_NORMAL, llc_normal_state_transitions }, + { LLC_CONN_STATE_BUSY, llc_busy_state_transitions }, + { LLC_CONN_STATE_REJ, llc_reject_state_transitions }, + { LLC_CONN_STATE_AWAIT, llc_await_state_transitions }, + { LLC_CONN_STATE_AWAIT_BUSY, llc_await_busy_state_transitions }, + { LLC_CONN_STATE_AWAIT_REJ, llc_await_rejct_state_transitions }, + { LLC_CONN_STATE_D_CONN, llc_d_conn_state_transitions }, + { LLC_CONN_STATE_RESET, llc_rst_state_transitions }, + { LLC_CONN_STATE_ERROR, llc_error_state_transitions }, + { LLC_CONN_STATE_TEMP, llc_temp_state_transitions } +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_evnt.c linux.20pre2-ac1/net/llc/llc_evnt.c --- linux.20pre2/net/llc/llc_evnt.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_evnt.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,112 @@ +/* + * llc_evnt.c - LLC station component event match functions + * Description : + * Functions in this module are implementation of station component events. + * Details of events can be found in IEEE-802.2 standard document. + * All functions have one station and one event as input argument. All of + * them return 0 On success and 1 otherwise. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include + +int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + return ev->type == LLC_STATION_EV_TYPE_SIMPLE && + ev->data.a.ev == + LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1; +} + +int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + return ev->type == LLC_STATION_EV_TYPE_SIMPLE && + ev->data.a.ev == + LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1; +} + +int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + return ev->type == LLC_STATION_EV_TYPE_ACK_TMR && + station->retry_count < station->maximum_retry ? 0 : 1; +} + +int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + return ev->type == LLC_STATION_EV_TYPE_ACK_TMR && + station->retry_count == station->maximum_retry ? 0 : 1; +} + +int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_STATION_EV_TYPE_PDU && + !LLC_PDU_IS_CMD(pdu) && /* command PDU */ + !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID && + !pdu->dsap ? 0 : 1; /* NULL DSAP value */ +} + +int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_STATION_EV_TYPE_PDU && + !LLC_PDU_IS_RSP(pdu) && /* response PDU */ + !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && + !pdu->dsap && /* NULL DSAP value */ + !station->xid_r_count ? 0 : 1; +} + +int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_STATION_EV_TYPE_PDU && + !LLC_PDU_IS_RSP(pdu) && /* response PDU */ + !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && + !pdu->dsap && /* NULL DSAP value */ + station->xid_r_count == 1 ? 0 : 1; +} + +int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_STATION_EV_TYPE_PDU && + !LLC_PDU_IS_CMD(pdu) && /* command PDU */ + !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST && + !pdu->dsap ? 0 : 1; /* NULL DSAP */ +} + +int llc_stat_ev_disable_req(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + return ev->type == LLC_STATION_EV_TYPE_PRIM && + ev->data.prim.prim == LLC_DISABLE_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_if.c linux.20pre2-ac1/net/llc/llc_if.c --- linux.20pre2/net/llc/llc_if.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_if.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,514 @@ +/* + * llc_if.c - Defines LLC interface to upper layer + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int llc_sap_req(struct llc_prim_if_block *prim); +static int llc_unitdata_req_handler(struct llc_prim_if_block *prim); +static int llc_test_req_handler(struct llc_prim_if_block *prim); +static int llc_xid_req_handler(struct llc_prim_if_block *prim); +static int llc_data_req_handler(struct llc_prim_if_block *prim); +static int llc_conn_req_handler(struct llc_prim_if_block *prim); +static int llc_disc_req_handler(struct llc_prim_if_block *prim); +static int llc_rst_req_handler(struct llc_prim_if_block *prim); +static int llc_flowcontrol_req_handler(struct llc_prim_if_block *prim); +static int llc_sap_resp(struct llc_prim_if_block *prim); +static int llc_conn_rsp_handler(struct llc_prim_if_block *prim); +static int llc_rst_rsp_handler(struct llc_prim_if_block *prim); +static int llc_no_rsp_handler(struct llc_prim_if_block *prim); + +extern void llc_register_sap(unsigned char sap, + int (*rcvfunc)(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt)); +extern void llc_unregister_sap(unsigned char sap); + +/* table of request handler functions */ +static llc_prim_call_t llc_req_prim[LLC_NBR_PRIMITIVES] = { + llc_unitdata_req_handler, /* order of functions must not change */ + llc_conn_req_handler, + llc_data_req_handler, + llc_disc_req_handler, + llc_rst_req_handler, + llc_flowcontrol_req_handler, + NULL, + llc_xid_req_handler, + llc_test_req_handler, +}; + +/* table of response handler functions */ +static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = { + llc_no_rsp_handler, /* order of functions must not change */ + llc_conn_rsp_handler, + llc_no_rsp_handler, + llc_no_rsp_handler, + llc_rst_rsp_handler, + llc_no_rsp_handler, +}; + +/** + * llc_sap_open - open interface to the upper layers. + * @nw_indicate: pointer to indicate function of upper layer. + * @nw_confirm: pointer to confirm function of upper layer. + * @lsap: SAP number. + * @sap: pointer to allocated SAP (output argument). + * + * Interface function to upper layer. each one who wants to get a SAP + * (for example NetBEUI) should call this function. Returns 0 for + * success, 1 for failure. + */ +struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate, + llc_prim_call_t nw_confirm, u8 lsap) +{ + /* verify this SAP is not already open; if so, return error */ + struct llc_sap *sap; + + MOD_INC_USE_COUNT; + sap = llc_sap_find(lsap); + if (sap) { /* SAP already exists */ + sap = NULL; + goto err; + } + /* sap requested does not yet exist */ + sap = llc_sap_alloc(); + if (!sap) + goto err; + /* allocated a SAP; initialize it and clear out its memory pool */ + sap->laddr.lsap = lsap; + sap->req = llc_sap_req; + sap->resp = llc_sap_resp; + sap->ind = nw_indicate; + sap->conf = nw_confirm; + sap->parent_station = llc_station_get(); + /* initialized SAP; add it to list of SAPs this station manages */ + llc_sap_save(sap); + llc_register_sap(lsap, mac_indicate); +out: return sap; +err: MOD_DEC_USE_COUNT; + goto out; +} + +/** + * llc_sap_close - close interface for upper layers. + * @sap: SAP to be closed. + * + * Close interface function to upper layer. each one who wants to + * close an open SAP (for example NetBEUI) should call this function. + */ +void llc_sap_close(struct llc_sap *sap) +{ + llc_unregister_sap(sap->laddr.lsap); + llc_free_sap(sap); + MOD_DEC_USE_COUNT; +} + +/** + * llc_sap_req - Request interface for upper layers + * @prim: pointer to structure that contains service parameters. + * + * Request interface function to upper layer. each one who wants to + * request a service from LLC, must call this function. details of + * requested service is defined in input argument(prim). Returns 0 for + * success, 1 otherwise. + */ +static int llc_sap_req(struct llc_prim_if_block *prim) +{ + int rc = 1; + + if (prim->prim > 8 || prim->prim == 6) { + printk(KERN_ERR __FUNCTION__ ": invalid primitive %d\n", + prim->prim); + goto out; + } + /* receive REQUEST primitive from network layer; call the appropriate + * primitive handler which then packages it up as an event and sends it + * to the SAP or CONNECTION event handler */ + if (prim->prim < LLC_NBR_PRIMITIVES) + /* valid primitive; call the function to handle it */ + rc = llc_req_prim[prim->prim](prim); +out: return rc; +} + +/** + * llc_unitdata_req_handler - unitdata request interface for upper layers + * @prim: pointer to structure that contains service parameters + * + * Upper layers calls this function when upper layer wants to send data + * using connection-less mode communication (UI pdu). Returns 0 for + * success, 1 otherwise. + */ +static int llc_unitdata_req_handler(struct llc_prim_if_block *prim) +{ + int rc = 1; + struct llc_sap_state_ev *ev; + /* accept data frame from network layer to be sent using connection- + * less mode communication; timeout/retries handled by network layer; + * package primitive as an event and send to SAP event handler */ + struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap); + + if (!sap) + goto out; + ev = llc_sap_alloc_ev(sap); + if (!ev) + goto out; + ev->type = LLC_SAP_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_DATAUNIT_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_REQ; + ev->data.prim.data = prim; + rc = 0; + llc_sap_send_ev(sap, ev); +out: return rc; +} + +/** + * llc_test_req_handler - TEST interface for upper layers. + * @prim: pointer to structure that contains service parameters. + * + * This function is called when upper layer wants to send a TEST pdu. + * Returns 0 for success, 1 otherwise. + */ +static int llc_test_req_handler(struct llc_prim_if_block *prim) +{ + int rc = 1; + struct llc_sap_state_ev *ev; + /* package primitive as an event and send to SAP event handler */ + struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap); + if (!sap) + goto out; + ev = llc_sap_alloc_ev(sap); + if (!ev) + goto out; + ev->type = LLC_SAP_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_TEST_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_REQ; + ev->data.prim.data = prim; + rc = 0; + llc_sap_send_ev(sap, ev); +out: return rc; +} + +/** + * llc_xid_req_handler - XID interface for upper layers + * @prim: pointer to structure that contains service parameters. + * + * This function is called when upper layer wants to send a XID pdu. + * Returns 0 for success, 1 otherwise. + */ +static int llc_xid_req_handler(struct llc_prim_if_block *prim) +{ + int rc = 1; + struct llc_sap_state_ev *ev; + /* package primitive as an event and send to SAP event handler */ + struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap); + + if (!sap) + goto out; + ev = llc_sap_alloc_ev(sap); + if (!ev) + goto out; + ev->type = LLC_SAP_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_XID_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_REQ; + ev->data.prim.data = prim; + rc = 0; + llc_sap_send_ev(sap, ev); +out: return rc; +} + +/** + * llc_data_req_handler - Connection data sending for upper layers. + * @prim: pointer to structure that contains service parameters + * + * This function is called when upper layer wants to send data using + * connection oriented communication mode. during sending data, connection + * will be locked and received frames and expired timers will be queued. + * Returns 0 for success, -ECONNABORTED when the connection already + * closed. and -EBUSY when sending data is not permitted in this state or + * LLC has send an I pdu with p bit set to 1 and is waiting for it's + * response. + */ +static int llc_data_req_handler(struct llc_prim_if_block *prim) +{ + struct llc_conn_state_ev *ev; + int rc = -ECONNABORTED; + /* accept data frame from network layer to be sent using connection + * mode communication; timeout/retries handled by this layer; + * package primitive as an event and send to connection event handler */ + struct sock *sk = prim->data->data.sk; + struct llc_opt *llc = llc_sk(sk); + + lock_sock(sk); + if (llc->state == LLC_CONN_STATE_ADM) + goto out; + rc = -EBUSY; + if (llc_data_accept_state(llc->state)) { /* data_conn_refuse */ + llc->failed_data_req = 1; + goto out; + } + if (llc->p_flag) { + llc->failed_data_req = 1; + goto out; + } + rc = -ENOMEM; + ev = llc_conn_alloc_ev(sk); + if (ev) { + ev->type = LLC_CONN_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_DATA_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_REQ; + ev->data.prim.data = prim; + prim->data->data.skb->dev = llc->dev; + rc = llc_conn_send_ev(sk, ev); + } +out: release_sock(sk); + return rc; +} + +/** + * confirm_impossible - Informs upper layer about failed connection + * @prim: pointer to structure that contains confirmation data. + * + * Informs upper layer about failing in connection establishment. This + * function is called by llc_conn_req_handler. + */ +static void confirm_impossible(struct llc_prim_if_block *prim) +{ + prim->data->conn.status = LLC_STATUS_IMPOSSIBLE; + prim->sap->conf(prim); +} + +/** + * llc_conn_req_handler - Called by upper layer to establish a conn + * @prim: pointer to structure that contains service parameters. + * + * Upper layer calls this to establish an LLC connection with a remote + * machine. this function packages a proper event and sends it connection + * component state machine. Success or failure of connection + * establishment will inform to upper layer via calling it's confirm + * function and passing proper information. + */ +static int llc_conn_req_handler(struct llc_prim_if_block *prim) +{ + int rc = -EBUSY; + struct llc_opt *llc; + struct llc_sap *sap = prim->sap; + struct llc_conn_state_ev *ev; + struct net_device *ddev = mac_dev_peer(prim->data->conn.dev, + prim->data->conn.dev->type, + prim->data->conn.daddr.mac), + *sdev = (ddev->flags & IFF_LOOPBACK) ? + ddev : prim->data->conn.dev; + struct llc_addr laddr, daddr; + /* network layer supplies addressing required to establish connection; + * package as an event and send it to the connection event handler */ + struct sock *sk; + + memcpy(laddr.mac, sdev->dev_addr, sizeof(laddr.mac)); + laddr.lsap = prim->data->conn.saddr.lsap; + memcpy(daddr.mac, ddev->dev_addr, sizeof(daddr.mac)); + daddr.lsap = prim->data->conn.daddr.lsap; + sk = llc_find_sock(sap, &daddr, &laddr); + if (sk) { + confirm_impossible(prim); + goto out_put; + } + rc = -ENOMEM; + if (prim->data->conn.sk) { + sk = prim->data->conn.sk; + if (llc_sock_init(sk)) + goto out; + } else { + sk = llc_sock_alloc(); + if (!sk) { + confirm_impossible(prim); + goto out; + } + prim->data->conn.sk = sk; + } + sock_hold(sk); + lock_sock(sk); + /* assign new connection to it's SAP */ + llc_sap_assign_sock(sap, sk); + llc = llc_sk(sk); + memcpy(&llc->daddr, &daddr, sizeof(llc->daddr)); + memcpy(&llc->laddr, &laddr, sizeof(llc->laddr)); + llc->dev = ddev; + llc->link = prim->data->conn.link; + llc->handler = prim->data->conn.handler; + ev = llc_conn_alloc_ev(sk); + if (ev) { + ev->type = LLC_CONN_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_CONN_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_REQ; + ev->data.prim.data = prim; + rc = llc_conn_send_ev(sk, ev); + } + if (rc) { + llc_sap_unassign_sock(sap, sk); + llc_sock_free(sk); + confirm_impossible(prim); + } + release_sock(sk); +out_put: + sock_put(sk); +out: return rc; +} + +/** + * llc_disc_req_handler - Called by upper layer to close a connection + * @prim: pointer to structure that contains service parameters. + * + * Upper layer calls this when it wants to close an established LLC + * connection with a remote machine. this function packages a proper event + * and sends it to connection component state machine. Returns 0 for + * success, 1 otherwise. + */ +static int llc_disc_req_handler(struct llc_prim_if_block *prim) +{ + u16 rc = 1; + struct llc_conn_state_ev *ev; + struct sock* sk = prim->data->disc.sk; + + sock_hold(sk); + lock_sock(sk); + if (llc_sk(sk)->state == LLC_CONN_STATE_ADM || + llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) + goto out; + /* postpone unassigning the connection from its SAP and returning the + * connection until all ACTIONs have been completely executed */ + ev = llc_conn_alloc_ev(sk); + if (!ev) + goto out; + ev->type = LLC_CONN_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_DISC_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_REQ; + ev->data.prim.data = prim; + rc = llc_conn_send_ev(sk, ev); +out: release_sock(sk); + sock_put(sk); + return rc; +} + +/** + * llc_rst_req_handler - Resets an established LLC connection + * @prim: pointer to structure that contains service parameters. + * + * Called when upper layer wants to reset an established LLC connection + * with a remote machine. this function packages a proper event and sends + * it to connection component state machine. Returns 0 for success, 1 + * otherwise. + */ +static int llc_rst_req_handler(struct llc_prim_if_block *prim) +{ + int rc = 1; + struct sock *sk = prim->data->res.sk; + struct llc_conn_state_ev *ev; + + lock_sock(sk); + ev = llc_conn_alloc_ev(sk); + if (ev) { + ev->type = LLC_CONN_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_RESET_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_REQ; + ev->data.prim.data = prim; + rc = llc_conn_send_ev(sk, ev); + } + release_sock(sk); + return rc; +} + +/* We don't support flow control. The original code from procom has + * some bits, but for now I'm cleaning this */ +static int llc_flowcontrol_req_handler(struct llc_prim_if_block *prim) +{ + return 1; +} + +/** + * llc_sap_resp - Sends response to peer + * @prim: pointer to structure that contains service parameters + * + * This function is a interface function to upper layer. each one who + * wants to response to an indicate can call this function via calling + * sap_resp with proper service parameters. Returns 0 for success, 1 + * otherwise. + */ +static int llc_sap_resp(struct llc_prim_if_block *prim) +{ + u16 rc = 1; + /* network layer RESPONSE primitive received; package primitive + * as an event and send it to the connection event handler */ + if (prim->prim < LLC_NBR_PRIMITIVES) + /* valid primitive; call the function to handle it */ + rc = llc_resp_prim[prim->prim](prim); + return rc; +} + +/** + * llc_conn_rsp_handler - Response to connect indication + * @prim: pointer to structure that contains response info. + * + * Response to connect indication. + */ +static int llc_conn_rsp_handler(struct llc_prim_if_block *prim) +{ + struct sock *sk = prim->data->conn.sk; + + llc_sk(sk)->link = prim->data->conn.link; + return 0; +} + +/** + * llc_rst_rsp_handler - Response to RESET indication + * @prim: pointer to structure that contains response info + * + * Returns 0 for success, 1 otherwise + */ +static int llc_rst_rsp_handler(struct llc_prim_if_block *prim) +{ + int rc = 1; + /* network layer supplies connection handle; map it to a connection; + * package as event and send it to connection event handler */ + struct sock *sk = prim->data->res.sk; + struct llc_conn_state_ev *ev = llc_conn_alloc_ev(sk); + + if (ev) { + ev->type = LLC_CONN_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_RESET_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_RESP; + ev->data.prim.data = prim; + rc = llc_conn_send_ev(sk, ev); + } + return rc; +} + +static int llc_no_rsp_handler(struct llc_prim_if_block *prim) +{ + return 0; +} + +EXPORT_SYMBOL(llc_sap_open); +EXPORT_SYMBOL(llc_sap_close); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_mac.c linux.20pre2-ac1/net/llc/llc_mac.c --- linux.20pre2/net/llc/llc_mac.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_mac.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,311 @@ +/* + * llc_mac.c - Manages interface between LLC and MAC + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_TR +extern void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh, + struct net_device *dev); +#endif +/* function prototypes */ +static void fix_up_incoming_skb(struct sk_buff *skb); + +/** + * mac_send_pdu - Sends PDU to specific device. + * @skb: pdu which must be sent + * + * If module is not initialized then returns failure, else figures out + * where to direct this PDU. Sends PDU to specific device, at this point a + * device must has been assigned to the PDU; If not, can't transmit the + * PDU. PDU sent to MAC layer, is free to re-send at a later time. Returns + * 0 on success, 1 for failure. + */ +int mac_send_pdu(struct sk_buff *skb) +{ + struct sk_buff *skb2; + int pri = GFP_ATOMIC, rc = -1; + + if (!skb->dev) { + printk(KERN_ERR __FUNCTION__ ": skb->dev == NULL!"); + goto out; + } + if (skb->sk) + pri = (int)skb->sk->priority; + skb2 = skb_clone(skb, pri); + if (!skb2) + goto out; + rc = 0; + dev_queue_xmit(skb2); +out: return rc; +} + +/** + * mac_indicate - 802.2 entry point from net lower layers + * @skb: received pdu + * @dev: device that receive pdu + * @pt: packet type + * + * When the system receives a 802.2 frame this function is called. It + * checks SAP and connection of received pdu and passes frame to + * llc_pdu_router for sending to proper state machine. If frame is + * related to a busy connection (a connection is sending data now), + * function queues this frame in connection's backlog. + */ +int mac_indicate(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt) +{ + struct llc_sap *sap; + llc_pdu_sn_t *pdu; + u8 dest; + + /* When the interface is in promisc. mode, drop all the crap that it + receives, do not try to analyse it. */ + if (skb->pkt_type == PACKET_OTHERHOST) { + printk(KERN_INFO __FUNCTION__ ": PACKET_OTHERHOST\n"); + goto drop; + } + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + goto out; + fix_up_incoming_skb(skb); + pdu = (llc_pdu_sn_t *)skb->nh.raw; + if (!pdu->dsap) { /* NULL DSAP, refer to station */ + llc_pdu_router(NULL, NULL, skb, 0); + goto out; + } + sap = llc_sap_find(pdu->dsap); + if (!sap) /* unknown SAP */ + goto drop; + llc_decode_pdu_type(skb, &dest); + if (dest == LLC_DEST_SAP) /* type 1 services */ + llc_pdu_router(sap, NULL, skb, LLC_TYPE_1); + else if (dest == LLC_DEST_CONN) { + struct llc_addr saddr, daddr; + struct sock *sk; + + llc_pdu_decode_sa(skb, saddr.mac); + llc_pdu_decode_ssap(skb, &saddr.lsap); + llc_pdu_decode_da(skb, daddr.mac); + llc_pdu_decode_dsap(skb, &daddr.lsap); + + sk = llc_find_sock(sap, &saddr, &daddr); + if (!sk) { /* didn't find an active connection; allocate a + connection to use; associate it with this SAP */ + sk = llc_sock_alloc(); + if (!sk) + goto drop; + memcpy(&llc_sk(sk)->daddr, &saddr, sizeof(saddr)); + llc_sap_assign_sock(sap, sk); + sock_hold(sk); + } + bh_lock_sock(sk); + if (!sk->lock.users) { + /* FIXME: Check this on SMP as it is now calling + * llc_pdu_router _with_ the lock held. + * Old comment: + * With the current code one can't call + * llc_pdu_router with the socket lock held, cause + * it'll route the pdu to the upper layers and it can + * reenter llc and in llc_req_prim will try to grab + * the same lock, maybe we should use spin_trylock_bh + * in the llc_req_prim (llc_data_req_handler, etc) and + * add the request to the backlog, well see... */ + llc_pdu_router(llc_sk(sk)->sap, sk, skb, LLC_TYPE_2); + bh_unlock_sock(sk); + } else { + skb->cb[0] = LLC_PACKET; + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); + } + sock_put(sk); + } else /* unknown or not supported pdu */ + goto drop; +out: return 0; +drop: kfree_skb(skb); + goto out; +} + +/** + * fix_up_incoming_skb - initializes skb pointers + * @skb: This argument points to incoming skb + * + * Initializes internal skb pointer to start of network layer by deriving + * length of LLC header; finds length of LLC control field in LLC header + * by looking at the two lowest-order bits of the first control field + * byte; field is either 3 or 4 bytes long. + */ +static void fix_up_incoming_skb(struct sk_buff *skb) +{ + u8 llc_len = 2; + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->data; + + if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) == LLC_PDU_TYPE_U) + llc_len = 1; + llc_len += 2; + skb_pull(skb, llc_len); + if (skb->protocol == htons(ETH_P_802_2)) { + u16 pdulen = ((struct ethhdr *)skb->mac.raw)->h_proto, + data_size = ntohs(pdulen) - llc_len; + + skb_trim(skb, data_size); + } +} + +/** + * llc_pdu_router - routes received pdus to the upper layers + * @sap: current sap component structure. + * @sk: current connection structure. + * @frame: received frame. + * @type: type of received frame, that is LLC_TYPE_1 or LLC_TYPE_2 + * + * Queues received PDUs from LLC_MAC PDU receive queue until queue is + * empty; examines LLC header to determine the destination of PDU, if DSAP + * is NULL then data unit destined for station else frame destined for SAP + * or connection; finds a matching open SAP, if one, forwards the packet + * to it; if no matching SAP, drops the packet. Returns 0 or the return of + * llc_conn_send_ev (that may well result in the connection being + * destroyed) + */ +int llc_pdu_router(struct llc_sap *sap, struct sock* sk, + struct sk_buff *skb, u8 type) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + int rc = 0; + + if (!pdu->dsap) { + struct llc_station *station = llc_station_get(); + struct llc_station_state_ev *stat_ev = + llc_station_alloc_ev(station); + if (stat_ev) { + stat_ev->type = LLC_STATION_EV_TYPE_PDU; + stat_ev->data.pdu.skb = skb; + stat_ev->data.pdu.reason = 0; + llc_station_send_ev(station, stat_ev); + } + } else if (type == LLC_TYPE_1) { + struct llc_sap_state_ev *sap_ev = llc_sap_alloc_ev(sap); + + if (sap_ev) { + sap_ev->type = LLC_SAP_EV_TYPE_PDU; + sap_ev->data.pdu.skb = skb; + sap_ev->data.pdu.reason = 0; + llc_sap_send_ev(sap, sap_ev); + } + } else if (type == LLC_TYPE_2) { + struct llc_conn_state_ev *conn_ev = llc_conn_alloc_ev(sk); + struct llc_opt *llc = llc_sk(sk); + + if (!llc->dev) + llc->dev = skb->dev; + if (conn_ev) { + conn_ev->type = LLC_CONN_EV_TYPE_PDU; + conn_ev->data.pdu.skb = skb; + conn_ev->data.pdu.reason = 0; + rc = llc_conn_send_ev(sk, conn_ev); + } + } + return rc; +} + +/** + * lan_hdrs_init - fills MAC header fields + * @skb: Address of the frame to initialize its MAC header + * @sa: The MAC source address + * @da: The MAC destination address + * + * Fills MAC header fields, depending on MAC type. Returns 0, If MAC type + * is a valid type and initialization completes correctly 1, otherwise. + */ +u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da) +{ + u8 *saddr; + u8 *daddr; + u16 rc = 0; + + switch (skb->dev->type) { +#ifdef CONFIG_TR + case ARPHRD_IEEE802_TR: { + struct trh_hdr *trh = (struct trh_hdr *) + skb_push(skb, sizeof(*trh)); + struct net_device *dev = skb->dev; + + trh->ac = AC; + trh->fc = LLC_FRAME; + if (sa) + memcpy(trh->saddr, sa, dev->addr_len); + else + memset(trh->saddr, 0, dev->addr_len); + if (da) { + memcpy(trh->daddr, da, dev->addr_len); + tr_source_route(skb, trh, dev); + } + skb->mac.raw = skb->data; + break; + } +#endif + case ARPHRD_ETHER: + case ARPHRD_LOOPBACK: { + unsigned short len = skb->len; + + skb->mac.raw = skb_push(skb, sizeof(struct ethhdr)); + memset(skb->mac.raw, 0, sizeof(struct ethhdr)); + ((struct ethhdr *)skb->mac.raw)->h_proto = htons(len); + daddr = ((struct ethhdr *)skb->mac.raw)->h_dest; + saddr = ((struct ethhdr *)skb->mac.raw)->h_source; + memcpy(daddr, da, ETH_ALEN); + memcpy(saddr, sa, ETH_ALEN); + break; + } + default: + printk(KERN_WARNING "Unknown DEVICE type : %d\n", + skb->dev->type); + rc = 1; + } + return rc; +} + +/** + * mac_dev_peer - search the appropriate dev to send packets to peer + * @current_dev - Current device suggested by upper layer + * @type - hardware type + * @mac - mac address + * + * Check if the we should use loopback to send packets, i.e., if the + * dmac belongs to one of the local interfaces, returning the pointer + * to the loopback &net_device struct or the current_dev if it is not + * local. + */ +struct net_device *mac_dev_peer(struct net_device *current_dev, int type, + u8 *mac) +{ + struct net_device *dev; + + rtnl_lock(); + dev = dev_getbyhwaddr(type, mac); + if (dev) + dev = __dev_get_by_name("lo"); + rtnl_unlock(); + return dev ? : current_dev; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_main.c linux.20pre2-ac1/net/llc/llc_main.c --- linux.20pre2/net/llc/llc_main.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_main.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,629 @@ +/* + * llc_main.c - This module contains main functions to manage station, saps + * and connections of the LLC. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* static function prototypes */ +static void llc_station_service_events(struct llc_station *station); +static void llc_station_free_ev(struct llc_station *station, + struct llc_station_state_ev *ev); +static void llc_station_send_pdus(struct llc_station *station); +static u16 llc_station_next_state(struct llc_station *station, + struct llc_station_state_ev *ev); +static u16 llc_exec_station_trans_actions(struct llc_station *station, + struct llc_station_state_trans *trans, + struct llc_station_state_ev *ev); +static struct llc_station_state_trans * + llc_find_station_trans(struct llc_station *station, + struct llc_station_state_ev *ev); +static int llc_rtn_all_conns(struct llc_sap *sap); + +extern void llc_register_sap(unsigned char sap, + int (*rcvfunc)(struct sk_buff *skb, + struct net_device *dev, + struct packet_type *pt)); +extern void llc_unregister_sap(unsigned char sap); + +static struct llc_station llc_main_station; /* only one of its kind */ +struct llc_prim_if_block llc_ind_prim, llc_cfm_prim; +static union llc_u_prim_data llc_ind_data_prim, llc_cfm_data_prim; + +/** + * llc_sap_alloc - allocates and initializes sap. + * + * Allocates and initializes sap. + */ +struct llc_sap *llc_sap_alloc(void) +{ + struct llc_sap *sap = kmalloc(sizeof(*sap), GFP_ATOMIC); + + if (sap) { + memset(sap, 0, sizeof(*sap)); + sap->state = LLC_SAP_STATE_ACTIVE; + memcpy(sap->laddr.mac, llc_main_station.mac_sa, ETH_ALEN); + spin_lock_init(&sap->sk_list.lock); + INIT_LIST_HEAD(&sap->sk_list.list); + skb_queue_head_init(&sap->mac_pdu_q); + } + return sap; +} + +/** + * llc_free_sap - frees a sap + * @sap: Address of the sap + * + * Frees all associated connections (if any), removes this sap from + * the list of saps in te station and them frees the memory for this sap. + */ +void llc_free_sap(struct llc_sap *sap) +{ + struct llc_station *station = sap->parent_station; + + llc_rtn_all_conns(sap); + spin_lock_bh(&station->sap_list.lock); + list_del(&sap->node); + spin_unlock_bh(&station->sap_list.lock); + kfree(sap); +} + +/** + * llc_sap_save - add sap to station list + * @sap: Address of the sap + * + * Adds a sap to the LLC's station sap list. + */ +void llc_sap_save(struct llc_sap *sap) +{ + spin_lock_bh(&llc_main_station.sap_list.lock); + list_add_tail(&sap->node, &llc_main_station.sap_list.list); + spin_unlock_bh(&llc_main_station.sap_list.lock); +} + +/** + * llc_sap_find - searchs a SAP in station + * @sap_value: sap to be found + * + * Searchs for a sap in the sap list of the LLC's station upon the sap ID. + * Returns the sap or %NULL if not found. + */ +struct llc_sap *llc_sap_find(u8 sap_value) +{ + struct llc_sap* sap = NULL; + struct list_head *entry; + + spin_lock_bh(&llc_main_station.sap_list.lock); + list_for_each(entry, &llc_main_station.sap_list.list) { + sap = list_entry(entry, struct llc_sap, node); + if (sap->laddr.lsap == sap_value) + break; + } + if (entry == &llc_main_station.sap_list.list) /* not found */ + sap = NULL; + spin_unlock_bh(&llc_main_station.sap_list.lock); + return sap; +} + +/** + * llc_backlog_rcv - Processes rx frames and expired timers. + * @sk: LLC sock (p8022 connection) + * @skb: queued rx frame or event + * + * This function processes frames that has received and timers that has + * expired during sending an I pdu (refer to data_req_handler). frames + * queue by mac_indicate function (llc_mac.c) and timers queue by timer + * callback functions(llc_c_ac.c). + */ +static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) +{ + int rc = 0; + struct llc_opt *llc = llc_sk(sk); + + if (skb->cb[0] == LLC_PACKET) { + if (llc->state > 1) /* not closed */ + rc = llc_pdu_router(llc->sap, sk, skb, LLC_TYPE_2); + else + kfree_skb(skb); + } else if (skb->cb[0] == LLC_EVENT) { + struct llc_conn_state_ev *ev = + (struct llc_conn_state_ev *)skb->data; + /* timer expiration event */ + if (llc->state > 1) /* not closed */ + rc = llc_conn_send_ev(sk, ev); + else + llc_conn_free_ev(ev); + kfree_skb(skb); + } + return rc; +} + +/** + * llc_sock_init - Initialize a socket with default llc values. + * @sk: socket to intiailize. + */ +int llc_sock_init(struct sock* sk) +{ + struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC); + int rc = -ENOMEM; + + if (!llc) + goto out; + memset(llc, 0, sizeof(*llc)); + rc = 0; + llc->sk = sk; + llc->state = LLC_CONN_STATE_ADM; + llc->inc_cntr = llc->dec_cntr = 2; + llc->dec_step = llc->connect_step = 1; + llc->ack_timer.expire = LLC_ACK_TIME; + llc->pf_cycle_timer.expire = LLC_P_TIME; + llc->rej_sent_timer.expire = LLC_REJ_TIME; + llc->busy_state_timer.expire = LLC_BUSY_TIME; + llc->n2 = 2; /* max retransmit */ + llc->k = 2; /* tx win size, will adjust dynam */ + llc->rw = 128; /* rx win size (opt and equal to + tx_win of remote LLC) */ + skb_queue_head_init(&llc->pdu_unack_q); + sk->backlog_rcv = llc_backlog_rcv; + llc_sk(sk) = llc; +out: return rc; +} + +/** + * __llc_sock_alloc - Allocates LLC sock + * + * Allocates a LLC sock and initializes it. Returns the new LLC sock + * or %NULL if there's no memory available for one + */ +struct sock *__llc_sock_alloc(void) +{ + struct sock *sk = sk_alloc(PF_LLC, GFP_ATOMIC, 1); + + if (!sk) + goto out; + if (llc_sock_init(sk)) + goto outsk; + sock_init_data(NULL, sk); +out: return sk; +outsk: sk_free(sk); + sk = NULL; + goto out; +} + +/** + * __llc_sock_free - Frees a LLC socket + * @sk - socket to free + * + * Frees a LLC socket + */ +void __llc_sock_free(struct sock *sk, u8 free) +{ + struct llc_opt *llc = llc_sk(sk); + + llc->state = LLC_CONN_OUT_OF_SVC; + /* stop all (possibly) running timers */ + llc_conn_ac_stop_all_timers(sk, NULL); + /* handle return of frames on lists */ + printk(KERN_INFO __FUNCTION__ ": unackq=%d, txq=%d\n", + skb_queue_len(&llc->pdu_unack_q), + skb_queue_len(&sk->write_queue)); + skb_queue_purge(&sk->write_queue); + skb_queue_purge(&llc->pdu_unack_q); + if (free) + sock_put(sk); +} + +/** + * llc_sock_reset - resets a connection + * @sk: LLC socket to reset + * + * Resets a connection to the out of service state. Stops its timers + * and frees any frames in the queues of the connection. + */ +void llc_sock_reset(struct sock *sk) +{ + struct llc_opt *llc = llc_sk(sk); + + llc_conn_ac_stop_all_timers(sk, NULL); + skb_queue_purge(&sk->write_queue); + skb_queue_purge(&llc->pdu_unack_q); + llc->remote_busy_flag = 0; + llc->cause_flag = 0; + llc->retry_count = 0; + llc->p_flag = 0; + llc->f_flag = 0; + llc->s_flag = 0; + llc->ack_pf = 0; + llc->first_pdu_Ns = 0; + llc->ack_must_be_send = 0; + llc->dec_step = 1; + llc->inc_cntr = 2; + llc->dec_cntr = 2; + llc->X = 0; + llc->failed_data_req = 0 ; + llc->last_nr = 0; +} + +/** + * llc_rtn_all_conns - Closes all connections of a sap + * @sap: sap to close its connections + * + * Closes all connections of a sap. Returns 0 if all actions complete + * successfully, nonzero otherwise + */ +static int llc_rtn_all_conns(struct llc_sap *sap) +{ + int rc = 0; + union llc_u_prim_data prim_data; + struct llc_prim_if_block prim; + struct list_head *entry, *tmp; + + spin_lock_bh(&sap->sk_list.lock); + if (list_empty(&sap->sk_list.list)) + goto out; + list_for_each_safe(entry, tmp, &sap->sk_list.list) { + struct llc_opt *llc = list_entry(entry, struct llc_opt, node); + + prim.sap = sap; + prim_data.disc.sk = llc->sk; + prim.prim = LLC_DISC_PRIM; + prim.data = &prim_data; + llc->state = LLC_CONN_STATE_TEMP; + if (sap->req(&prim)) + rc = 1; + } +out: spin_unlock_bh(&sap->sk_list.lock); + return rc; +} + +/** + * llc_station_get - get addr of global station. + * + * Returns address of a place to copy the global station to it. + */ +struct llc_station *llc_station_get(void) +{ + return &llc_main_station; +} + +/** + * llc_station_alloc_ev - allocates an event + * @station: Address of the station + * + * Allocates an event in this station. Returns the allocated event on + * success, %NULL otherwise. + */ +struct llc_station_state_ev *llc_station_alloc_ev(struct llc_station *station) +{ + struct llc_station_state_ev *ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + + if (ev) + memset(ev, 0, sizeof(*ev)); + return ev; +} + +/** + * llc_station_send_ev: queue event and try to process queue. + * @station: Address of the station + * @ev: Address of the event + * + * Queues an event (on the station event queue) for handling by the + * station state machine and attempts to process any queued-up events. + */ +void llc_station_send_ev(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + spin_lock_bh(&station->ev_q.lock); + list_add_tail(&ev->node, &station->ev_q.list); + llc_station_service_events(station); + spin_unlock_bh(&station->ev_q.lock); +} + +/** + * llc_station_send_pdu - queues PDU to send + * @station: Address of the station + * @skb: Address of the PDU + * + * Queues a PDU to send to the MAC layer. + */ +void llc_station_send_pdu(struct llc_station *station, struct sk_buff *skb) +{ + skb_queue_tail(&station->mac_pdu_q, skb); + llc_station_send_pdus(station); +} + +/** + * llc_station_send_pdus - tries to send queued PDUs + * @station: Address of the station + * + * Tries to send any PDUs queued in the station mac_pdu_q to the MAC + * layer. + */ +static void llc_station_send_pdus(struct llc_station *station) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&station->mac_pdu_q)) != NULL) { + int rc = mac_send_pdu(skb); + + kfree_skb(skb); + if (rc) + break; + } +} + +/** + * llc_station_free_ev - frees an event + * @station: Address of the station + * @event: Address of the event + * + * Frees an event. + */ +static void llc_station_free_ev(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + struct sk_buff *skb = ev->data.pdu.skb; + + if (ev->type == LLC_STATION_EV_TYPE_PDU) + kfree_skb(skb); + kfree(ev); +} + +/** + * llc_station_service_events - service events in the queue + * @station: Address of the station + * + * Get an event from the station event queue (if any); attempt to service + * the event; if event serviced, get the next event (if any) on the event + * queue; if event not service, re-queue the event on the event queue and + * attempt to service the next event; when serviced all events in queue, + * finished; if don't transition to different state, just service all + * events once; if transition to new state, service all events again. + * Caller must hold station->ev_q.lock. + */ +static void llc_station_service_events(struct llc_station *station) +{ + struct llc_station_state_ev *ev; + struct list_head *entry, *tmp; + + list_for_each_safe(entry, tmp, &station->ev_q.list) { + ev = list_entry(entry, struct llc_station_state_ev, node); + list_del(&ev->node); + llc_station_next_state(station, ev); + } +} + +/** + * llc_station_next_state - processes event and goes to the next state + * @station: Address of the station + * @ev: Address of the event + * + * Processes an event, executes any transitions related to that event and + * updates the state of the station. + */ +static u16 llc_station_next_state(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + u16 rc = 1; + struct llc_station_state_trans *trans; + + if (station->state > LLC_NBR_STATION_STATES) + goto out; + trans = llc_find_station_trans(station, ev); + if (trans) { + /* got the state to which we next transition; perform the + * actions associated with this transition before actually + * transitioning to the next state */ + rc = llc_exec_station_trans_actions(station, trans, ev); + if (!rc) + /* transition station to next state if all actions + * execute successfully; done; wait for next event */ + station->state = trans->next_state; + } else + /* event not recognized in current state; re-queue it for + * processing again at a later time; return failure */ + rc = 0; +out: llc_station_free_ev(station, ev); + return rc; +} + +/** + * llc_find_station_trans - finds transition for this event + * @station: Address of the station + * @ev: Address of the event + * + * Search thru events of the current state of the station until list + * exhausted or it's obvious that the event is not valid for the current + * state. Returns the address of the transition if cound, %NULL otherwise. + */ +static struct llc_station_state_trans * + llc_find_station_trans(struct llc_station *station, + struct llc_station_state_ev *ev) +{ + int i = 0; + struct llc_station_state_trans *rc = NULL; + struct llc_station_state_trans **next_trans; + struct llc_station_state *curr_state = + &llc_station_state_table[station->state - 1]; + + for (next_trans = curr_state->transitions; next_trans[i]->ev; i++) + if (!next_trans[i]->ev(station, ev)) { + rc = next_trans[i]; + break; + } + return rc; +} + +/** + * llc_exec_station_trans_actions - executes actions for transition + * @station: Address of the station + * @trans: Address of the transition + * @ev: Address of the event that caused the transition + * + * Executes actions of a transition of the station state machine. Returns + * 0 if all actions complete successfully, nonzero otherwise. + */ +static u16 llc_exec_station_trans_actions(struct llc_station *station, + struct llc_station_state_trans *trans, + struct llc_station_state_ev *ev) +{ + u16 rc = 0; + llc_station_action_t *next_action; + + for (next_action = trans->ev_actions; + next_action && *next_action; next_action++) + if ((*next_action)(station, ev)) + rc = 1; + return rc; +} + +/** + * llc_alloc_frame - allocates sk_buff for frame + * + * Allocates an sk_buff for frame and initializes sk_buff fields. + * Returns allocated skb or %NULL when out of memory. + */ +struct sk_buff *llc_alloc_frame(void) +{ + struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC); + + if (skb) { + skb_reserve(skb, 50); + skb->nh.raw = skb->h.raw = skb->data; + skb->protocol = htons(ETH_P_802_2); + skb->dev = dev_base->next; + skb->mac.raw = skb->head; + } + return skb; +} + +static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) +{ + struct llc_opt *llc; + struct list_head *sap_entry, *llc_entry; + off_t begin = 0, pos = 0; + int len = 0; + + spin_lock_bh(&llc_main_station.sap_list.lock); + list_for_each(sap_entry, &llc_main_station.sap_list.list) { + struct llc_sap *sap = list_entry(sap_entry, struct llc_sap, + node); + + len += sprintf(bf + len, "lsap=%d\n", sap->laddr.lsap); + spin_lock_bh(&sap->sk_list.lock); + if (list_empty(&sap->sk_list.list)) { + len += sprintf(bf + len, "no connections\n"); + goto unlock; + } + len += sprintf(bf + len, + "connection list:\nstate retr txwin rxwin\n"); + list_for_each(llc_entry, &sap->sk_list.list) { + llc = list_entry(llc_entry, struct llc_opt, node); + len += sprintf(bf + len, " %-5d%-5d%-6d%-5d\n", + llc->state, llc->retry_count, llc->k, + llc->rw); + } +unlock: spin_unlock_bh(&sap->sk_list.lock); + pos = begin + len; + if (pos < offset) { + len = 0; /* Keep dumping into the buffer start */ + begin = pos; + } + if (pos > offset + length) /* We have dumped enough */ + break; + } + spin_unlock_bh(&llc_main_station.sap_list.lock); + + /* The data in question runs from begin to begin + len */ + *start = bf + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Remove unwanted header data from length */ + return len; +} + +static char llc_banner[] __initdata = + KERN_INFO "LLC 2.0 by Procom, 1997, Arnaldo C. Melo, 2001\n" + KERN_INFO "NET4.0 IEEE 802.2 extended support\n"; +static char llc_error_msg[] __initdata = + KERN_ERR "LLC install NOT successful.\n"; + +static int __init llc_init(void) +{ + u16 rc = 0; + struct llc_station_state_ev *ev; + + printk(llc_banner); + INIT_LIST_HEAD(&llc_main_station.ev_q.list); + spin_lock_init(&llc_main_station.ev_q.lock); + INIT_LIST_HEAD(&llc_main_station.sap_list.list); + spin_lock_init(&llc_main_station.sap_list.lock); + skb_queue_head_init(&llc_main_station.mac_pdu_q); + ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + if (!ev) + goto err; + memset(ev, 0, sizeof(*ev)); + if(dev_base->next) + memcpy(llc_main_station.mac_sa, dev_base->next->dev_addr, ETH_ALEN); + else + memset(llc_main_station.mac_sa, 0, ETH_ALEN); + llc_main_station.ack_timer.expires = jiffies + 3 * HZ; + /* initialize the station component */ + llc_register_sap(0, mac_indicate); + llc_main_station.maximum_retry = 1; + llc_main_station.state = LLC_STATION_STATE_DOWN; + ev->type = LLC_STATION_EV_TYPE_SIMPLE; + ev->data.a.ev = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK; + rc = llc_station_next_state(&llc_main_station, ev); + llc_build_offset_table(); + llc_ind_prim.data = &llc_ind_data_prim; + llc_cfm_prim.data = &llc_cfm_data_prim; + proc_net_create("802.2", 0, llc_proc_get_info); + llc_ui_init(); +out: return rc; +err: printk(llc_error_msg); + rc = 1; + goto out; +} + +static void __exit llc_exit(void) +{ + llc_ui_exit(); + llc_unregister_sap(0); + proc_net_remove("802.2"); +} + +module_init(llc_init); +module_exit(llc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Procom, 1997, Arnaldo C. Melo, Jay Schullist, 2001"); +MODULE_DESCRIPTION("LLC 2.0, NET4.0 IEEE 802.2 extended support"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_pdu.c linux.20pre2-ac1/net/llc/llc_pdu.c --- linux.20pre2/net/llc/llc_pdu.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_pdu.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,652 @@ +/* + * llc_pdu.c - access to PDU internals + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include + +static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type); +static int llc_get_llc_hdr_length(u8 pdu_type); +static u8 llc_pdu_get_pf_bit(llc_pdu_sn_t *pdu); + +/** + * llc_pdu_header_init - initializes pdu header + * @skb: input skb that header must be set into it. + * @pdu_type: type of PDU (U, I or S). + * @ssap: source sap. + * @dsap: destination sap. + * @cr: command/response bit (0 or 1). + * + * This function sets DSAP, SSAP and command/Response bit in LLC header. + */ +void llc_pdu_header_init(struct sk_buff *skb, u8 pdu_type, u8 ssap, + u8 dsap, u8 cr) +{ + llc_pdu_un_t *p; + + skb->nh.raw = skb_push(skb, llc_get_llc_hdr_length(pdu_type)); + p = (llc_pdu_un_t *)skb->nh.raw; + p->dsap = dsap; + p->ssap = ssap; + p->ssap |= cr; +} + +void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 pdu_type) +{ + ((llc_pdu_un_t *)skb->nh.raw)->ssap |= pdu_type; +} + +/** + * pdu_set_pf_bit - sets poll/final bit in LLC header + * @pdu_frame: input frame that p/f bit must be set into it. + * @bit_value: poll/final bit (0 or 1). + * + * This function sets poll/final bit in LLC header (based on type of PDU). + * in I or S pdus, p/f bit is right bit of fourth byte in header. in U + * pdus p/f bit is fifth bit of third byte. + */ +void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value) +{ + u8 pdu_type; + + if (llc_pdu_decode_pdu_type(skb, &pdu_type)) + goto out; + switch (pdu_type) { + case LLC_PDU_TYPE_I: + case LLC_PDU_TYPE_S: + ((llc_pdu_sn_t *)skb->nh.raw)->ctrl_2 = + (((llc_pdu_sn_t *)skb->nh.raw)->ctrl_2 & 0xFE) | + bit_value; + break; + case LLC_PDU_TYPE_U: + ((llc_pdu_un_t *)skb->nh.raw)->ctrl_1 |= + (((llc_pdu_un_t *)skb->nh.raw)->ctrl_1 & 0xEF) | + (bit_value << 4); + break; + } +out:; +} + +/** + * llc_pdu_decode_pf_bit - extracs poll/final bit from LLC header + * @skb: input skb that p/f bit must be extracted from it + * @pf_bit: poll/final bit (0 or 1) + * + * This function extracts poll/final bit from LLC header (based on type of + * PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In + * U pdus p/f bit is fifth bit of third byte. + */ +int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit) +{ + u8 pdu_type; + int rc = llc_pdu_decode_pdu_type(skb, &pdu_type); + + if (rc) + goto out; + switch (pdu_type) { + case LLC_PDU_TYPE_I: + case LLC_PDU_TYPE_S: + *pf_bit = ((llc_pdu_sn_t *)skb->nh.raw)->ctrl_2 & + LLC_S_PF_BIT_MASK; + break; + case LLC_PDU_TYPE_U: + *pf_bit = (((llc_pdu_un_t *)skb->nh.raw)->ctrl_1 & + LLC_U_PF_BIT_MASK) >> 4; + break; + } +out: return 0; +} + +/** + * llc_pdu_decode_cr_bit - extracs command response bit from LLC header + * @skb: input skb that c/r bit must be extracted from it. + * @cr_bit: command/response bit (0 or 1). + * + * This function extracts command/response bit from LLC header. this bit + * is right bit of source SAP. + */ +int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit) +{ + *cr_bit = ((llc_pdu_un_t *)skb->nh.raw)->ssap & LLC_PDU_CMD_RSP_MASK; + return 0; +} + +/** + * llc_pdu_decode_sa - extracs source address (MAC) of input frame + * @skb: input skb that source address must be extracted from it. + * @sa: pointer to source address (6 byte array). + * + * This function extracts source address(MAC) of input frame. + */ +int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa) +{ + if (skb->protocol == ntohs(ETH_P_802_2)) + memcpy(sa, ((struct ethhdr *)skb->mac.raw)->h_source, ETH_ALEN); + else if (skb->protocol == ntohs(ETH_P_TR_802_2)) + memcpy(sa, ((struct trh_hdr *)skb->mac.raw)->saddr, ETH_ALEN); + return 0; +} + +/** + * llc_pdu_decode_da - extracts dest address of input frame + * @skb: input skb that destination address must be extracted from it + * @sa: pointer to destination address (6 byte array). + * + * This function extracts destination address(MAC) of input frame. + */ +int llc_pdu_decode_da(struct sk_buff *skb, u8 *da) +{ + if (skb->protocol == ntohs(ETH_P_802_2)) + memcpy(da, ((struct ethhdr *)skb->mac.raw)->h_dest, ETH_ALEN); + else if (skb->protocol == ntohs(ETH_P_TR_802_2)) + memcpy(da, ((struct trh_hdr *)skb->mac.raw)->daddr, ETH_ALEN); + return 0; +} + +/** + * llc_pdu_decode_dsap - extracts dest SAP of input frame + * @skb: input skb that destination SAP must be extracted from it. + * @dsap: destination SAP (output argument). + * + * This function extracts destination SAP of input frame. right bit of + * DSAP designates individual/group SAP. + */ +int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap) +{ + *dsap = ((llc_pdu_un_t *)skb->nh.raw)->dsap & 0xFE; + return 0; +} + +/** + * llc_pdu_decode_ssap - extracts source SAP of input frame + * @skb: input skb that source SAP must be extracted from it. + * @ssap: source SAP (output argument). + * + * This function extracts source SAP of input frame. right bit of SSAP is + * command/response bit. + */ +int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap) +{ + *ssap = ((llc_pdu_un_t *)skb->nh.raw)->ssap & 0xFE; + return 0; +} + +/** + * llc_pdu_init_as_ui_cmd - sets LLC header as UI PDU + * @skb: input skb that header must be set into it. + * + * This function sets third byte of LLC header as a UI PDU. + */ +int llc_pdu_init_as_ui_cmd(struct sk_buff *skb) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_UI; + return 0; +} + +/** + * llc_pdu_init_as_xid_cmd - sets bytes 3, 4 & 5 of LLC header as XID + * @skb: input skb that header must be set into it. + * + * This function sets third,fourth,fifth and sixth bytes of LLC header as + * a XID PDU. + */ +int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, + u8 rx_window) +{ + llc_xid_info_t *xid_info; + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_XID; + pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; + xid_info = (llc_xid_info_t *)(((u8 *)&pdu->ctrl_1) + 1); + xid_info->fmt_id = LLC_XID_FMT_ID; /* 0x81*/ + xid_info->type = svcs_supported; + xid_info->rw = (rx_window << 1); /* size of recieve window */ + skb_put(skb, 3); + return 0; +} + +/** + * llc_pdu_init_as_test_cmd - sets PDU as TEST + * @skb - Address of the skb to build + * + * Sets a PDU as TEST + */ +int llc_pdu_init_as_test_cmd(struct sk_buff *skb) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST; + pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; + return 0; +} + +/** + * llc_pdu_init_as_disc_cmd - Builds DISC PDU + * @skb: Address of the skb to build + * @p_bit: The P bit to set in the PDU + * + * Builds a pdu frame as a DISC command. + */ +int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC; + pdu->ctrl_1 |= (((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK); + return 0; +} + +/** + * pdu_init_as_i_cmd - builds I pdu + * @skb: Address of the skb to build + * @p_bit: The P bit to set in the PDU + * @ns: The sequence number of the data PDU + * @nr: The seq. number of the expected I PDU from the remote + * + * Builds a pdu frame as an I command. + */ +int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_I; + pdu->ctrl_2 = 0; + pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */ + pdu->ctrl_1 |= ((ns << 1) & 0xFE); /* set N(S) in bits 2..8 */ + pdu->ctrl_2 |= ((nr << 1) & 0xFE); /* set N(R) in bits 10..16 */ + return 0; +} + +/** + * pdu_init_as_rej_cmd - builds REJ PDU + * @skb: Address of the skb to build + * @p_bit: The P bit to set in the PDU + * @nr: The seq. number of the expected I PDU from the remote + * + * Builds a pdu frame as a REJ command. + */ +int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_S; + pdu->ctrl_1 |= LLC_2_PDU_CMD_REJ; + pdu->ctrl_2 = 0; + pdu->ctrl_2 |= (p_bit & LLC_S_PF_BIT_MASK); + pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ + pdu->ctrl_2 |= ((nr << 1) & 0xFE); /* set N(R) in bits 10..16 */ + return 0; +} + +/** + * pdu_init_as_rnr_cmd - builds RNR pdu + * @skb: Address of the skb to build + * @p_bit: The P bit to set in the PDU + * @nr: The seq. number of the expected I PDU from the remote + * + * Builds a pdu frame as an RNR command. + */ +int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_S; + pdu->ctrl_1 |= LLC_2_PDU_CMD_RNR; + pdu->ctrl_2 = 0; + pdu->ctrl_2 |= (p_bit & LLC_S_PF_BIT_MASK); + pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ + pdu->ctrl_2 |= ((nr << 1) & 0xFE); /* set N(R) in bits 10..16 */ + return 0; +} + +/** + * pdu_init_as_rr_cmd - Builds RR pdu + * @skb: Address of the skb to build + * @p_bit: The P bit to set in the PDU + * @nr: The seq. number of the expected I PDU from the remote + * + * Builds a pdu frame as an RR command. + */ +int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_S; + pdu->ctrl_1 |= LLC_2_PDU_CMD_RR; + pdu->ctrl_2 = (p_bit & LLC_S_PF_BIT_MASK); + pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ + pdu->ctrl_2 |= ((nr << 1) & 0xFE); /* set N(R) in bits 10..16 */ + return 0; +} + +/** + * pdu_init_as_sabme_cmd - builds SABME pdu + * @skb: Address of the skb to build + * @p_bit: The P bit to set in the PDU + * + * Builds a pdu frame as an SABME command. + */ +int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME; + pdu->ctrl_1 |= (((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK); + return 0; +} + +/** + * pdu_init_as_dm_rsp - builds DM response pdu + * @skb: Address of the skb to build + * @f_bit: The F bit to set in the PDU + * + * Builds a pdu frame as a DM response. + */ +int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_2_PDU_RSP_DM; + pdu->ctrl_1 |= (((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK); + return 0; +} + +/** + * pdu_init_as_xid_rsp - builds XID response PDU + * @skb: Address of the skb to build + * @svcs_supported: The class of the LLC (I or II) + * @rx_window: The size of the receive window of the LLC + * + * Builds a pdu frame as an XID response. + */ +int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, + u8 rx_window) +{ + llc_xid_info_t *xid_info; + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_XID; + pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; + + xid_info = (llc_xid_info_t *)(((u8 *)&pdu->ctrl_1) + 1); + xid_info->fmt_id = LLC_XID_FMT_ID; + xid_info->type = svcs_supported; + xid_info->rw = rx_window << 1; + skb_put(skb, 3); + return 0; +} + +/** + * pdu_init_as_test_rsp - build TEST response PDU + * @skb: Address of the skb to build + * @ev_skb: The received TEST command PDU frame + * + * Builds a pdu frame as a TEST response. + */ +int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb) +{ + int dsize; + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST; + pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; + if (ev_skb->protocol == ntohs(ETH_P_802_2)) { + dsize = ntohs(((struct ethhdr *)ev_skb->mac.raw)->h_proto) - 3; + memcpy(((u8 *)skb->nh.raw) + 3, + ((u8 *)ev_skb->nh.raw) + 3, dsize); + skb_put(skb, dsize); + } + return 0; +} + +/** + * pdu_init_as_frmr_rsp - builds FRMR response PDU + * @pdu_frame: Address of the frame to build + * @prev_pdu: The rejected PDU frame + * @f_bit: The F bit to set in the PDU + * @vs: tx state vari value for the data link conn at the rejecting LLC + * @vr: rx state var value for the data link conn at the rejecting LLC + * @vzyxw: completely described in the IEEE Std 802.2 document (Pg 55) + * + * Builds a pdu frame as a FRMR response. + */ +int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, llc_pdu_sn_t *prev_pdu, + u8 f_bit, u8 vs, u8 vr, u8 vzyxw) +{ + llc_frmr_info_t *frmr_info; + u8 prev_pf = 0; + u8 *ctrl; + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_2_PDU_RSP_FRMR; + pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; + + frmr_info = (llc_frmr_info_t *)&pdu->ctrl_2; + ctrl = (u8 *)&prev_pdu->ctrl_1; + FRMR_INFO_SET_REJ_CNTRL(frmr_info,ctrl); + FRMR_INFO_SET_Vs(frmr_info, vs); + FRMR_INFO_SET_Vr(frmr_info, vr); + prev_pf = llc_pdu_get_pf_bit(prev_pdu); + FRMR_INFO_SET_C_R_BIT(frmr_info, prev_pf); + FRMR_INFO_SET_INVALID_PDU_CTRL_IND(frmr_info, vzyxw); + FRMR_INFO_SET_INVALID_PDU_INFO_IND(frmr_info, vzyxw); + FRMR_INFO_SET_PDU_INFO_2LONG_IND(frmr_info, vzyxw); + FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw); + FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw); + skb_put(skb, 5); + return 0; +} + +/** + * pdu_init_as_rr_rsp - builds RR response pdu + * @skb: Address of the skb to build + * @f_bit: The F bit to set in the PDU + * @nr: The seq. number of the expected data PDU from the remote + * + * Builds a pdu frame as an RR response. + */ +int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_S; + pdu->ctrl_1 |= LLC_2_PDU_RSP_RR; + pdu->ctrl_2 = 0; + pdu->ctrl_2 |= (f_bit & LLC_S_PF_BIT_MASK); + pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ + pdu->ctrl_2 |= ((nr << 1) & 0xFE); /* set N(R) in bits 10..16 */ + return 0; +} + +/** + * pdu_init_as_rej_rsp - builds REJ response pdu + * @skb: Address of the skb to build + * @f_bit: The F bit to set in the PDU + * @nr: The seq. number of the expected data PDU from the remote + * + * Builds a pdu frame as a REJ response. + */ +int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_S; + pdu->ctrl_1 |= LLC_2_PDU_RSP_REJ; + pdu->ctrl_2 = 0; + pdu->ctrl_2 |= (f_bit & LLC_S_PF_BIT_MASK); + pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ + pdu->ctrl_2 |= ((nr << 1) & 0xFE); /* set N(R) in bits 10..16 */ + return 0; +} + +/** + * pdu_init_as_rnr_rsp - builds RNR response pdu + * @pdu_frame: Address of the frame to build + * @f_bit: The F bit to set in the PDU + * @nr: The seq. number of the expected data PDU from the remote + * + * Builds a pdu frame as an RNR response. + */ +int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +{ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_S; + pdu->ctrl_1 |= LLC_2_PDU_RSP_RNR; + pdu->ctrl_2 = 0; + pdu->ctrl_2 |= (f_bit & LLC_S_PF_BIT_MASK); + pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ + pdu->ctrl_2 |= ((nr << 1) & 0xFE); /* set N(R) in bits 10..16 */ + return 0; +} + +/** + * pdu_init_as_ua_rsp - builds UA response pdu + * @skb: Address of the frame to build + * @f_bit: The F bit to set in the PDU + * + * Builds a pdu frame as a UA response. + */ +int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + pdu->ctrl_1 = LLC_PDU_TYPE_U; + pdu->ctrl_1 |= LLC_2_PDU_RSP_UA; + pdu->ctrl_1 |= (((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK); + return 0; +} + +/** + * llc_pdu_decode_pdu_type - designates PDU type + * @skb: input skb that type of it must be designated. + * @type: type of PDU (output argument). + * + * This function designates type of PDU (I,S or U). + */ +static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw; + + if (pdu->ctrl_1 & 1) { + if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U) + *type = LLC_PDU_TYPE_U; + else + *type = LLC_PDU_TYPE_S; + } else + *type = LLC_PDU_TYPE_I; + return 0; +} + +/** + * llc_decode_pdu_type - designates component LLC must handle for PDU + * @skb: input skb + * @dest: destination component + * + * This function designates which component of LLC must handle this PDU. + */ +int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest) +{ + u8 type = LLC_DEST_CONN; /* I-PDU or S-PDU type */ + llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw; + + if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) != LLC_PDU_TYPE_U) + goto out; + switch (LLC_U_PDU_CMD(pdu)) { + case LLC_1_PDU_CMD_XID: + case LLC_1_PDU_CMD_UI: + case LLC_1_PDU_CMD_TEST: + type = LLC_DEST_SAP; + break; + case LLC_2_PDU_CMD_SABME: + case LLC_2_PDU_CMD_DISC: + case LLC_2_PDU_RSP_UA: + case LLC_2_PDU_RSP_DM: + case LLC_2_PDU_RSP_FRMR: + break; + default: + type = LLC_DEST_INVALID; + break; + } +out: *dest = type; + return 0; +} + +/** + * get_llc_hdr_len - designates LLC header length + * @pdu_type: type of PDU. + * + * This function designates LLC header length of PDU. header length for I + * and S PDU is 4 and for U is 3 bytes. Returns the length of header. + */ +static int llc_get_llc_hdr_length(u8 pdu_type) +{ + int rtn_val = 0; + + switch (pdu_type) { + case LLC_PDU_TYPE_I: + case LLC_PDU_TYPE_S: + rtn_val = 4; + break; + case LLC_PDU_TYPE_U: + rtn_val = 3; + break; + } + return rtn_val; +} + +/** + * llc_pdu_get_pf_bit - extracts p/f bit of input PDU + * @pdu: pointer to LLC header. + * + * This function extracts p/f bit of input PDU. at first examines type of + * PDU and then extracts p/f bit. Returns the p/f bit. + */ +static u8 llc_pdu_get_pf_bit(llc_pdu_sn_t *pdu) +{ + u8 pdu_type; + u8 pf_bit = 0; + + if (pdu->ctrl_1 & 1) { + if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U) + pdu_type = LLC_PDU_TYPE_U; + else + pdu_type = LLC_PDU_TYPE_S; + } else + pdu_type = LLC_PDU_TYPE_I; + switch (pdu_type) { + case LLC_PDU_TYPE_I: + case LLC_PDU_TYPE_S: + pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK; + break; + case LLC_PDU_TYPE_U: + pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4; + break; + } + return pf_bit; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_s_ac.c linux.20pre2-ac1/net/llc/llc_s_ac.c --- linux.20pre2/net/llc/llc_s_ac.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_s_ac.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,222 @@ +/* + * llc_s_ac.c - actions performed during sap state transition. + * + * Description : + * Functions in this module are implementation of sap component actions. + * Details of actions can be found in IEEE-802.2 standard document. + * All functions have one sap and one event as input argument. All of + * them return 0 On success and 1 otherwise. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include + +/** + * llc_sap_action_unit_data_ind - forward UI PDU to network layer + * @sap: SAP + * @ev: the event to forward + * + * Received a UI PDU from MAC layer; forward to network layer as a + * UNITDATA INDICATION; verify our event is the kind we expect + */ +int llc_sap_action_unitdata_ind(struct llc_sap *sap, + struct llc_sap_state_ev *ev) +{ + llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev); + return 0; +} + +/** + * llc_sap_action_send_ui - sends UI PDU resp to UNITDATA REQ to MAC layer + * @sap: SAP + * @ev: the event to send + * + * Sends a UI PDU to the MAC layer in response to a UNITDATA REQUEST + * primitive from the network layer. Verifies event is a primitive type of + * event. Verify the primitive is a UNITDATA REQUEST. + */ +int llc_sap_action_send_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + struct llc_prim_if_block *prim = ev->data.prim.data; + struct llc_prim_unit_data *prim_data = &prim->data->udata; + struct sk_buff *skb = prim->data->udata.skb; + int rc; + + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, + prim_data->daddr.lsap, LLC_PDU_CMD); + rc = llc_pdu_init_as_ui_cmd(skb); + if (rc) + goto out; + rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); + if (!rc) + llc_sap_send_pdu(sap, skb); +out: return rc; +} + +/** + * llc_sap_action_send_xid_c - send XID PDU as response to XID REQ + * @sap: SAP + * @ev: the event to send + * + * Send a XID command PDU to MAC layer in response to a XID REQUEST + * primitive from the network layer. Verify event is a primitive type + * event. Verify the primitive is a XID REQUEST. + */ +int llc_sap_action_send_xid_c(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + struct llc_prim_if_block *prim = ev->data.prim.data; + struct llc_prim_xid *prim_data = &prim->data->xid; + struct sk_buff *skb = prim_data->skb; + int rc; + + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, + prim_data->daddr.lsap, LLC_PDU_CMD); + rc = llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0); + if (rc) + goto out; + rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); + if (!rc) + llc_sap_send_pdu(sap, skb); +out: return rc; +} + +/** + * llc_sap_action_send_xid_r - send XID PDU resp to MAC for received XID + * @sap: SAP + * @ev: the event to send + * + * Send XID response PDU to MAC in response to an earlier received XID + * command PDU. Verify event is a PDU type event + */ +int llc_sap_action_send_xid_r(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + u8 mac_da[ETH_ALEN], mac_sa[ETH_ALEN], dsap; + int rc = 1; + struct sk_buff *ev_skb = ev->data.pdu.skb; + struct sk_buff *skb; + + llc_pdu_decode_sa(ev_skb, mac_da); + llc_pdu_decode_da(ev_skb, mac_sa); + llc_pdu_decode_ssap(ev_skb, &dsap); + skb = llc_alloc_frame(); + if (!skb) + goto out; + skb->dev = ev_skb->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap, + LLC_PDU_RSP); + rc = llc_pdu_init_as_xid_rsp(skb, LLC_XID_NULL_CLASS_2, 0); + if (rc) + goto out; + rc = lan_hdrs_init(skb, mac_sa, mac_da); + if (!rc) + llc_sap_send_pdu(sap, skb); +out: return rc; +} + +/** + * llc_sap_action_send_test_c - send TEST PDU to MAC in resp to TEST REQ + * @sap: SAP + * @ev: the event to send + * + * Send a TEST command PDU to the MAC layer in response to a TEST REQUEST + * primitive from the network layer. Verify event is a primitive type + * event; verify the primitive is a TEST REQUEST. + */ +int llc_sap_action_send_test_c(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + struct llc_prim_if_block *prim = ev->data.prim.data; + struct llc_prim_test *prim_data = &prim->data->test; + struct sk_buff *skb = prim_data->skb; + int rc; + + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, + prim_data->daddr.lsap, LLC_PDU_CMD); + rc = llc_pdu_init_as_test_cmd(skb); + if (rc) + goto out; + rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); + if (!rc) + llc_sap_send_pdu(sap, skb); +out: return rc; +} + +int llc_sap_action_send_test_r(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + u8 mac_da[ETH_ALEN], mac_sa[ETH_ALEN], dsap; + int rc = 1; + struct sk_buff *ev_skb = ev->data.pdu.skb; + struct sk_buff *skb; + + llc_pdu_decode_sa(ev_skb, mac_da); + llc_pdu_decode_da(ev_skb, mac_sa); + llc_pdu_decode_ssap(ev_skb, &dsap); + skb = llc_alloc_frame(); + if (!skb) + goto out; + skb->dev = ev_skb->dev; + llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap, + LLC_PDU_RSP); + rc = llc_pdu_init_as_test_rsp(skb, ev_skb); + if (rc) + goto out; + rc = lan_hdrs_init(skb, mac_sa, mac_da); + if (!rc) + llc_sap_send_pdu(sap, skb); +out: return rc; +} + +/** + * llc_sap_action_report_status - report data link status to layer mgmt + * @sap: SAP + * @ev: the event to send + * + * Report data link status to layer management. Verify our event is the + * kind we expect. + */ +int llc_sap_action_report_status(struct llc_sap *sap, + struct llc_sap_state_ev *ev) +{ + return 0; +} + +/** + * llc_sap_action_xid_ind - send XID PDU resp to net layer via XID IND + * @sap: SAP + * @ev: the event to send + * + * Send a XID response PDU to the network layer via a XID INDICATION + * primitive. + */ +int llc_sap_action_xid_ind(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev); + return 0; +} + +/** + * llc_sap_action_test_ind - send TEST PDU to net layer via TEST IND + * @sap: SAP + * @ev: the event to send + * + * Send a TEST response PDU to the network layer via a TEST INDICATION + * primitive. Verify our event is a PDU type event. + */ +int llc_sap_action_test_ind(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev); + return 0; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_sap.c linux.20pre2-ac1/net/llc/llc_sap.c --- linux.20pre2/net/llc/llc_sap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_sap.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,259 @@ +/* + * llc_sap.c - driver routines for SAP component. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void llc_sap_free_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev); +static int llc_sap_next_state(struct llc_sap *sap, struct llc_sap_state_ev *ev); +static int llc_exec_sap_trans_actions(struct llc_sap *sap, + struct llc_sap_state_trans *trans, + struct llc_sap_state_ev *ev); +static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, + struct llc_sap_state_ev *ev); + +/** + * llc_sap_assign_sock - adds a connection to a SAP + * @sap: pointer to SAP. + * @conn: pointer to connection. + * + * This function adds a connection to connection_list of a SAP. + */ +void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk) +{ + spin_lock_bh(&sap->sk_list.lock); + llc_sk(sk)->sap = sap; + list_add_tail(&llc_sk(sk)->node, &sap->sk_list.list); + sock_hold(sk); + spin_unlock_bh(&sap->sk_list.lock); +} + +/** + * llc_sap_unassign_sock - removes a connection from SAP + * @sap: SAP + * @sk: pointer to connection + * + * This function removes a connection from connection_list of a SAP. + * List locking is performed by caller (rtn_all_conns). + */ +void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) +{ + spin_lock_bh(&sap->sk_list.lock); + list_del(&llc_sk(sk)->node); + sock_put(sk); + spin_unlock_bh(&sap->sk_list.lock); +} + +/** + * llc_sap_alloc_ev - allocates sap event + * @sap: pointer to SAP + * @ev: allocated event (output argument) + * + * Returns the allocated sap event or %NULL when out of memory. + */ +struct llc_sap_state_ev *llc_sap_alloc_ev(struct llc_sap *sap) +{ + struct llc_sap_state_ev *ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + + if (ev) + memset(ev, 0, sizeof(*ev)); + return ev; +} + +/** + * llc_sap_send_ev - sends event to SAP state machine + * @sap: pointer to SAP + * @ev: pointer to occurred event + * + * After executing actions of the event, upper layer will be indicated + * if needed(on receiving an UI frame). + */ +void llc_sap_send_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + struct llc_prim_if_block *prim; + u8 flag; + + llc_sap_next_state(sap, ev); + flag = ev->ind_cfm_flag; + prim = ev->prim; + if (flag == LLC_IND) { + skb_get(ev->data.pdu.skb); + sap->ind(prim); + } + llc_sap_free_ev(sap, ev); +} + +/** + * llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu. + * @sap: pointer to SAP + * @skb: received pdu + * @ev: pointer to occurred event + */ +void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb, + struct llc_sap_state_ev *ev) +{ + llc_pdu_un_t *pdu; + struct llc_prim_if_block *prim = &llc_ind_prim; + union llc_u_prim_data *prim_data = llc_ind_prim.data; + u8 lfb; + + llc_pdu_decode_sa(skb, prim_data->udata.saddr.mac); + llc_pdu_decode_da(skb, prim_data->udata.daddr.mac); + llc_pdu_decode_dsap(skb, &prim_data->udata.daddr.lsap); + llc_pdu_decode_ssap(skb, &prim_data->udata.saddr.lsap); + prim_data->udata.pri = 0; + prim_data->udata.skb = skb; + pdu = (llc_pdu_un_t *)skb->nh.raw; + switch (LLC_U_PDU_RSP(pdu)) { + case LLC_1_PDU_CMD_TEST: + prim->prim = LLC_TEST_PRIM; + break; + case LLC_1_PDU_CMD_XID: + prim->prim = LLC_XID_PRIM; + break; + case LLC_1_PDU_CMD_UI: + if (skb->protocol == ntohs(ETH_P_TR_802_2)) { + if (((struct trh_hdr *)skb->mac.raw)->rcf) { + lfb = ntohs(((struct trh_hdr *) + skb->mac.raw)->rcf) & + 0x0070; + prim_data->udata.lfb = lfb >> 4; + } else { + lfb = 0xFF; + prim_data->udata.lfb = 0xFF; + } + } + prim->prim = LLC_DATAUNIT_PRIM; + break; + } + prim->data = prim_data; + prim->sap = sap; + ev->ind_cfm_flag = LLC_IND; + ev->prim = prim; +} + +/** + * llc_sap_send_pdu - Sends a frame to MAC layer for transmition + * @sap: pointer to SAP + * @skb: pdu that must be sent + */ +void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb) +{ + mac_send_pdu(skb); + kfree_skb(skb); +} + +/** + * llc_sap_free_ev - frees an sap event + * @sap: pointer to SAP + * @ev: released event + */ +static void llc_sap_free_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + if (ev->type == LLC_SAP_EV_TYPE_PDU) { + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + if (LLC_U_PDU_CMD(pdu) != LLC_1_PDU_CMD_UI) + kfree_skb(ev->data.pdu.skb); + } + kfree(ev); +} + +/** + * llc_sap_next_state - finds transition, execs actions & change SAP state + * @sap: pointer to SAP + * @ev: happened event + * + * This function finds transition that matches with happened event, then + * executes related actions and finally changes state of SAP. It returns + * 0 on success and 1 for failure. + */ +static int llc_sap_next_state(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + int rc = 1; + struct llc_sap_state_trans *trans; + + if (sap->state <= LLC_NBR_SAP_STATES) { + trans = llc_find_sap_trans(sap, ev); + if (trans) { + /* got the state to which we next transition; perform + * the actions associated with this transition before + * actually transitioning to the next state */ + rc = llc_exec_sap_trans_actions(sap, trans, ev); + if (!rc) + /* transition SAP to next state if all actions + execute successfully */ + sap->state = trans->next_state; + } + } + return rc; +} + +/** + * llc_find_sap_trans - finds transition for event + * @sap: pointer to SAP + * @ev: happened event + * + * This function finds transition that matches with happened event. + * Returns the pointer to found transition on success or %NULL for + * failure. + */ +static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, + struct llc_sap_state_ev* ev) +{ + int i = 0; + struct llc_sap_state_trans *rc = NULL; + struct llc_sap_state_trans **next_trans; + struct llc_sap_state *curr_state = &llc_sap_state_table[sap->state - 1]; + /* search thru events for this state until list exhausted or until + * its obvious the event is not valid for the current state */ + for (next_trans = curr_state->transitions; next_trans [i]->ev; i++) + if (!next_trans[i]->ev(sap, ev)) { + /* got event match; return it */ + rc = next_trans[i]; + break; + } + return rc; +} + +/** + * llc_exec_sap_trans_actions - execute actions related to event + * @sap: pointer to SAP + * @trans: pointer to transition that it's actions must be performed + * @ev: happened event. + * + * This function executes actions that is related to happened event. + * Returns 0 for success and 1 for failure of at least one action. + */ +static int llc_exec_sap_trans_actions(struct llc_sap *sap, + struct llc_sap_state_trans *trans, + struct llc_sap_state_ev *ev) +{ + int rc = 0; + llc_sap_action_t *next_action; + + for (next_action = trans->ev_actions; + next_action && *next_action; next_action++) + if ((*next_action)(sap, ev)) + rc = 1; + return rc; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_s_ev.c linux.20pre2-ac1/net/llc/llc_s_ev.c --- linux.20pre2/net/llc/llc_s_ev.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_s_ev.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,101 @@ +/* + * llc_s_ev.c - Defines SAP component events + * + * The followed event functions are SAP component events which are described + * in 802.2 LLC protocol standard document. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include + +int llc_sap_ev_activation_req(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + return ev->type == LLC_SAP_EV_TYPE_SIMPLE && + ev->data.a.ev == LLC_SAP_EV_ACTIVATION_REQ ? 0 : 1; +} + +int llc_sap_ev_rx_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && + !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_UI ? 0 : 1; +} + +int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + return ev->type == LLC_SAP_EV_TYPE_PRIM && + ev->data.prim.prim == LLC_DATAUNIT_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; + +} + +int llc_sap_ev_xid_req(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + return ev->type == LLC_SAP_EV_TYPE_PRIM && + ev->data.prim.prim == LLC_XID_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && + !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1; +} + +int llc_sap_ev_rx_xid_r(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) && + !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1; +} + +int llc_sap_ev_test_req(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + return ev->type == LLC_SAP_EV_TYPE_PRIM && + ev->data.prim.prim == LLC_TEST_PRIM && + ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; +} + +int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && + !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1; +} + +int llc_sap_ev_rx_test_r(struct llc_sap *sap, struct llc_sap_state_ev *ev) +{ + llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw; + + return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) && + !LLC_PDU_TYPE_IS_U(pdu) && + LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1; +} + +int llc_sap_ev_deactivation_req(struct llc_sap *sap, + struct llc_sap_state_ev *ev) +{ + return ev->type == LLC_SAP_EV_TYPE_SIMPLE && + ev->data.a.ev == LLC_SAP_EV_DEACTIVATION_REQ ? 0 : 1; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_sock.c linux.20pre2-ac1/net/llc/llc_sock.c --- linux.20pre2/net/llc/llc_sock.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_sock.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,1755 @@ +/* + * llc_sock.c - LLC User Interface SAPs + * Description: + * Functions in this module are implementation of socket based llc + * communications for the Linux operating system. Support of llc class + * one and class two is provided via SOCK_DGRAM and SOCK_STREAM + * respectively. + * + * An llc2 connection is (mac + sap), only one llc2 sap connection + * is allowed per mac. Though one sap may have multiple mac + sap + * connections. + * + * Copyright (c) 2001 by Jay Schulist + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define dprintk(format, a...) printk(KERN_INFO __FUNCTION__ ": " format, ##a) + +/* remember: uninitialized global data is zeroed because its in .bss */ +static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START; +static u16 llc_ui_sap_link_no_max[256]; +static u8 llc_ui_addrany[IFHWADDRLEN]; +static struct sockaddr_llc llc_ui_addrnull; +static struct proto_ops llc_ui_ops; +static struct sock *llc_ui_sockets; +static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED; + +static int llc_ui_indicate(struct llc_prim_if_block *prim); +static int llc_ui_confirm(struct llc_prim_if_block *prim); +static int llc_ui_wait_for_conn(struct sock *sk, int seconds); +static int llc_ui_wait_for_disc(struct sock *sk, int seconds); + +/** + * llc_ui_next_link_no - return the next unused link number for a sap + * @sap: Address of sap to get link number from. + * + * Return the next unused link number for a given sap. + */ +static inline u16 llc_ui_next_link_no(int sap) +{ + return llc_ui_sap_link_no_max[sap]++; +} + +/** + * llc_ui_mac_match - determines if two mac addresses are the same + * @mac1: First mac address to compare. + * @mac2: Second mac address to compare. + * + * Determines if two given mac address are the same. Returns 0 if there + * is not a complete match up to len, 1 if a complete match up to len is + * found. + */ +static inline u8 llc_ui_mac_match(u8 *mac1, u8 *mac2) +{ + return !memcmp(mac1, mac2, IFHWADDRLEN); +} + +/** + * llc_ui_mac_null - determines if a address is a null mac address + * @mac: Mac address to test if null. + * + * Determines if a given address is a null mac address. Returns 0 if the + * address is not a null mac, 1 if the address is a null mac. + */ +static inline u8 llc_ui_mac_null(u8 *mac) +{ + return !memcmp(mac, llc_ui_addrany, IFHWADDRLEN); +} + +/** + * llc_ui_addr_null - determines if a address structure is null + * @addr: Address to test if null. + */ +static inline u8 llc_ui_addr_null(struct sockaddr_llc *addr) +{ + return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr)); +} + +/** + * llc_ui_protocol_type - return eth protocol for ARP header type + * @arphrd: ARP header type. + * + * Given an ARP header type return the corresponding ethernet protocol. + * Returns 0 if ARP header type not supported or the corresponding + * ethernet protocol type. + */ +static inline u16 llc_ui_protocol_type(u16 arphrd) +{ + u16 rc = htons(ETH_P_802_2); + + if (arphrd == ARPHRD_IEEE802_TR) + rc = htons(ETH_P_TR_802_2); + return rc; +} + +/** + * llc_ui_header_len - return length of llc header based on operation + * @sk: Socket which contains a valid llc socket type. + * @addr: Complete sockaddr_llc structure received from the user. + * + * Provide the length of the llc header depending on what kind of + * operation the user would like to perform and the type of socket. + * Returns the correct llc header length. + */ +static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) +{ + u8 rc = LLC_PDU_LEN_U; + + if (addr->sllc_test || addr->sllc_xid) + rc = LLC_PDU_LEN_U; + else if (sk->type == SOCK_STREAM) + rc = LLC_PDU_LEN_I; + return rc; +} + +/** + * llc_ui_send_conn - send connect command for new llc2 connection + * @sap : Sap the socket is bound to. + * @addr: Source and destination fields provided by the user. + * @dev : Device which this connection should use. + * @link: Link number to assign to this connection. + * + * Send a connect command to the llc layer for a new llc2 connection. + * Returns 0 upon success, non-zero if action didn't succeed. + */ +static int llc_ui_send_conn(struct sock *sk, struct llc_sap *sap, + struct sockaddr_llc *addr, + struct net_device *dev, int link) +{ + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + union llc_u_prim_data prim_data; + struct llc_prim_if_block prim; + + prim.data = &prim_data; + prim.sap = sap; + prim.prim = LLC_CONN_PRIM; + prim_data.conn.dev = dev; + prim_data.conn.link = link; + prim_data.conn.sk = NULL; + prim_data.conn.handler = sk; + prim_data.conn.pri = 0; + prim_data.conn.saddr.lsap = llc_ui->addr.sllc_ssap; + prim_data.conn.daddr.lsap = addr->sllc_dsap; + memcpy(prim_data.conn.saddr.mac, dev->dev_addr, IFHWADDRLEN); + memcpy(prim_data.conn.daddr.mac, addr->sllc_dmac, IFHWADDRLEN); + return sap->req(&prim); +} + +/** + * llc_ui_send_disc - send disc command to llc layer + * @sk: Socket with valid llc information. + * + * Send a disconnect command to the llc layer for an established + * llc2 connection. + * Returns 0 upon success, non-zero if action did not succeed. + */ +static int llc_ui_send_disc(struct sock *sk) +{ + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + union llc_u_prim_data prim_data; + struct llc_prim_if_block prim; + int rc = 0; + + if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED) + goto out; + sk->state = TCP_CLOSING; + prim.data = &prim_data; + prim.sap = llc_ui->sap; + prim.prim = LLC_DISC_PRIM; + prim_data.disc.sk = llc_ui->core_sk; + prim_data.disc.link = llc_ui->link; + rc = llc_ui->sap->req(&prim); +out: return rc; +} + +/** + * llc_ui_send_data - send data via reliable llc2 connection + * @sap: Sap the socket is bound to. + * @sk: Connection the socket is using. + * @skb: Data the user wishes to send. + * @addr: Source and destination fields provided by the user. + * + * Send data via reliable llc2 connection. + * Returns 0 upon success, non-zero if action did not succeed. + */ +static int llc_ui_send_data(struct llc_sap *sap, struct sock* sk, + struct sk_buff *skb, struct sockaddr_llc *addr) +{ + union llc_u_prim_data prim_data; + struct llc_prim_if_block prim; + struct llc_ui_opt* llc_ui = llc_ui_sk(sk); + struct llc_opt* llc_core = llc_sk(llc_ui->core_sk); + int rc; + + prim.data = &prim_data; + prim.sap = sap; + prim.prim = LLC_DATA_PRIM; + prim_data.data.skb = skb; + prim_data.data.pri = 0; + prim_data.data.sk = llc_ui->core_sk; + skb->protocol = llc_ui_protocol_type(addr->sllc_arphrd); + sock_hold(sk); +try: rc = sap->req(&prim); + if (rc != -EBUSY) + goto out; + rc = wait_event_interruptible(sk->socket->wait, !llc_ui->core_sk || + !llc_core->failed_data_req); + if (!rc) + goto try; + if (!llc_ui->core_sk) + rc = -ENOTCONN; +out: sock_put(sk); + return rc; +} + +/** + * llc_ui_send_llc1 - send llc1 prim data block to llc layer. + * @sap : Sap the socket is bound to. + * @skb : Data the user wishes to send. + * @addr : Source and destination fields provided by the user. + * @primitive: Action the llc layer should perform. + * + * Send an llc1 primitive data block to the llc layer for processing. + * This function is used for test, xid and unit_data messages. + * Returns 0 upon success, non-zero if action did not succeed. + */ +static int llc_ui_send_llc1(struct llc_sap *sap, struct sk_buff *skb, + struct sockaddr_llc *addr, int primitive) +{ + union llc_u_prim_data prim_data; + struct llc_prim_if_block prim; + + prim.data = &prim_data; + prim.sap = sap; + prim.prim = primitive; + prim_data.test.skb = skb; + prim_data.test.saddr.lsap = sap->laddr.lsap; + prim_data.test.daddr.lsap = addr->sllc_dsap; + skb->protocol = llc_ui_protocol_type(addr->sllc_arphrd); + memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); + memcpy(prim_data.test.daddr.mac, addr->sllc_dmac, IFHWADDRLEN); + return sap->req(&prim); +} + +/** + * llc_ui_find_sap - returns sap struct that matches sap number specified + * @sap: Sap number to search for. + * + * Search the local socket list and return the first instance of the sap + * structure which matches the sap number the user specified. + * Returns llc_sap upon match, %NULL otherwise. + */ +static inline struct llc_sap *llc_ui_find_sap(u8 sap) +{ + struct sock *sk; + struct llc_sap *s = NULL; + + read_lock_bh(&llc_ui_sockets_lock); + for (sk = llc_ui_sockets; sk; sk = sk->next) { + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + + if (!llc_ui->sap) + continue; + if (llc_ui->sap->laddr.lsap == sap) { + s = llc_ui->sap; + break; + } + } + read_unlock_bh(&llc_ui_sockets_lock); + return s; +} + +static struct sock *__llc_ui_find_sk_by_exact(struct llc_addr *laddr, + struct llc_addr *daddr) +{ + struct sock *sk; + + for (sk = llc_ui_sockets; sk; sk = sk->next) { + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + + if (llc_ui->addr.sllc_ssap == laddr->lsap && + llc_ui->addr.sllc_dsap == daddr->lsap && + llc_ui_mac_null(llc_ui->addr.sllc_mmac) && + llc_ui_mac_match(llc_ui->addr.sllc_smac, laddr->mac) && + llc_ui_mac_match(llc_ui->addr.sllc_dmac, daddr->mac)) + break; + } + return sk; +} + +/** + * __llc_ui_find_sk_by_addr - return socket matching local mac + sap. + * @addr: Local address to match. + * + * Search the local socket list and return the socket which has a matching + * local (mac + sap) address (allows null mac). This search will work on + * unconnected and connected sockets, though find_by_link_no is recommend + * for connected sockets. + * Returns sock upon match, %NULL otherwise. + */ +static struct sock *__llc_ui_find_sk_by_addr(struct llc_addr *laddr, + struct llc_addr *daddr, + struct net_device *dev) +{ + struct sock *sk, *tmp_sk; + + for (sk = llc_ui_sockets; sk; sk = sk->next) { + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + + if (llc_ui->addr.sllc_ssap != laddr->lsap) + continue; + if (llc_ui_mac_null(llc_ui->addr.sllc_smac)) { + if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac) && + !llc_ui_mac_match(llc_ui->addr.sllc_mmac, laddr->mac)) + continue; + break; + } + if (dev && !llc_ui_mac_null(llc_ui->addr.sllc_mmac) && + llc_ui_mac_match(llc_ui->addr.sllc_mmac, laddr->mac) && + llc_ui_mac_match(llc_ui->addr.sllc_smac, dev->dev_addr)) + break; + if (dev->flags & IFF_LOOPBACK) + break; + if (!llc_ui_mac_match(llc_ui->addr.sllc_smac, laddr->mac)) + continue; + tmp_sk = __llc_ui_find_sk_by_exact(laddr, daddr); + if (tmp_sk) { + sk = tmp_sk; + break; + } + if (llc_ui_mac_null(llc_ui->addr.sllc_dmac)) + break; + } + return sk; +} + +static struct sock *llc_ui_find_sk_by_addr(struct llc_addr *addr, + struct llc_addr *daddr, + struct net_device *dev) +{ + struct sock *sk; + + read_lock(&llc_ui_sockets_lock); + sk = __llc_ui_find_sk_by_addr(addr, daddr, dev); + if (sk) + sock_hold(sk); + read_unlock(&llc_ui_sockets_lock); + return sk; +} + +static struct sock *llc_ui_bh_find_sk_by_addr(struct llc_addr *addr, + struct llc_addr *daddr, + struct net_device *dev) +{ + struct sock *sk; + + read_lock_bh(&llc_ui_sockets_lock); + sk = __llc_ui_find_sk_by_addr(addr, daddr, dev); + if (sk) + sock_hold(sk); + read_unlock_bh(&llc_ui_sockets_lock); + return sk; +} + +/** + * llc_ui_insert_socket - insert socket into list + * @sk: Socket to insert. + * + * Insert a socket into the local llc socket list. + */ +static inline void llc_ui_insert_socket(struct sock *sk) +{ + write_lock_bh(&llc_ui_sockets_lock); + sk->next = llc_ui_sockets; + if (sk->next) + llc_ui_sockets->pprev = &sk->next; + llc_ui_sockets = sk; + sk->pprev = &llc_ui_sockets; + sock_hold(sk); + write_unlock_bh(&llc_ui_sockets_lock); +} + +/** + * llc_ui_remove_socket - remove socket from list + * @sk: Socket to remove. + * + * Remove a socket from the local llc socket list. + */ +static inline void llc_ui_remove_socket(struct sock *sk) +{ + write_lock_bh(&llc_ui_sockets_lock); + if (sk->pprev) { + if (sk->next) + sk->next->pprev = sk->pprev; + *sk->pprev = sk->next; + sk->pprev = NULL; + /* this only makes sense if the socket was inserted on the + * list, if sk->pprev is NULL it wasn't */ + sock_put(sk); + } + write_unlock_bh(&llc_ui_sockets_lock); +} + +/** + * llc_ui_destroy_sk - destroy socket + * @data: Socket which is to be destroyed. + * + * Really destroy the socket. + */ +static void llc_ui_destroy_sk(struct sock *sk) +{ + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + sock_put(sk); + MOD_DEC_USE_COUNT; +} + +/** + * llc_ui_destroy_timer - try to destroy socket again + * @data: Socket which is to be destroyed. + * + * Attempt to destroy a socket which was previously destroyed but + * was still in use at the time. + */ +static void llc_ui_destroy_timer(unsigned long data) +{ + struct sock *sk = (struct sock *)data; + + if (!atomic_read(&sk->wmem_alloc) && + !atomic_read(&sk->rmem_alloc) && sk->dead) + llc_ui_destroy_sk(sk); + else { + sk->timer.expires = jiffies + SOCK_DESTROY_TIME; + add_timer(&sk->timer); + } +} + +/** + * llc_ui_create - alloc and init a new llc_ui socket + * @sock: Socket to initialize and attach allocated sk to. + * @protocol: Unused. + * + * Allocate and initialize a new llc_ui socket, validate the user wants a + * socket type we have available. + * Returns 0 upon success, negative upon failure. + */ +static int llc_ui_create(struct socket *sock, int protocol) +{ + struct sock *sk; + struct llc_ui_opt *llc_ui; + int rc = -ESOCKTNOSUPPORT; + + MOD_INC_USE_COUNT; + if (sock->type != SOCK_DGRAM && sock->type != SOCK_STREAM) + goto decmod; + rc = -ENOMEM; + sk = sk_alloc(PF_LLC, GFP_KERNEL, 1); + if (!sk) + goto decmod; + llc_ui = kmalloc(sizeof(*llc_ui), GFP_KERNEL); + if (!llc_ui) + goto outsk; + memset(llc_ui, 0, sizeof(*llc_ui)); + rc = 0; + sock_init_data(sock, sk); + llc_ui_sk(sk) = llc_ui; + sock->ops = &llc_ui_ops; +out: return rc; +outsk: sk_free(sk); +decmod: MOD_DEC_USE_COUNT; + goto out; +} + +/** + * llc_ui_release - shutdown socket + * @sock: Socket to release. + * + * Shutdown and deallocate an existing socket. + */ +static int llc_ui_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct llc_ui_opt *llc_ui; + + if (!sk) + goto out; + llc_ui = llc_ui_sk(sk); + if (llc_ui->core_sk && !llc_ui_send_disc(sk)) + llc_ui_wait_for_disc(sk, 255); + llc_ui_remove_socket(sk); + if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap)) + llc_sap_close(llc_ui->sap); + dprintk("rxq=%d, txq=%d\n", skb_queue_len(&sk->receive_queue), + skb_queue_len(&sk->write_queue)); + sock_orphan(sk); + sock->sk = NULL; + if (!atomic_read(&sk->wmem_alloc) && + !atomic_read(&sk->rmem_alloc) && sk->dead) + llc_ui_destroy_sk(sk); + else { + init_timer(&sk->timer); + sk->timer.expires = jiffies + SOCK_DESTROY_TIME; + sk->timer.function = llc_ui_destroy_timer; + sk->timer.data = (unsigned long)sk; + add_timer(&sk->timer); + } +out: return 0; +} + +/** + * llc_ui_autoport - provide dynamicly allocate SAP number + * + * Provide the caller with a dynamicly allocated SAP number according + * to the rules that are set in this function. Returns: 0, upon failure, + * SAP number otherwise. + */ +static int llc_ui_autoport(void) +{ + struct llc_sap *sap; + int i, tries = 0; + + while (tries < LLC_SAP_DYN_TRIES) { + for (i = llc_ui_sap_last_autoport; + i < LLC_SAP_DYN_STOP; i += 2) { + sap = llc_ui_find_sap(i); + if (!sap) { + llc_ui_sap_last_autoport = i + 2; + goto out; + } + } + llc_ui_sap_last_autoport = LLC_SAP_DYN_START; + tries++; + } + i = 0; +out: return i; +} + +/** + * llc_ui_autobind - Bind a socket to a specific address. + * @sk: Socket to bind an address to. + * @addr: Address the user wants the socket bound to. + * + * Bind a socket to a specific address. For llc a user is able to bind to + * a specific sap only or mac + sap. If the user only specifies a sap and + * a null dmac (all zeros) the user is attempting to bind to an entire + * sap. This will stop anyone else on the local system from using that + * sap. If someone else has a mac + sap open the bind to null + sap will + * fail. + * If the user desires to bind to a specific mac + sap, it is possible to + * have multiple sap connections via multiple macs. + * Bind and autobind for that matter must enforce the correct sap usage + * otherwise all hell will break loose. + * Returns: 0 upon success, negative otherwise. + */ +static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) +{ + struct sock *sk = sock->sk; + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_sap *sap; + struct net_device *dev = NULL; + int rc = -EINVAL; + + if (!sk->zapped) + goto out; + /* bind to a specific mac, optional. */ + if (!llc_ui_mac_null(addr->sllc_smac)) { + rtnl_lock(); + dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); + rtnl_unlock(); + rc = -ENETUNREACH; + if (!dev) + goto out; + llc_ui->dev = dev; + } + /* bind to a specific sap, optional. */ + if (!addr->sllc_ssap) { + rc = -EUSERS; + addr->sllc_ssap = llc_ui_autoport(); + if (!addr->sllc_ssap) + goto out; + } + sap = llc_ui_find_sap(addr->sllc_ssap); + if (!sap) { + sap = llc_sap_open(llc_ui_indicate, llc_ui_confirm, + addr->sllc_ssap); + rc = -EBUSY; /* some other network layer is using the sap */ + if (!sap) + goto out; + } else { + struct llc_addr laddr, daddr; + struct sock *ask; + + rc = -EUSERS; /* can't get exclusive use of sap */ + if (!dev && llc_ui_mac_null(addr->sllc_mmac)) + goto out; + memset(&laddr, 0, sizeof(laddr)); + memset(&daddr, 0, sizeof(daddr)); + if (!llc_ui_mac_null(addr->sllc_mmac)) { + if (sk->type != SOCK_DGRAM) { + rc = -EOPNOTSUPP; + goto out; + } + memcpy(laddr.mac, addr->sllc_mmac, IFHWADDRLEN); + } else + memcpy(laddr.mac, addr->sllc_smac, IFHWADDRLEN); + laddr.lsap = addr->sllc_ssap; + rc = -EADDRINUSE; /* mac + sap clash. */ + ask = llc_ui_bh_find_sk_by_addr(&laddr, &daddr, dev); + if (ask) { + sock_put(ask); + goto out; + } + } + memcpy(&llc_ui->addr, addr, sizeof(*addr)); + llc_ui->sap = sap; + rc = sk->zapped = 0; + llc_ui_insert_socket(sk); +out: return rc; +} + +/** + * llc_ui_bind - bind a socket to a specific address. + * @sock: Socket to bind an address to. + * @uaddr: Address the user wants the socket bound to. + * @addrlen: Length of the uaddr structure. + * + * Bind a socket to a specific address. For llc a user is able to bind to + * a specific sap only or mac + sap. If the user only specifies a sap and + * a null dmac (all zeros) the user is attempting to bind to an entire + * sap. This will stop anyone else on the local system from using that + * sap. If someone else has a mac + sap open the bind to null + sap will + * fail. + * If the user desires to bind to a specific mac + sap, it is possible to + * have multiple sap connections via multiple macs. + * Bind and autobind for that matter must enforce the correct sap usage + * otherwise all hell will break loose. + * Returns: 0 upon success, negative otherwise. + */ +static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) +{ + struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; + struct sock *sk = sock->sk; + int rc = -EINVAL; + + if (!sk->zapped || addrlen != sizeof(*addr)) + goto out; + rc = -EAFNOSUPPORT; + if (addr->sllc_family != AF_LLC) + goto out; + /* use autobind, to avoid code replication. */ + rc = llc_ui_autobind(sock, addr); +out: return rc; +} + +/** + * llc_ui_shutdown - shutdown a connect llc2 socket. + * @sock: Socket to shutdown. + * @how: What part of the socket to shutdown. + * + * Shutdown a connected llc2 socket. Currently this function only supports + * shutting down both sends and receives (2), we could probably make this + * function such that a user can shutdown only half the connection but not + * right now. + * Returns: 0 upon success, negative otherwise. + */ +static int llc_ui_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + int rc = -ENOTCONN; + + lock_sock(sk); + if (sk->state != TCP_ESTABLISHED) + goto out; + rc = -EINVAL; + if (how != 2) + goto out; + rc = llc_ui_send_disc(sk); + if (!rc) + llc_ui_wait_for_disc(sk, 255); + /* Wake up anyone sleeping in poll */ + sk->state_change(sk); +out: release_sock(sk); + return rc; +} + +/** + * llc_ui_connect - Connect to a remote llc2 mac + sap. + * @sock: Socket which will be connected to the remote destination. + * @uaddr: Remote and possibly the local address of the new connection. + * @addrlen: Size of uaddr structure. + * @flags: Operational flags specified by the user. + * + * Connect to a remote llc2 mac + sap. The caller must specify the + * destination mac and address to connect to. If the user previously + * called bind(2) with a smac the user does not need to specify the source + * address and mac. + * This function will autobind if user did not previously call bind. + * Returns: 0 upon success, negative otherwise. + */ +static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, + int addrlen, int flags) +{ + struct sock *sk = sock->sk; + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; + struct net_device *dev; + int rc = -EINVAL; + + lock_sock(sk); + if (addrlen != sizeof(*addr)) + goto out; + rc = -EAFNOSUPPORT; + if (addr->sllc_family != AF_LLC) + goto out; + /* bind connection to sap if user hasn't done it. */ + if (sk->zapped) { + /* bind to sap with null dev, exclusive */ + rc = llc_ui_autobind(sock, addr); + if (rc) + goto out; + } + if (!llc_ui->dev) { + rtnl_lock(); + dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); + rtnl_unlock(); + if (!dev) + goto out; + } else + dev = llc_ui->dev; + if (sk->type != SOCK_STREAM) + goto out; + rc = -EALREADY; + if (sock->state == SS_CONNECTING) + goto out; + sock->state = SS_CONNECTING; + sk->state = TCP_SYN_SENT; + llc_ui->link = llc_ui_next_link_no(llc_ui->sap->laddr.lsap); + rc = llc_ui_send_conn(sk, llc_ui->sap, addr, dev, llc_ui->link); + if (rc) { + sock->state = SS_UNCONNECTED; + sk->state = TCP_CLOSE; + goto out; + } + rc = llc_ui_wait_for_conn(sk, 255); +out: release_sock(sk); + return rc; +} + +/** + * llc_ui_listen - allow a normal socket to accept incoming connections + * @sock: Socket to allow incoming connections on. + * @backlog: Number of connections to queue. + * + * Allow a normal socket to accept incoming connections. + * Returns 0 upon success, negative otherwise. + */ +static int llc_ui_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int rc = -EINVAL; + + lock_sock(sk); + if (sock->state != SS_UNCONNECTED) + goto out; + rc = -EOPNOTSUPP; + if (sk->type != SOCK_STREAM && sk->type != SOCK_SEQPACKET) + goto out; + rc = -EAGAIN; + if (sk->zapped) + goto out; + rc = 0; + if (!(unsigned)backlog) /* BSDism */ + backlog = 1; + if ((unsigned)backlog > SOMAXCONN) + backlog = SOMAXCONN; + sk->max_ack_backlog = backlog; + if (sk->state != TCP_LISTEN) { + sk->ack_backlog = 0; + sk->state = TCP_LISTEN; + } + sk->socket->flags |= __SO_ACCEPTCON; +out: release_sock(sk); + return rc; +} + +static int llc_ui_wait_for_disc(struct sock *sk, int seconds) +{ + DECLARE_WAITQUEUE(wait, current); + int rc, timeout = seconds * HZ; + + add_wait_queue_exclusive(sk->sleep, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + rc = 0; + if (sk->state != TCP_CLOSE) + timeout = schedule_timeout(timeout); + else + break; + rc = -ERESTARTSYS; + if (signal_pending(current)) + break; + rc = -EAGAIN; + if (!timeout) + break; + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + return rc; +} + +static int llc_ui_wait_for_conn(struct sock *sk, int seconds) +{ + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + DECLARE_WAITQUEUE(wait, current); + int rc, timeout = seconds * HZ; + + add_wait_queue_exclusive(sk->sleep, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + rc = 0; + if (sk->state != TCP_ESTABLISHED) + timeout = schedule_timeout(timeout); + if (sk->state == TCP_ESTABLISHED) { + if (!llc_ui->core_sk) + rc = -EAGAIN; + break; + } + rc = -EAGAIN; + if (sk->state == TCP_CLOSE) + break; + rc = -ERESTARTSYS; + if (signal_pending(current)) + break; + rc = -EAGAIN; + if (!timeout) + break; + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + return rc; +} + +/** + * llc_ui_accept - accept a new incoming connection. + * @sock: Socket which connections arrive on. + * @newsock: Socket to move incoming connection to. + * @flags: User specified operational flags. + * + * Accept a new incoming connection. + * Returns 0 upon success, negative otherwise. + */ +static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) +{ + struct sock *sk = sock->sk, *newsk; + struct llc_ui_opt *llc_ui, *newllc_ui; + struct llc_opt *newllc_core; + struct sk_buff *skb; + int rc = -EOPNOTSUPP; + + lock_sock(sk); + if (sk->type != SOCK_SEQPACKET && sk->type != SOCK_STREAM) + goto out; + rc = -EINVAL; + if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN) + goto out; + /* wait for a connection to arrive. */ + do { + skb = skb_dequeue(&sk->receive_queue); + if (!skb) { + rc = -EWOULDBLOCK; + if (flags & O_NONBLOCK) + goto out; + interruptible_sleep_on(sk->sleep); + rc = -ERESTARTSYS; + if (signal_pending(current)) + goto out; + } + } while (!skb); + + rc = -EINVAL; + if(!skb->sk) + goto frees; + /* attach connection to a new socket. */ + rc = llc_ui_create(newsock, sk->protocol); + if (rc) + goto frees; + rc = 0; + newsk = newsock->sk; + newsk->pair = NULL; + newsk->socket = newsock; + newsk->sleep = &newsock->wait; + newsk->zapped = 0; + newsk->state = TCP_ESTABLISHED; + newsock->state = SS_CONNECTED; + llc_ui = llc_ui_sk(sk); + newllc_ui = llc_ui_sk(newsk); + newllc_ui->sap = llc_ui->sap; + newllc_ui->dev = llc_ui->dev; + newllc_ui->core_sk = skb->sk; + newllc_core = llc_sk(newllc_ui->core_sk); + newllc_ui->link = newllc_core->link; + newllc_core->handler = newsk; + memcpy(&newllc_ui->addr, &llc_ui->addr, sizeof(newllc_ui->addr)); + memcpy(newllc_ui->addr.sllc_dmac, newllc_core->daddr.mac, IFHWADDRLEN); + newllc_ui->addr.sllc_dsap = newllc_core->daddr.lsap; + + /* put original socket back into a clean listen state. */ + sk->state = TCP_LISTEN; + sk->ack_backlog--; + llc_ui_insert_socket(newsk); + skb->sk = NULL; +frees: kfree_skb(skb); +out: release_sock(sk); + return rc; +} + +/** + * llc_ui_recvmsg - copy received data to the socket user. + * @sock: Socket to copy data from. + * @msg: Various user space related information. + * @size: Size of user buffer. + * @flags: User specified flags. + * @scm: Unknown. + * + * Copy received data to the socket user. + * Returns non-negative upon success, negative otherwise. + */ +static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size, + int flags, struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; + struct sk_buff *skb; + int rc = -ENOMEM, copied = 0; + int noblock = flags & MSG_DONTWAIT; + + lock_sock(sk); + skb = skb_recv_datagram(sk, flags, noblock, &rc); + if (!skb) + goto out; + copied = skb->len; + if (copied > size) { + copied = size; + msg->msg_flags |= MSG_TRUNC; + } + rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (rc) + goto dgram_free; + if (uaddr) + memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); + msg->msg_namelen = sizeof(*uaddr); +dgram_free: + skb_free_datagram(sk, skb); /* Free the datagram. */ +out: release_sock(sk); + return rc ? : copied; +} + +/** + * llc_ui_sendmsg - Transmit data provided by the socket user. + * @sock: Socket to transmit data from. + * @msg: Various user related information. + * @len: Length of data to transmit. + * @scm: Unknown. + * + * Transmit data provided by the socket user. + * Returns non-negative upon success, negative otherwise. + */ +static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name; + int flags = msg->msg_flags; + struct net_device *dev; + struct sk_buff *skb; + int rc = -EOPNOTSUPP, size = 0; + + lock_sock(sk); + if (flags & ~MSG_DONTWAIT) + goto release; + rc = -EINVAL; + if (addr) { + if (msg->msg_namelen < sizeof(*addr)) + goto release; + } else { + if (llc_ui_addr_null(&llc_ui->addr)) + goto release; + addr = &llc_ui->addr; + } + /* must bind connection to sap if user hasn't done it. */ + if (sk->zapped) { + /* bind to sap with null dev, exclusive. */ + rc = llc_ui_autobind(sock, addr); + if (rc) + goto release; + } + if (!llc_ui->dev) { + rtnl_lock(); + dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); + rtnl_unlock(); + rc = -ENETUNREACH; + if (!dev) + goto release; + } else + dev = llc_ui->dev; + size = dev->hard_header_len + len + llc_ui_header_len(sk, addr); + rc = -EMSGSIZE; + if (size > dev->mtu) + goto release; + skb = sock_alloc_send_skb(sk, size, flags & MSG_DONTWAIT, &rc); + if (!skb) + goto release; + skb->sk = sk; + skb->dev = dev; + skb_reserve(skb, dev->hard_header_len + llc_ui_header_len(sk, addr)); + rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); + if (rc) + goto release; + if (addr->sllc_test) { + rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_TEST_PRIM); + goto out; + } + if (addr->sllc_xid) { + rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_XID_PRIM); + goto out; + } + if (sk->type == SOCK_DGRAM || addr->sllc_ua) { + rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_DATAUNIT_PRIM); + goto out; + } + rc = -ENOPROTOOPT; + if (!(sk->type == SOCK_STREAM && !addr->sllc_ua)) + goto out; + rc = -ENOTCONN; + if (!llc_ui->core_sk) + goto out; + rc = llc_ui_send_data(llc_ui->sap, sk, skb, addr); +out: if (rc) + skb_free_datagram(sk, skb); +release: + release_sock(sk); + return rc ? : len; +} + +/** + * llc_ui_getname - return the address info of a socket + * @sock: Socket to get address of. + * @uaddr: Address structure to return information. + * @uaddrlen: Length of address structure. + * @peer: Does user want local or remote address information. + * + * Return the address information of a socket. + */ +static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddrlen, int peer) +{ + struct sockaddr_llc sllc; + struct sock *sk = sock->sk; + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + int rc = 0; + + lock_sock(sk); + if (sk->zapped) + goto out; + *uaddrlen = sizeof(sllc); + memset(uaddr, 0, *uaddrlen); + if (peer) { + rc = -ENOTCONN; + if (sk->state != TCP_ESTABLISHED) + goto out; + if(llc_ui->dev) + sllc.sllc_arphrd = llc_ui->dev->type; + sllc.sllc_dsap = llc_sk(llc_ui->core_sk)->daddr.lsap; + memcpy(&sllc.sllc_dmac, &llc_sk(llc_ui->core_sk)->daddr.mac, + IFHWADDRLEN); + } else { + rc = -EINVAL; + if (!llc_ui->sap) + goto out; + sllc.sllc_ssap = llc_ui->sap->laddr.lsap; + + if (llc_ui->dev) { + sllc.sllc_arphrd = llc_ui->dev->type; + memcpy(&sllc.sllc_smac, &llc_ui->dev->dev_addr, + IFHWADDRLEN); + } + } + rc = 0; + sllc.sllc_family = AF_LLC; + memcpy(uaddr, &sllc, sizeof(sllc)); +out: release_sock(sk); + return rc; +} + +/** + * llc_ui_ioctl - io controls for PF_LLC + * @sock: Socket to get/set info + * @cmd: command + * @arg: optional argument for cmd + * + * get/set info on llc sockets + */ +static int llc_ui_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + return dev_ioctl(cmd, (void *)arg); +} + +/** + * llc_ui_setsockopt - set various connection specific parameters. + * @sock: Socket to set options on. + * @level: Socket level user is requesting operations on. + * @optname: Operation name. + * @optval User provided operation data. + * @optlen: Length of optval. + * + * Set various connection specific parameters. + */ +static int llc_ui_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + struct sock *sk = sock->sk; + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc_core; + int rc = -EINVAL, opt; + + lock_sock(sk); + if (level != SOL_LLC || optlen != sizeof(int)) + goto out; + rc = -ENOTCONN; + if (!llc_ui->core_sk) + goto out; + rc = get_user(opt, (int *)optval); + if (rc) + goto out; + rc = -EINVAL; + llc_core = llc_sk(llc_ui->core_sk); + switch (optname) { + case LLC_OPT_RETRY: + if (opt > LLC_OPT_MAX_RETRY) + goto out; + llc_core->n2 = opt; + break; + case LLC_OPT_SIZE: + if (opt > LLC_OPT_MAX_SIZE) + goto out; + llc_core->n1 = opt; + break; + case LLC_OPT_ACK_TMR_EXP: + if (opt > LLC_OPT_MAX_ACK_TMR_EXP) + goto out; + llc_core->ack_timer.expire = opt; + break; + case LLC_OPT_P_TMR_EXP: + if (opt > LLC_OPT_MAX_P_TMR_EXP) + goto out; + llc_core->pf_cycle_timer.expire = opt; + break; + case LLC_OPT_REJ_TMR_EXP: + if (opt > LLC_OPT_MAX_REJ_TMR_EXP) + goto out; + llc_core->rej_sent_timer.expire = opt; + break; + case LLC_OPT_BUSY_TMR_EXP: + if (opt > LLC_OPT_MAX_BUSY_TMR_EXP) + goto out; + llc_core->busy_state_timer.expire = opt; + break; + case LLC_OPT_TX_WIN: + if (opt > LLC_OPT_MAX_WIN) + goto out; + llc_core->k = opt; + break; + case LLC_OPT_RX_WIN: + if (opt > LLC_OPT_MAX_WIN) + goto out; + llc_core->rw = opt; + break; + default: + rc = -ENOPROTOOPT; + goto out; + } + rc = 0; +out: release_sock(sk); + return rc; +} + +/** + * llc_ui_getsockopt - get connection specific socket info + * @sock: Socket to get information from. + * @level: Socket level user is requesting operations on. + * @optname: Operation name. + * @optval: Variable to return operation data in. + * @optlen: Length of optval. + * + * Get connection specific socket information. + */ +static int llc_ui_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) +{ + struct sock *sk = sock->sk; + struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc_core; + int val = 0, len = 0, rc = -EINVAL; + + lock_sock(sk); + if (level != SOL_LLC) + goto out; + rc = -ENOTCONN; + if (!llc_ui->core_sk) + goto out; + rc = get_user(len, optlen); + if (rc) + goto out; + rc = -EINVAL; + if (len != sizeof(int)) + goto out; + llc_core = llc_sk(llc_ui->core_sk); + switch (optname) { + case LLC_OPT_RETRY: + val = llc_core->n2; break; + case LLC_OPT_SIZE: + val = llc_core->n1; break; + case LLC_OPT_ACK_TMR_EXP: + val = llc_core->ack_timer.expire; break; + case LLC_OPT_P_TMR_EXP: + val = llc_core->pf_cycle_timer.expire; break; + case LLC_OPT_REJ_TMR_EXP: + val = llc_core->rej_sent_timer.expire; break; + case LLC_OPT_BUSY_TMR_EXP: + val = llc_core->busy_state_timer.expire; break; + case LLC_OPT_TX_WIN: + val = llc_core->k; break; + case LLC_OPT_RX_WIN: + val = llc_core->rw; break; + default: + rc = -ENOPROTOOPT; + goto out; + } + rc = 0; + if (put_user(len, optlen) || copy_to_user(optval, &val, len)) + rc = -EFAULT; +out: release_sock(sk); + return rc; +} + +/** + * llc_ui_ind_test - handle TEST indication + * @prim: Primitive block provided by the llc layer. + * + * handle TEST indication. + */ +static void llc_ui_ind_test(struct llc_prim_if_block *prim) +{ + struct llc_prim_test *prim_data = &prim->data->test; + struct sk_buff *skb = prim_data->skb; + struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); + struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, + &prim_data->saddr, skb->dev); + if (!sk) + goto out; + if (sk->state == TCP_LISTEN) + goto out_put; + /* save primitive for use by the user. */ + llc_ui->sllc_family = AF_LLC; + llc_ui->sllc_arphrd = skb->dev->type; + llc_ui->sllc_test = 1; + llc_ui->sllc_xid = 0; + llc_ui->sllc_ua = 0; + llc_ui->sllc_dsap = prim_data->daddr.lsap; + memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); + llc_ui->sllc_ssap = prim_data->saddr.lsap; + memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); + /* queue skb to the user. */ + if (sock_queue_rcv_skb(sk, skb)) + kfree_skb(skb); +out_put: + sock_put(sk); +out:; +} + +/** + * llc_ui_ind_xid - handle XID indication + * @prim: Primitive block provided by the llc layer. + * + * handle XID indication. + */ +static void llc_ui_ind_xid(struct llc_prim_if_block *prim) +{ + struct llc_prim_xid *prim_data = &prim->data->xid; + struct sk_buff *skb = prim_data->skb; + struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); + struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, + &prim_data->saddr, skb->dev); + if (!sk) + goto out; + if (sk->state == TCP_LISTEN) + goto out_put; + /* save primitive for use by the user. */ + llc_ui->sllc_family = AF_LLC; + llc_ui->sllc_arphrd = 0; + llc_ui->sllc_test = 0; + llc_ui->sllc_xid = 1; + llc_ui->sllc_ua = 0; + llc_ui->sllc_dsap = prim_data->daddr.lsap; + memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); + llc_ui->sllc_ssap = prim_data->saddr.lsap; + memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); + /* queue skb to the user. */ + if (sock_queue_rcv_skb(sk, skb)) + kfree_skb(skb); +out_put: + sock_put(sk); +out:; +} + +/** + * llc_ui_ind_dataunit - handle DATAUNIT indication + * @prim: Primitive block provided by the llc layer. + * + * handle DATAUNIT indication. + */ +static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim) +{ + struct llc_prim_unit_data *prim_data = &prim->data->udata; + struct sk_buff *skb = prim_data->skb; + struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); + struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, + &prim_data->saddr, skb->dev); + if (!sk) + goto out; + if (sk->state == TCP_LISTEN) + goto out_put; + /* save primitive for use by the user. */ + llc_ui->sllc_family = AF_LLC; + llc_ui->sllc_arphrd = skb->dev->type; + llc_ui->sllc_test = 0; + llc_ui->sllc_xid = 0; + llc_ui->sllc_ua = 1; + llc_ui->sllc_dsap = prim_data->daddr.lsap; + memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); + llc_ui->sllc_ssap = prim_data->saddr.lsap; + memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); + /* queue skb to the user. */ + if (sock_queue_rcv_skb(sk, skb)) + kfree_skb(skb); +out_put: + sock_put(sk); +out:; +} + +/** + * llc_ui_ind_conn - handle CONNECT indication + * @prim: Primitive block provided by the llc layer. + * + * handle CONNECT indication. + */ +static void llc_ui_ind_conn(struct llc_prim_if_block *prim) +{ + struct llc_prim_conn *prim_data = &prim->data->conn; + struct sock* sk; + struct sk_buff *skb2; + + llc_sk(prim_data->sk)->laddr.lsap = prim->sap->laddr.lsap; + sk = llc_ui_find_sk_by_addr(&llc_sk(prim_data->sk)->laddr, + &prim_data->saddr, prim_data->dev); + if (!sk) { + dprintk("llc_ui_find_sk_by_addr failed\n"); + goto out; + } + if (sk->type != SOCK_STREAM || sk->state != TCP_LISTEN) + goto out_put; + if (prim->data->conn.status) + goto out_put; /* bad status. */ + /* give this connection a link number. */ + llc_sk(prim_data->sk)->link = + llc_ui_next_link_no(llc_sk(prim_data->sk)->laddr.lsap); + skb2 = alloc_skb(0, GFP_ATOMIC); + if (!skb2) + goto out_put; + skb2->sk = prim_data->sk; + skb_queue_tail(&sk->receive_queue, skb2); + sk->state_change(sk); +out_put: + sock_put(sk); +out:; +} + +/** + * llc_ui_ind_data - handle DATA indication + * @prim: Primitive block provided by the llc layer. + * + * handle CONNECT indication. + */ +static void llc_ui_ind_data(struct llc_prim_if_block *prim) +{ + struct llc_prim_data *prim_data = &prim->data->data; + struct sk_buff *skb = prim_data->skb; + struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); + struct sock* sk = llc_sk(prim_data->sk)->handler; + + if (!sk) + goto out; + sock_hold(sk); + if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED) + goto out_put; + /* save primitive for use by the user. */ + llc_ui->sllc_family = AF_LLC; + llc_ui->sllc_arphrd = skb->dev->type; + llc_ui->sllc_test = 0; + llc_ui->sllc_xid = 0; + llc_ui->sllc_ua = 0; + llc_ui->sllc_dsap = llc_ui_sk(sk)->sap->laddr.lsap; + memcpy(llc_ui->sllc_dmac, llc_sk(prim_data->sk)->laddr.mac, + IFHWADDRLEN); + llc_ui->sllc_ssap = llc_sk(prim_data->sk)->daddr.lsap; + memcpy(llc_ui->sllc_smac, llc_sk(prim_data->sk)->daddr.mac, + IFHWADDRLEN); + /* queue skb to the user. */ + if (sock_queue_rcv_skb(sk, skb)) { + dprintk("sock_queue_rcv_skb failed!\n"); + kfree_skb(skb); + } +out_put: + sock_put(sk); +out:; +} + +/** + * llc_ui_ind_disc - handle DISC indication + * @prim: Primitive block provided by the llc layer. + * + * handle DISC indication. + */ +static void llc_ui_ind_disc(struct llc_prim_if_block *prim) +{ + struct llc_prim_disc *prim_data = &prim->data->disc; + struct sock* sk = llc_sk(prim_data->sk)->handler; + + if (!sk) + goto out; + sock_hold(sk); + if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED) + goto out_put; + llc_ui_sk(sk)->core_sk = NULL; + sk->shutdown = SHUTDOWN_MASK; + sk->socket->state = SS_UNCONNECTED; + sk->state = TCP_CLOSE; + if (!sk->dead) { + sk->state_change(sk); + sk->dead = 1; + } +out_put: + sock_put(sk); +out:; +} + +/** + * llc_ui_indicate - LLC user interface hook into the LLC layer. + * @prim: Primitive block provided by the llc layer. + * + * LLC user interface hook into the LLC layer, every llc_ui sap references + * this function as its indicate handler. + * Always returns 0 to indicate reception of primitive. + */ +static int llc_ui_indicate(struct llc_prim_if_block *prim) +{ + switch (prim->prim) { + case LLC_TEST_PRIM: + llc_ui_ind_test(prim); break; + case LLC_XID_PRIM: + llc_ui_ind_xid(prim); break; + case LLC_DATAUNIT_PRIM: + llc_ui_ind_dataunit(prim); break; + case LLC_CONN_PRIM: + llc_ui_ind_conn(prim); break; + case LLC_DATA_PRIM: + llc_ui_ind_data(prim); break; + case LLC_DISC_PRIM: + llc_ui_ind_disc(prim); break; + case LLC_RESET_PRIM: + case LLC_FLOWCONTROL_PRIM: + default: break; + } + return 0; +} + +/** + * llc_ui_conf_conn - handle CONN confirm. + * @prim: Primitive block provided by the llc layer. + * + * handle CONN confirm. + */ +static void llc_ui_conf_conn(struct llc_prim_if_block *prim) +{ + struct llc_prim_conn *prim_data = &prim->data->conn; + struct llc_opt *llc_core = llc_sk(prim_data->sk); + struct llc_ui_opt *llc_ui = llc_ui_sk(prim_data->sk); + struct sock* sk = llc_core->handler; + + if (!sk) { + dprintk("llc_core->handler == NULL!\n"); + goto out; + } + sock_hold(sk); + if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT) + goto out_put; + if (!prim->data->conn.status) { + sk->socket->state = SS_CONNECTED; + sk->state = TCP_ESTABLISHED; + llc_ui->core_sk = prim_data->sk; + } else { + dprintk("prim->data->conn.status = %d\n", + prim->data->conn.status); + sk->socket->state = SS_UNCONNECTED; + sk->state = TCP_CLOSE; + llc_ui->core_sk = NULL; + } + sk->state_change(sk); +out_put: + sock_put(sk); +out:; +} + +/** + * llc_ui_conf_data - handle DATA confirm. + * @prim: Primitive block provided by the llc layer. + * + * handle DATA confirm. + */ +static void llc_ui_conf_data(struct llc_prim_if_block *prim) +{ + struct llc_prim_data *prim_data = &prim->data->data; + struct sock* sk = llc_sk(prim_data->sk)->handler; + + if (sk) + wake_up(sk->sleep); +} + +/** + * llc_ui_conf_disc - handle DISC confirm. + * @prim: Primitive block provided by the llc layer. + * + * handle DISC confirm. + */ +static void llc_ui_conf_disc(struct llc_prim_if_block *prim) +{ + struct llc_prim_disc *prim_data = &prim->data->disc; + struct sock* sk = llc_sk(prim_data->sk)->handler; + + if (!sk) + goto out; + sock_hold(sk); + if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING) + goto out_put; + llc_ui_sk(sk)->core_sk = NULL; + sk->socket->state = SS_UNCONNECTED; + sk->state = TCP_CLOSE; + sk->state_change(sk); +out_put: + sock_put(sk); +out:; +} + +/** + * llc_ui_confirm - LLC user interface hook into the LLC layer + * @prim: Primitive block provided by the llc layer. + * + * LLC user interface hook into the LLC layer, every llc_ui sap references + * this function as its confirm handler. + * Always returns 0 to indicate reception of primitive. + */ +static int llc_ui_confirm(struct llc_prim_if_block *prim) +{ + switch (prim->prim) { + case LLC_CONN_PRIM: + llc_ui_conf_conn(prim); break; + case LLC_DATA_PRIM: + llc_ui_conf_data(prim); break; + case LLC_DISC_PRIM: + llc_ui_conf_disc(prim); break; + case LLC_RESET_PRIM: break; + default: + printk(KERN_ERR __FUNCTION__ ": unknown prim %d\n", + prim->prim); + break; + } + return 0; +} + +#ifdef CONFIG_PROC_FS +/** + * llc_ui_get_info - return info to procfs + * @buffer: where to put the formatted output + * @start: starting from + * @offset: offset into buffer. + * @length: size of the buffer + * + * Get the output of the local llc ui socket list to the caller. + * Returns the length of data wrote to buffer. + */ +static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length) +{ + off_t pos = 0; + off_t begin = 0; + struct sock *s; + int len = sprintf(buffer, "SocketID SKt Mc local_mac_sap\t " + "remote_mac_sap\t tx_queue rx_queue st uid " + "link_no\n"); + /* Output the LLC socket data for the /proc filesystem */ + read_lock_bh(&llc_ui_sockets_lock); + for (s = llc_ui_sockets; s; s = s->next) { + struct llc_ui_opt *llc_ui = llc_ui_sk(s); + len += sprintf(buffer + len, "%p %02X %02X ", s, s->type, + !llc_ui_mac_null(llc_ui->addr.sllc_mmac)); + if (llc_ui->sap) { + if (llc_ui->dev && + llc_ui_mac_null(llc_ui->addr.sllc_mmac)) + len += sprintf(buffer + len, + "%02X:%02X:%02X:%02X:%02X:%02X", + llc_ui->dev->dev_addr[0], + llc_ui->dev->dev_addr[1], + llc_ui->dev->dev_addr[2], + llc_ui->dev->dev_addr[3], + llc_ui->dev->dev_addr[4], + llc_ui->dev->dev_addr[5]); + else { + if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac)) + len += sprintf(buffer + len, + "%02X:%02X:%02X:%02X:%02X:%02X", + llc_ui->addr.sllc_mmac[0], + llc_ui->addr.sllc_mmac[1], + llc_ui->addr.sllc_mmac[2], + llc_ui->addr.sllc_mmac[3], + llc_ui->addr.sllc_mmac[4], + llc_ui->addr.sllc_mmac[5]); + else + len += sprintf(buffer + len, + "00:00:00:00:00:00"); + } + len += sprintf(buffer + len, "@%02X ", + llc_ui->sap->laddr.lsap); + } else + len += sprintf(buffer + len, "00:00:00:00:00:00@00 "); + len += sprintf(buffer + len, + "%02X:%02X:%02X:%02X:%02X:%02X@%02X " + "%08X:%08X %02X %-3d ", + llc_ui->addr.sllc_dmac[0], llc_ui->addr.sllc_dmac[1], + llc_ui->addr.sllc_dmac[2], llc_ui->addr.sllc_dmac[3], + llc_ui->addr.sllc_dmac[4], llc_ui->addr.sllc_dmac[5], + llc_ui->addr.sllc_dsap, + atomic_read(&s->wmem_alloc), + atomic_read(&s->rmem_alloc), s->state, + SOCK_INODE(s->socket)->i_uid); + if (llc_ui->core_sk) + len += sprintf(buffer + len, "%-7d\n", + llc_sk(llc_ui->core_sk)->link); + else + len += sprintf(buffer + len, "no_link\n"); + /* Are we still dumping unwanted data then discard the record */ + pos = begin + len; + + if (pos < offset) { + len = 0; /* Keep dumping into the buffer start */ + begin = pos; + } + if (pos > offset + length) /* We have dumped enough */ + break; + } + read_unlock_bh(&llc_ui_sockets_lock); + + /* The data in question runs from begin to begin + len */ + *start = buffer + offset - begin; /* Start of wanted data */ + len -= offset - begin; /* Remove unwanted header data from length */ + if (len > length) + len = length; /* Remove unwanted tail data from length */ + return len; +} +#endif /* CONFIG_PROC_FS */ + +static struct net_proto_family llc_ui_family_ops = { + family: PF_LLC, + create: llc_ui_create, +}; + +static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = { + family: PF_LLC, + release: llc_ui_release, + bind: llc_ui_bind, + connect: llc_ui_connect, + socketpair: sock_no_socketpair, + accept: llc_ui_accept, + getname: llc_ui_getname, + poll: datagram_poll, + ioctl: llc_ui_ioctl, + listen: llc_ui_listen, + shutdown: llc_ui_shutdown, + setsockopt: llc_ui_setsockopt, + getsockopt: llc_ui_getsockopt, + sendmsg: llc_ui_sendmsg, + recvmsg: llc_ui_recvmsg, + mmap: sock_no_mmap, + sendpage: sock_no_sendpage, +}; + +#include +SOCKOPS_WRAP(llc_ui, PF_LLC); + +static char llc_ui_banner[] __initdata = + KERN_INFO "NET4.0 IEEE 802.2 User Interface SAPs, Jay Schulist, 2001\n"; + +int __init llc_ui_init(void) +{ + llc_ui_sap_last_autoport = LLC_SAP_DYN_START; + sock_register(&llc_ui_family_ops); + proc_net_create("llc", 0, llc_ui_get_info); + printk(llc_ui_banner); + return 0; +} + +void __exit llc_ui_exit(void) +{ + proc_net_remove("llc"); + sock_unregister(PF_LLC); +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_s_st.c linux.20pre2-ac1/net/llc/llc_s_st.c --- linux.20pre2/net/llc/llc_s_st.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_s_st.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,163 @@ +/* + * llc_s_st.c - Defines SAP component state machine transitions. + * + * The followed transitions are SAP component state machine transitions + * which are described in 802.2 LLC protocol standard document. + * + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include + +/* dummy last-transition indicator; common to all state transition groups */ +/* last entry for this state */ +/* all members are zeros, .bss zeroes it */ +static struct llc_sap_state_trans llc_sap_state_trans_n; + +/* state LLC_SAP_STATE_INACTIVE transition for LLC_SAP_EV_ACTIVATION_REQ event */ +static llc_sap_action_t llc_sap_inactive_state_actions_1[] = { + llc_sap_action_report_status, + NULL +}; + +static struct llc_sap_state_trans llc_sap_inactive_state_trans_1 = { + llc_sap_ev_activation_req, LLC_SAP_STATE_ACTIVE, + llc_sap_inactive_state_actions_1 +}; + +/* array of pointers; one to each transition */ +static struct llc_sap_state_trans *llc_sap_inactive_state_transitions[] = { + &llc_sap_inactive_state_trans_1, + &llc_sap_state_trans_n +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_UI event */ +static llc_sap_action_t llc_sap_active_state_actions_1[] = { + llc_sap_action_unitdata_ind, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_1 = { + llc_sap_ev_rx_ui, LLC_SAP_STATE_ACTIVE, + llc_sap_active_state_actions_1 +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_UNITDATA_REQ event */ +static llc_sap_action_t llc_sap_active_state_actions_2[] = { + llc_sap_action_send_ui, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_2 = { + llc_sap_ev_unitdata_req, LLC_SAP_STATE_ACTIVE, + llc_sap_active_state_actions_2 +}; + + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_XID_REQ event */ +static llc_sap_action_t llc_sap_active_state_actions_3[] = { + llc_sap_action_send_xid_c, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_3 = { + llc_sap_ev_xid_req, LLC_SAP_STATE_ACTIVE, + llc_sap_active_state_actions_3 +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_XID_C event */ +static llc_sap_action_t llc_sap_active_state_actions_4[] = { + llc_sap_action_send_xid_r, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_4 = { + llc_sap_ev_rx_xid_c, LLC_SAP_STATE_ACTIVE, + llc_sap_active_state_actions_4 +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_XID_R event */ +static llc_sap_action_t llc_sap_active_state_actions_5[] = { + llc_sap_action_xid_ind, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_5 = { + llc_sap_ev_rx_xid_r, LLC_SAP_STATE_ACTIVE, + llc_sap_active_state_actions_5 +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_TEST_REQ event */ +static llc_sap_action_t llc_sap_active_state_actions_6[] = { + llc_sap_action_send_test_c, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_6 = { + llc_sap_ev_test_req, LLC_SAP_STATE_ACTIVE, + llc_sap_active_state_actions_6 +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_TEST_C event */ +static llc_sap_action_t llc_sap_active_state_actions_7[] = { + llc_sap_action_send_test_r, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_7 = { + llc_sap_ev_rx_test_c, LLC_SAP_STATE_ACTIVE, + llc_sap_active_state_actions_7 +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_TEST_R event */ +static llc_sap_action_t llc_sap_active_state_actions_8[] = { + llc_sap_action_test_ind, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_8 = { + llc_sap_ev_rx_test_r, LLC_SAP_STATE_ACTIVE, + llc_sap_active_state_actions_8 +}; + +/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_DEACTIVATION_REQ event */ +static llc_sap_action_t llc_sap_active_state_actions_9[] = { + llc_sap_action_report_status, + NULL +}; + +static struct llc_sap_state_trans llc_sap_active_state_trans_9 = { + llc_sap_ev_deactivation_req, LLC_SAP_STATE_INACTIVE, + llc_sap_active_state_actions_9 +}; + +/* array of pointers; one to each transition */ +static struct llc_sap_state_trans *llc_sap_active_state_transitions[] = { + &llc_sap_active_state_trans_2, + &llc_sap_active_state_trans_1, + &llc_sap_active_state_trans_3, + &llc_sap_active_state_trans_4, + &llc_sap_active_state_trans_5, + &llc_sap_active_state_trans_6, + &llc_sap_active_state_trans_7, + &llc_sap_active_state_trans_8, + &llc_sap_active_state_trans_9, + &llc_sap_state_trans_n +}; + +/* SAP state transition table */ +struct llc_sap_state llc_sap_state_table[] = { + { LLC_SAP_STATE_INACTIVE, llc_sap_inactive_state_transitions }, + { LLC_SAP_STATE_ACTIVE, llc_sap_active_state_transitions } +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/llc_stat.c linux.20pre2-ac1/net/llc/llc_stat.c --- linux.20pre2/net/llc/llc_stat.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/llc_stat.c 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,199 @@ +/* + * llc_stat.c - Implementation of LLC station component state machine + * transitions + * Copyright (c) 1997 by Procom Technology, Inc. + * 2001 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include + +/* ------------------- COMMON STATION STATE transitions ------------------ */ + +/* dummy last-transition indicator; common to all state transition groups */ +/* last entry for this state */ +/* all members are zeros, .bss zeroes it */ +static struct llc_station_state_trans llc_stat_state_trans_n; + +/* ------------------------ DOWN STATE transitions ----------------------- */ + +/* state transition for LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK event */ +static llc_station_action_t llc_stat_down_state_actions_1[] = { + llc_station_ac_start_ack_timer, + llc_station_ac_set_retry_cnt_0, + llc_station_ac_set_xid_r_cnt_0, + llc_station_ac_send_null_dsap_xid_c, + NULL +}; + +static struct llc_station_state_trans llc_stat_down_state_trans_1 = { + llc_stat_ev_enable_with_dup_addr_check, + LLC_STATION_STATE_DUP_ADDR_CHK, + llc_stat_down_state_actions_1 +}; + +/* state transition for LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK event */ +static llc_station_action_t llc_stat_down_state_actions_2[] = { + llc_station_ac_report_status, /* STATION UP */ + NULL +}; + +static struct llc_station_state_trans llc_stat_down_state_trans_2 = { + llc_stat_ev_enable_without_dup_addr_check, + LLC_STATION_STATE_UP, + llc_stat_down_state_actions_2 +}; + +/* array of pointers; one to each transition */ +static struct llc_station_state_trans *llc_stat_dwn_state_trans[] = { + &llc_stat_down_state_trans_1, + &llc_stat_down_state_trans_2, + &llc_stat_state_trans_n +}; + +/* ------------------------- UP STATE transitions ------------------------ */ +/* state transition for LLC_STATION_EV_DISABLE_REQ event */ +static llc_station_action_t llc_stat_up_state_actions_1[] = { + llc_station_ac_report_status, /* STATION DOWN */ + NULL +}; + +static struct llc_station_state_trans llc_stat_up_state_trans_1 = { + llc_stat_ev_disable_req, LLC_STATION_STATE_DOWN, + llc_stat_up_state_actions_1 +}; + +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */ +static llc_station_action_t llc_stat_up_state_actions_2[] = { + llc_station_ac_send_xid_r, + NULL +}; + +static struct llc_station_state_trans llc_stat_up_state_trans_2 = { + llc_stat_ev_rx_null_dsap_xid_c, LLC_STATION_STATE_UP, + llc_stat_up_state_actions_2 +}; + +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_TEST_C event */ +static llc_station_action_t llc_stat_up_state_actions_3[] = { + llc_station_ac_send_test_r, + NULL +}; + +static struct llc_station_state_trans llc_stat_up_state_trans_3 = { + llc_stat_ev_rx_null_dsap_test_c, LLC_STATION_STATE_UP, + llc_stat_up_state_actions_3 +}; + +/* array of pointers; one to each transition */ +static struct llc_station_state_trans *llc_stat_up_state_trans [] = { + &llc_stat_up_state_trans_1, + &llc_stat_up_state_trans_2, + &llc_stat_up_state_trans_3, + &llc_stat_state_trans_n +}; + +/* ---------------------- DUP ADDR CHK STATE transitions ----------------- */ +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ + * event */ +static llc_station_action_t llc_stat_dupaddr_state_actions_1[] = { + llc_station_ac_inc_xid_r_cnt_by_1, + NULL +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_1 = { + llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq, + LLC_STATION_STATE_DUP_ADDR_CHK, + llc_stat_dupaddr_state_actions_1 +}; + +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ + * event */ +static llc_station_action_t llc_stat_dupaddr_state_actions_2[] = { + llc_station_ac_report_status, /* DUPLICATE ADDRESS FOUND */ + NULL +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_2 = { + llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq, + LLC_STATION_STATE_DOWN, + llc_stat_dupaddr_state_actions_2 +}; + +/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */ +static llc_station_action_t llc_stat_dupaddr_state_actions_3[] = { + llc_station_ac_send_xid_r, + NULL +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_3 = { + llc_stat_ev_rx_null_dsap_xid_c, LLC_STATION_STATE_DUP_ADDR_CHK, + llc_stat_dupaddr_state_actions_3 +}; + +/* state transition for LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY + * event */ +static llc_station_action_t llc_stat_dupaddr_state_actions_4[] = { + llc_station_ac_start_ack_timer, + llc_station_ac_inc_retry_cnt_by_1, + llc_station_ac_set_xid_r_cnt_0, + llc_station_ac_send_null_dsap_xid_c, + NULL +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_4 = { + llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry, + LLC_STATION_STATE_DUP_ADDR_CHK, + llc_stat_dupaddr_state_actions_4 +}; + +/* state transition for LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY + * event */ +static llc_station_action_t llc_stat_dupaddr_state_actions_5[] = { + llc_station_ac_report_status, /* STATION UP */ + NULL +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_5 = { + llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry, + LLC_STATION_STATE_UP, + llc_stat_dupaddr_state_actions_5 +}; + +/* state transition for LLC_STATION_EV_DISABLE_REQ event */ +static llc_station_action_t llc_stat_dupaddr_state_actions_6[] = { + llc_station_ac_report_status, /* STATION DOWN */ + NULL +}; + +static struct llc_station_state_trans llc_stat_dupaddr_state_trans_6 = { + llc_stat_ev_disable_req, LLC_STATION_STATE_DOWN, + llc_stat_dupaddr_state_actions_6 +}; + +/* array of pointers; one to each transition */ +static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = { + &llc_stat_dupaddr_state_trans_6, /* Request */ + &llc_stat_dupaddr_state_trans_4, /* Timer */ + &llc_stat_dupaddr_state_trans_5, + &llc_stat_dupaddr_state_trans_1, /* Receive frame */ + &llc_stat_dupaddr_state_trans_2, + &llc_stat_dupaddr_state_trans_3, + &llc_stat_state_trans_n +}; + +struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES] = { + { LLC_STATION_STATE_DOWN, llc_stat_dwn_state_trans }, + { LLC_STATION_STATE_DUP_ADDR_CHK, llc_stat_dupaddr_state_trans }, + { LLC_STATION_STATE_UP, llc_stat_up_state_trans } +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/llc/Makefile linux.20pre2-ac1/net/llc/Makefile --- linux.20pre2/net/llc/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/net/llc/Makefile 2002-08-06 15:42:06.000000000 +0100 @@ -0,0 +1,38 @@ +########################################################################### +# Makefile for the Linux 802.2 LLC (fully-functional) layer. +# +# Note 1! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... +# +# Copyright (c) 1997 by Procom Technology,Inc. +# 2001 by Arnaldo Carvalho de Melo +# +# This program can be redistributed or modified under the terms of the +# GNU General Public License as published by the Free Software Foundation. +# This program is distributed without any warranty or implied warranty +# of merchantability or fitness for a particular purpose. +# +# See the GNU General Public License for more details. +########################################################################### + +O_TARGET := llc.o + +obj-y := llc_if.o llc_c_ev.o llc_c_ac.o llc_mac.o llc_sap.o llc_s_st.o \ + llc_main.o llc_s_ac.o llc_conn.o llc_c_st.o llc_stat.o llc_actn.o \ + llc_s_ev.o llc_evnt.o llc_pdu.o + +ifeq ($(CONFIG_LLC_UI),y) + obj-y += llc_sock.o +endif + +# Objects that export symbols. +export-objs := llc_if.o + +ifeq ($(CONFIG_LLC),m) + obj-m += $(O_TARGET) +endif + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/Makefile linux.20pre2-ac1/net/Makefile --- linux.20pre2/net/Makefile 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/net/Makefile 2002-08-06 15:41:56.000000000 +0100 @@ -7,7 +7,7 @@ O_TARGET := network.o -mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core +mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched llc core export-objs := netsyms.o subdir-y := core ethernet @@ -45,7 +45,7 @@ subdir-$(CONFIG_DECNET) += decnet subdir-$(CONFIG_ECONET) += econet subdir-$(CONFIG_VLAN_8021Q) += 8021q - +subdir-$(CONFIG_LLC) += llc obj-y := socket.o $(join $(subdir-y), $(patsubst %,/%.o,$(notdir $(subdir-y)))) ifeq ($(CONFIG_NET),y) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/netsyms.c linux.20pre2-ac1/net/netsyms.c --- linux.20pre2/net/netsyms.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/netsyms.c 2002-08-13 14:59:29.000000000 +0100 @@ -82,7 +82,7 @@ extern void destroy_8023_client(struct datalink_proto *); #endif -#ifdef CONFIG_ATALK_MODULE +#if defined(CONFIG_ATALK_MODULE) || defined(CONFIG_FILTER) #include #endif @@ -461,6 +461,7 @@ #endif /* CONFIG_INET */ #ifdef CONFIG_TR +EXPORT_SYMBOL(tr_source_route); EXPORT_SYMBOL(tr_type_trans); #endif @@ -479,6 +480,7 @@ EXPORT_SYMBOL(__dev_get_by_index); EXPORT_SYMBOL(dev_get_by_name); EXPORT_SYMBOL(__dev_get_by_name); +EXPORT_SYMBOL(dev_getbyhwaddr); EXPORT_SYMBOL(netdev_finish_unregister); EXPORT_SYMBOL(netdev_set_master); EXPORT_SYMBOL(eth_type_trans); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/sched/sch_generic.c linux.20pre2-ac1/net/sched/sch_generic.c --- linux.20pre2/net/sched/sch_generic.c 2002-08-13 13:58:23.000000000 +0100 +++ linux.20pre2-ac1/net/sched/sch_generic.c 2002-08-06 15:41:57.000000000 +0100 @@ -475,10 +475,8 @@ dev_watchdog_down(dev); - while (test_bit(__LINK_STATE_SCHED, &dev->state)) { - current->policy |= SCHED_YIELD; - schedule(); - } + while (test_bit(__LINK_STATE_SCHED, &dev->state)) + yield(); spin_unlock_wait(&dev->xmit_lock); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/socket.c linux.20pre2-ac1/net/socket.c --- linux.20pre2/net/socket.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/socket.c 2002-08-06 17:27:12.000000000 +0100 @@ -147,8 +147,7 @@ while (atomic_read(&net_family_lockct) != 0) { spin_unlock(&net_family_lock); - current->policy |= SCHED_YIELD; - schedule(); + yield(); spin_lock(&net_family_lock); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/sunrpc/sched.c linux.20pre2-ac1/net/sunrpc/sched.c --- linux.20pre2/net/sunrpc/sched.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/sunrpc/sched.c 2002-08-13 14:59:42.000000000 +0100 @@ -777,8 +777,7 @@ } if (flags & RPC_TASK_ASYNC) return NULL; - current->policy |= SCHED_YIELD; - schedule(); + yield(); } while (!signalled()); return NULL; @@ -1104,8 +1103,7 @@ __rpc_schedule(); if (!list_empty(&all_tasks)) { dprintk("rpciod_killall: waiting for tasks to exit\n"); - current->policy |= SCHED_YIELD; - schedule(); + yield(); } } @@ -1175,8 +1173,7 @@ * wait briefly before checking the process id. */ current->sigpending = 0; - current->policy |= SCHED_YIELD; - schedule(); + yield(); /* * Display a message if we're going to wait longer. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/net/unix/af_unix.c linux.20pre2-ac1/net/unix/af_unix.c --- linux.20pre2/net/unix/af_unix.c 2002-08-13 13:58:56.000000000 +0100 +++ linux.20pre2-ac1/net/unix/af_unix.c 2002-08-13 15:06:49.000000000 +0100 @@ -565,10 +565,8 @@ addr->hash)) { write_unlock(&unix_table_lock); /* Sanity yield. It is unusual case, but yet... */ - if (!(ordernum&0xFF)) { - current->policy |= SCHED_YIELD; - schedule(); - } + if (!(ordernum&0xFF)) + yield(); goto retry; } addr->hash ^= sk->type; @@ -1385,7 +1383,7 @@ static void unix_copy_addr(struct msghdr *msg, struct sock *sk) { - msg->msg_namelen = sizeof(short); + msg->msg_namelen = 0; if (sk->protinfo.af_unix.addr) { msg->msg_namelen=sk->protinfo.af_unix.addr->len; memcpy(msg->msg_name, @@ -1885,6 +1883,8 @@ module_init(af_unix_init); module_exit(af_unix_exit); +MODULE_LICENSE("GPL"); + /* * Local variables: * compile-command: "gcc -g -D__KERNEL__ -Wall -O6 -I/usr/src/linux/include -c af_unix.c" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/Rules.make linux.20pre2-ac1/Rules.make --- linux.20pre2/Rules.make 2002-08-13 13:58:19.000000000 +0100 +++ linux.20pre2-ac1/Rules.make 2002-08-06 15:41:56.000000000 +0100 @@ -291,10 +291,6 @@ include .depend endif -ifneq ($(wildcard $(TOPDIR)/.hdepend),) -include $(TOPDIR)/.hdepend -endif - # # Find files whose flags have changed and force recompilation. # For safety, this works in the converse direction: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/scripts/extract-ikconfig linux.20pre2-ac1/scripts/extract-ikconfig --- linux.20pre2/scripts/extract-ikconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/scripts/extract-ikconfig 2002-08-06 15:42:22.000000000 +0100 @@ -0,0 +1,17 @@ +#! /bin/bash -x +# extracts .config info from a [b]zImage file +# uses: binoffset (new), dd, zcat, strings, grep +# $arg1 is [b]zImage filename + +HDR=`binoffset $1 0x1f 0x8b 0x08 0x0` +PID=$$ +TMPFILE="$1.vmlin.$PID" + +# dd if=$1 bs=1 skip=$HDR | zcat - | strings /dev/stdin \ +# | grep "[A-Za-z_0-9]=[ynm]$" | sed "s/^/CONFIG_/" > $1.oldconfig.$PID +# exit + +dd if=$1 bs=1 skip=$HDR | zcat - > $TMPFILE +strings $TMPFILE | grep "^[\#[:blank:]]*CONFIG_[A-Za-z_0-9]*" > $1.oldconfig.$PID +wc $1.oldconfig.$PID +rm $TMPFILE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/scripts/include_deps linux.20pre2-ac1/scripts/include_deps --- linux.20pre2/scripts/include_deps 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/scripts/include_deps 2002-08-06 15:42:22.000000000 +0100 @@ -0,0 +1,15 @@ +# Read the .depend files, extract the dependencies for .h targets, convert +# relative names to absolute and write the result to stdout. It is part of +# building the global .h dependency graph for kbuild 2.4. KAO + +/^[^ ]/ { copy = 0; fn = "/error/"; } +/^[^ ][^ ]*\.h:/ { copy = 1; fn = FILENAME; sub(/\.depend/, "", fn); } +!copy { next; } + { + indent = $0; sub(/[^ ].*/, "", indent); + if ($1 != "" && $1 !~ /^[@$\/\\]/) { $1 = fn $1 }; + if ($2 != "" && $2 !~ /^[@$\/\\]/) { $2 = fn $2 }; + $1 = $1; # ensure $0 is rebuilt + $0 = indent $0; + print; + } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/scripts/mkconfigs.c linux.20pre2-ac1/scripts/mkconfigs.c --- linux.20pre2/scripts/mkconfigs.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.20pre2-ac1/scripts/mkconfigs.c 2002-08-06 15:42:22.000000000 +0100 @@ -0,0 +1,181 @@ +/*************************************************************************** + * mkconfigs.c + * (C) 2002 Randy Dunlap + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# Rules for scripts/mkconfigs.c input.config output.c +# to generate configs.c from linux/.config: +# - drop lines that begin with '#' +# - drop blank lines +# - lines that use double-quotes must \\-escape-quote them + +################## skeleton configs.c file: #################### + +#include +#include + +static char *configs[] __initdata = + + , + +; + +################### end configs.c file ###################### + + * Changelog for ver. 0.2, 2002-02-15, rddunlap@osdl.org: + - strip leading "CONFIG_" from config option strings; + - use "static" and "__attribute__((unused))"; + - don't use EXPORT_SYMBOL(); + - separate each config line with \newline instead of space; + + * Changelog for ver. 0.3, 2002-02-18, rddunlap@osdl.org: + - keep all "not set" comment lines from .config so that 'make *config' + will be happy, but don't keep other comments; + - keep leading "CONFIG_" on each line; + +****************************************************************/ + +#include +#include +#include +#include + +#define VERSION "0.2" +#define LINE_SIZE 1000 + +int include_all_lines = 1; // whether to include "=n" lines in the output + +void usage (const char *progname) +{ + fprintf (stderr, "%s ver. %s\n", progname, VERSION); + fprintf (stderr, "usage: %s input.config.name path/configs.c\n", + progname); + exit (1); +} + +void make_intro (FILE *sourcefile) +{ + fprintf (sourcefile, "#include \n"); +///// fprintf (sourcefile, "#include \n"); + fprintf (sourcefile, "\n"); +///// fprintf (sourcefile, "char *configs[] __initdata = {\n"); + fprintf (sourcefile, "static char __attribute__ ((unused)) *configs[] __initdata = {\n"); + fprintf (sourcefile, " \"CONFIG_BEGIN=n\\n\" ,\n"); +} + +void make_ending (FILE *sourcefile) +{ + fprintf (sourcefile, " \"CONFIG_END=n\\n\"\n"); + fprintf (sourcefile, "};\n"); +///// fprintf (sourcefile, "EXPORT_SYMBOL (configs);\n"); +} + +void make_lines (FILE *configfile, FILE *sourcefile) +{ + char cfgline[LINE_SIZE]; + char *ch; + + while (fgets (cfgline, LINE_SIZE, configfile)) { + /* kill the trailing newline in cfgline */ + cfgline[strlen (cfgline) - 1] = '\0'; + + /* don't keep #-only line or an empty/blank line */ + if ((cfgline[0] == '#' && cfgline[1] == '\0') || + cfgline[0] == '\0') + continue; + + if (!include_all_lines && + cfgline[0] == '#') // strip out all comment lines + continue; + + /* really only want to keep lines that begin with + * "CONFIG_" or "# CONFIG_" */ + if (strncmp (cfgline, "CONFIG_", 7) && + strncmp (cfgline, "# CONFIG_", 9)) + continue; + + /* + * use strchr() to check for "-quote in cfgline; + * if not found, output the line, quoted; + * if found, output a char at a time, with \\-quote + * preceding double-quote chars + */ + if (!strchr (cfgline, '"')) { + fprintf (sourcefile, " \"%s\\n\" ,\n", cfgline); + continue; + } + + /* go to char-at-a-time mode for this config and + * precede any double-quote with a backslash */ + fprintf (sourcefile, " \""); /* lead-in */ + for (ch = cfgline; *ch; ch++) { + if (*ch == '"') + fputc ('\\', sourcefile); + fputc (*ch, sourcefile); + } + fprintf (sourcefile, "\\n\" ,\n"); + } +} + +int make_configs (FILE *configfile, FILE *sourcefile) +{ + make_intro (sourcefile); + make_lines (configfile, sourcefile); + make_ending (sourcefile); +} + +int main (int argc, char *argv[]) +{ + char *progname = argv[0]; + char *configname, *sourcename; + FILE *configfile, *sourcefile; + + if (argc != 3) + usage (progname); + + configname = argv[1]; + sourcename = argv[2]; + + configfile = fopen (configname, "r"); + if (!configfile) { + fprintf (stderr, "%s: cannot open '%s'\n", + progname, configname); + exit (2); + } + sourcefile = fopen (sourcename, "w"); + if (!sourcefile) { + fprintf (stderr, "%s: cannot open '%s'\n", + progname, sourcename); + exit (2); + } + + make_configs (configfile, sourcefile); + + if (fclose (sourcefile)) { + fprintf (stderr, "%s: error %d closing '%s'\n", + progname, errno, sourcename); + exit (3); + } + if (fclose (configfile)) { + fprintf (stderr, "%s: error %d closing '%s'\n", + progname, errno, configname); + exit (3); + } + + exit (0); +} + +/* end mkconfigs.c */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/scripts/mkdep.c linux.20pre2-ac1/scripts/mkdep.c --- linux.20pre2/scripts/mkdep.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/scripts/mkdep.c 2002-08-06 15:42:22.000000000 +0100 @@ -48,6 +48,8 @@ char __depname[512] = "\n\t@touch "; #define depname (__depname+9) int hasdep; +char cwd[PATH_MAX]; +int lcwd; struct path_struct { int len; @@ -202,8 +204,22 @@ memcpy(path->buffer+path->len, name, len); path->buffer[path->len+len] = '\0'; if (access(path->buffer, F_OK) == 0) { + int l = lcwd + strlen(path->buffer); + char name2[l+2], *p; + if (path->buffer[0] == '/') { + memcpy(name2, path->buffer, l+1); + } + else { + memcpy(name2, cwd, lcwd); + name2[lcwd] = '/'; + memcpy(name2+lcwd+1, path->buffer, path->len+len+1); + } + while ((p = strstr(name2, "/../"))) { + *p = '\0'; + strcpy(strrchr(name2, '/'), p+3); + } do_depname(); - printf(" \\\n %s", path->buffer); + printf(" \\\n %s", name2); return; } } @@ -585,6 +601,12 @@ return 1; } + if (!getcwd(cwd, sizeof(cwd))) { + fprintf(stderr, "mkdep: getcwd() failed %m\n"); + return 1; + } + lcwd = strlen(cwd); + add_path("."); /* for #include "..." */ while (++argv, --argc > 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre2/scripts/tkgen.c linux.20pre2-ac1/scripts/tkgen.c --- linux.20pre2/scripts/tkgen.c 2002-08-13 13:58:38.000000000 +0100 +++ linux.20pre2-ac1/scripts/tkgen.c 2002-08-06 15:42:22.000000000 +0100 @@ -625,6 +625,7 @@ if ( ! vartable[i].global_written ) { global( vartable[i].name ); + vartable[i].global_written = 1; } printf( "\t" ); } @@ -699,6 +700,19 @@ } /* + * Generate global declarations for the dependency chain (e.g. CONSTANT_M). + */ + for ( tmp = cfg->depend; tmp; tmp = tmp->next ) + { + int i = get_varnum( tmp->name ); + if ( ! vartable[i].global_written ) + { + global( vartable[i].name ); + vartable[i].global_written = 1; + } + } + + /* * Generate indentation. */ printf( "\t" );