diff -u --recursive --new-file v2.3.99-pre9/linux/CREDITS linux/CREDITS --- v2.3.99-pre9/linux/CREDITS Tue May 23 15:31:32 2000 +++ linux/CREDITS Wed May 24 17:52:42 2000 @@ -550,6 +550,13 @@ S: Littleton, Massachusetts 01460 S: USA +N: Frank Davis +E: fdavis112@juno.com +D: Various kernel patches +S: 8 Lakeview Terr. +S: Kerhonskon, NY 12446 +S: USA + N: Wayne Davison E: davison@borland.com D: Second extended file system co-designer @@ -1632,7 +1639,7 @@ E: claudio@conectiva.com E: claudio@helllabs.org W: http://helllabs.org/~claudio -D: OV511 driver hacks +D: V4L, OV511 driver hacks S: Conectiva S.A. S: R. Tocantins 89 S: 80050-430 Curitiba PR diff -u --recursive --new-file v2.3.99-pre9/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.99-pre9/linux/Documentation/Configure.help Tue May 23 15:31:32 2000 +++ linux/Documentation/Configure.help Wed May 24 17:52:52 2000 @@ -12647,6 +12647,21 @@ The module will be called microcode.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +/dev/cpu/*/msr - Model-specific register support +CONFIG_X86_MSR + This device gives privileged processes access to the x86 + Model-Specific Registers (MSRs). It is a character device with + major 202 and minors 0 to 31 for /dev/cpu/0/msr to /dev/cpu/31/msr. + MSR accesses are directed to a specific CPU on multi-processor + systems. + +/dev/cpu/*/cpuid - CPU information support +CONFIG_X86_CPUID + This device gives processes access to the x86 CPUID instruction to + be executed on a specific processor. It is a character device + with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to + /dev/cpu/31/cpuid. + Enhanced Real Time Clock Support CONFIG_RTC If you say Y here and create a character special file /dev/rtc with @@ -14829,6 +14844,14 @@ 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 Documentation/modules.txt. + +Video For Linux /proc file system information +CONFIG_VIDEO_PROC_FS + If you say Y here, you are able to access video device information + in /proc/video. + + To use this option, you have to check, that the "/proc file system + support" (CONFIG_PROC_FS) is enabled too. AIMSlab RadioTrack (aka RadioReveal) support CONFIG_RADIO_RTRACK diff -u --recursive --new-file v2.3.99-pre9/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.3.99-pre9/linux/Documentation/DocBook/Makefile Tue May 23 15:31:32 2000 +++ linux/Documentation/DocBook/Makefile Wed May 24 10:55:27 2000 @@ -24,6 +24,12 @@ $(TOPDIR)/scripts/docproc: $(MAKE) -C $(TOPDIR)/scripts docproc +kernel-hacking.sgml: kernel-hacking.tmpl + $(TOPDIR)/scripts/docgen <$< >$@ + +kernel-locking.sgml: kernel-locking.tmpl + $(TOPDIR)/scripts/docgen <$< >$@ + wanbook.sgml: wanbook.tmpl $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/syncppp.c \ wanbook.sgml diff -u --recursive --new-file v2.3.99-pre9/linux/Documentation/fb/modedb.txt linux/Documentation/fb/modedb.txt --- v2.3.99-pre9/linux/Documentation/fb/modedb.txt Wed Aug 18 10:10:06 1999 +++ linux/Documentation/fb/modedb.txt Wed May 24 22:48:36 2000 @@ -41,8 +41,20 @@ e.g. there can be multiple 640x480 modes, each of them is tried). If that fails, the default mode is tried. If that fails, it walks over all modes. -BTW, only a few drivers use this at the moment. Others are to follow -(feel free to send patches). +To specify a video mode at bootup, use the following boot options: + video=:x[-][@refresh] + +where is a name from the table below. Valid default modes can be +found in linux/drivers/video/modedb.c. Check your driver's documentation. +There may be more modes. + Drivers that support modedb boot options + Boot Name Cards Supported + ami - Amiga chipset frame buffer + aty128fb - ATI Rage128 / Pro frame buffer + atyfb - ATI Mach64 frame buffer + tdfx - 3D Fx frame buffer +BTW, only a few drivers use this at the moment. Others are to follow +(feel free to send patches). diff -u --recursive --new-file v2.3.99-pre9/linux/Documentation/sound/OPL3-SA2 linux/Documentation/sound/OPL3-SA2 --- v2.3.99-pre9/linux/Documentation/sound/OPL3-SA2 Sun Nov 7 16:37:33 1999 +++ linux/Documentation/sound/OPL3-SA2 Wed May 24 19:28:05 2000 @@ -1,7 +1,7 @@ Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o) --------------------------------------------------------------- -Scott Murray, scottm@interlog.com +Scott Murray, scott@spiteful.org January 5, 1999 NOTE: All trade-marked terms mentioned below are properties of their diff -u --recursive --new-file v2.3.99-pre9/linux/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt --- v2.3.99-pre9/linux/Documentation/usb/ov511.txt Tue May 23 15:31:32 2000 +++ linux/Documentation/usb/ov511.txt Wed May 24 08:29:47 2000 @@ -6,8 +6,8 @@ Homepage: http://alpha.dyndns.org/ov511 NEW IN THIS VERSION: - o 352x288 mode - o force_rgb parameter for apps that expect RGB instead of BGR + o 384x288 and 448x336 modes + o better /proc/video support INTRODUCTION: @@ -179,7 +179,7 @@ your colors look VERY wrong, you may want to change this. WORKING FEATURES: - o Color streaming/capture at 640x480, 352x288, and 320x240 + o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, and 320x240 o YUV420 color o Monochrome o Setting/getting of saturation, contrast and brightness (no hue yet; only diff -u --recursive --new-file v2.3.99-pre9/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.99-pre9/linux/MAINTAINERS Tue May 23 15:31:32 2000 +++ linux/MAINTAINERS Wed May 24 19:28:05 2000 @@ -665,7 +665,7 @@ L: linux-kernel@vger.rutgers.edu S: Maintained -MODULE SUPPORT [GENERAL], KERNELD +MODULE SUPPORT [GENERAL], KMOD P: Keith Owens M: kaos@ocs.com.au L: linux-kernel@vger.rutgers.edu diff -u --recursive --new-file v2.3.99-pre9/linux/Makefile linux/Makefile --- v2.3.99-pre9/linux/Makefile Tue May 23 15:31:32 2000 +++ linux/Makefile Wed May 24 08:29:47 2000 @@ -1,7 +1,7 @@ VERSION = 2 -PATCHLEVEL = 3 -SUBLEVEL = 99 -EXTRAVERSION = -pre9 +PATCHLEVEL = 4 +SUBLEVEL = 0 +EXTRAVERSION = -test1 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -159,8 +159,8 @@ DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus.a DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/zorro.a DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a -DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.a -DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.a +DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o +DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a DRIVERS-$(CONFIG_VT) += drivers/video/video.o @@ -427,7 +427,7 @@ dep-files: scripts/mkdep archdep include/linux/version.h scripts/mkdep init/*.c > .depend - scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend + scripts/mkdep `find $(FINDHPATH) -name SCCS -prune -or -follow -name \*.h ! -name modversions.h -print` > .hdepend $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" ifdef CONFIG_MODVERSIONS diff -u --recursive --new-file v2.3.99-pre9/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.3.99-pre9/linux/arch/alpha/kernel/signal.c Thu Mar 2 14:36:22 2000 +++ linux/arch/alpha/kernel/signal.c Wed May 24 18:38:26 2000 @@ -36,6 +36,36 @@ struct switch_stack *, unsigned long, unsigned long); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_addr, &to->si_addr); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * The OSF/1 sigprocmask calling sequence is different from the * C sigprocmask() sequence.. @@ -489,7 +519,7 @@ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t)); + err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.3.99-pre9/linux/arch/arm/kernel/signal.c Fri Jan 28 15:09:06 2000 +++ linux/arch/arm/kernel/signal.c Wed May 24 18:38:26 2000 @@ -34,6 +34,41 @@ extern int ptrace_cancel_bpt (struct task_struct *); extern int ptrace_set_bpt (struct task_struct *); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * atomically swap in the new signal mask, and wait for a signal. */ @@ -370,7 +405,7 @@ err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->info, info); /* Clear all the bits of the ucontext we don't use. */ err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.3.99-pre9/linux/arch/i386/Makefile Mon Mar 27 08:08:21 2000 +++ linux/arch/i386/Makefile Thu May 25 09:35:10 2000 @@ -49,6 +49,10 @@ CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) endif +ifdef CONFIG_M686FX +CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) +endif + ifdef CONFIG_MK6 CFLAGS += $(shell if $(CC) -march=k6 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=k6"; fi) endif diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.99-pre9/linux/arch/i386/config.in Tue May 23 15:31:33 2000 +++ linux/arch/i386/config.in Thu May 25 09:35:10 2000 @@ -18,13 +18,15 @@ mainmenu_option next_comment comment 'Processor type and features' choice 'Processor family' \ - "386 CONFIG_M386 \ - 486/Cx486 CONFIG_M486 \ - 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ - Pentium/TSC CONFIG_M586TSC \ - PPro/P-II/P-III CONFIG_M686 \ - K6/II/III CONFIG_MK6 \ - Athlon CONFIG_MK7" PPro + "386 CONFIG_M386 \ + 486/Cx486 CONFIG_M486 \ + 586/K5/5x86/6x86/6x86MX CONFIG_M586 \ + Pentium/TSC CONFIG_M586TSC \ + PPro/Pentium-II CONFIG_M686 \ + Pentium-III CONFIG_M686FX \ + K6/K6-II/K6-III CONFIG_MK6 \ + Athlon CONFIG_MK7 \ + Crusoe CONFIG_MCRUSOE" PPro # # Define implied options from the CPU selection here # @@ -60,6 +62,14 @@ define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y fi +if [ "$CONFIG_M686FX" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_PGE y + define_bool CONFIG_X86_USE_PPRO_CHECKSUM y + define_bool CONFIG_X86_FX y +fi if [ "$CONFIG_MK6" = "y" ]; then define_int CONFIG_X86_L1_CACHE_BYTES 32 define_bool CONFIG_X86_ALIGNMENT_16 y @@ -74,8 +84,14 @@ define_bool CONFIG_X86_PGE y define_bool CONFIG_X86_USE_PPRO_CHECKSUM y fi +if [ "$CONFIG_MCRUSOE" = "y" ]; then + define_int CONFIG_X86_L1_CACHE_BYTES 32 + define_bool CONFIG_X86_TSC y +fi tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE +tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR +tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID choice 'High Memory Support' \ "off CONFIG_NOHIGHMEM \ @@ -89,7 +105,9 @@ define_bool CONFIG_X86_PAE y fi -bool 'Math emulation' CONFIG_MATH_EMULATION +if [ "$CONFIG_X86_FX" != "y" ]; then + bool 'Math emulation' CONFIG_MATH_EMULATION +fi bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP if [ "$CONFIG_SMP" != "y" ]; then diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.99-pre9/linux/arch/i386/defconfig Tue May 23 15:31:33 2000 +++ linux/arch/i386/defconfig Thu May 25 09:35:10 2000 @@ -19,8 +19,10 @@ # CONFIG_M586 is not set # CONFIG_M586TSC is not set CONFIG_M686=y +# CONFIG_M686FX is not set # CONFIG_MK6 is not set # CONFIG_MK7 is not set +# CONFIG_MCRUSOE is not set CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y CONFIG_X86_CMPXCHG=y @@ -32,6 +34,8 @@ CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y # CONFIG_MICROCODE is not set +# CONFIG_X86_MSR is not set +# CONFIG_X86_CPUID is not set CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set @@ -194,7 +198,6 @@ # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_IDEDMA_PCI_AUTO is not set # CONFIG_BLK_DEV_IDEDMA is not set -# CONFIG_IDEDMA_PCI_EXPERIMENTAL is not set # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.3.99-pre9/linux/arch/i386/kernel/Makefile Wed Apr 12 10:02:34 2000 +++ linux/arch/i386/kernel/Makefile Wed May 24 17:52:52 2000 @@ -40,6 +40,22 @@ endif endif +ifeq ($(CONFIG_X86_MSR),y) +OX_OBJS += msr.o +else + ifeq ($(CONFIG_X86_MSR),m) + MX_OBJS += msr.o + endif +endif + +ifeq ($(CONFIG_X86_CPUID),y) +OX_OBJS += cpuid.o +else + ifeq ($(CONFIG_X86_CPUID),m) + MX_OBJS += cpuid.o + endif +endif + ifeq ($(CONFIG_MICROCODE),y) OX_OBJS += microcode.o else diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c --- v2.3.99-pre9/linux/arch/i386/kernel/apic.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/apic.c Wed May 24 15:46:10 2000 @@ -128,6 +128,11 @@ void __init sync_Arb_IDs(void) { + /* + * Wait for idle. + */ + apic_wait_icr_idle(); + Dprintk("Synchronizing Arb IDs.\n"); apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.3.99-pre9/linux/arch/i386/kernel/apm.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/apm.c Wed May 24 17:52:42 2000 @@ -922,6 +922,10 @@ case APM_USER_SUSPEND: /* map all suspends to ACPI D3 */ if (pm_send_all(PM_SUSPEND, (void *)3)) { + if (event == APM_CRITICAL_SUSPEND) { + printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armagedon\n" ); + return 0; + } if (apm_bios_info.version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; @@ -934,7 +938,6 @@ break; } - queue_event(event, sender); return 1; } @@ -964,6 +967,7 @@ case APM_SYS_STANDBY: case APM_USER_STANDBY: if (send_event(event, NULL)) { + queue_event(event, NULL); if (standbys_pending <= 0) standby(); } @@ -980,17 +984,18 @@ if (ignore_bounce) break; #endif - /* - * If we are already processing a SUSPEND, - * then further SUSPEND events from the BIOS - * will be ignored. We also return here to - * cope with the fact that the Thinkpads keep - * sending a SUSPEND event until something else - * happens! - */ + /* + * If we are already processing a SUSPEND, + * then further SUSPEND events from the BIOS + * will be ignored. We also return here to + * cope with the fact that the Thinkpads keep + * sending a SUSPEND event until something else + * happens! + */ if (waiting_for_resume) - return; + return; if (send_event(event, NULL)) { + queue_event(event, NULL); waiting_for_resume = 1; if (suspends_pending <= 0) (void) suspend(); @@ -1007,6 +1012,7 @@ #endif set_time(); send_event(event, NULL); + queue_event(event, NULL); break; case APM_CAPABILITY_CHANGE: @@ -1020,6 +1026,7 @@ break; case APM_CRITICAL_SUSPEND: + send_event(event, NULL); /* We can only hope it worked; critical suspend may not fail */ (void) suspend(); break; } @@ -1056,6 +1063,7 @@ static void apm_mainloop(void) { + int timeout = HZ; DECLARE_WAITQUEUE(wait, current); if (smp_num_cpus > 1) @@ -1065,7 +1073,10 @@ current->state = TASK_INTERRUPTIBLE; for (;;) { /* Nothing to do, just sleep for the timeout */ - schedule_timeout(APM_CHECK_TIMEOUT); + timeout = 2*timeout; + if (timeout > APM_CHECK_TIMEOUT) + timeout = APM_CHECK_TIMEOUT; + schedule_timeout(timeout); if (exit_kapmd) break; @@ -1080,13 +1091,16 @@ continue; if (apm_do_idle()) { unsigned long start = jiffies; - while (system_idle()) { + while ((!exit_kapmd) && system_idle()) { apm_do_idle(); - if (jiffies - start > APM_CHECK_TIMEOUT) - break; + if (jiffies - start > (5*APM_CHECK_TIMEOUT)) { + apm_event_handler(); + start = jiffies; + } } apm_do_busy(); apm_event_handler(); + timeout = 1; } #endif } diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/cpuid.c linux/arch/i386/kernel/cpuid.c --- v2.3.99-pre9/linux/arch/i386/kernel/cpuid.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/kernel/cpuid.c Wed May 24 22:47:48 2000 @@ -0,0 +1,168 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2000 H. Peter Anvin - 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + + +/* + * cpuid.c + * + * x86 CPUID access device + * + * This device is accessed by lseek() to the appropriate CPUID level + * and then read in chunks of 16 bytes. A larger size means multiple + * reads of consecutive levels. + * + * This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on + * an SMP box will direct the access to CPU %d. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_SMP + +struct cpuid_command { + int cpu; + u32 reg; + u32 *data; +}; + +static void cpuid_smp_cpuid(void *cmd_block) +{ + struct cpuid_command *cmd = (struct cpuid_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]); +} + +extern inline void do_cpuid(int cpu, u32 reg, u32 *data) +{ + struct cpuid_command cmd; + + if ( cpu == smp_processor_id() ) { + cpuid(reg, &data[0], &data[1], &data[2], &data[3]); + } else { + cmd->cpu = cpu; + cmd->reg = reg; + cmd->data = data; + + smp_call_function(cpuid_smp_cpuid, (void *)cmd, 1, 1); + } +} +#else /* ! CONFIG_SMP */ + +extern inline void do_cpuid(int cpu, u32 reg, u32 *data) +{ + cpuid(reg, &data[0], &data[1], &data[2], &data[3]); +} + +#endif /* ! CONFIG_SMP */ + +static loff_t cpuid_seek(struct file *file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; /* SEEK_END not supported */ + } +} + +static ssize_t cpuid_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + u32 *tmp = (u32 *)buf; + u32 data[4]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + + if ( count % 16 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 16 ) { + do_cpuid(cpu, reg, data); + if ( copy_to_user(tmp,&data,16) ) + return -EFAULT; + tmp += 4; + *ppos = reg++; + } + + return ((char *)tmp) - buf; +} + +static int cpuid_open(struct inode *inode, struct file *file) +{ + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + + if ( !(cpu_online_map & (1UL << cpu)) ) + return -ENXIO; /* No such CPU */ + + MOD_INC_USE_COUNT; + return 0; +} + +static int cpuid_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * File operations we support + */ +static struct file_operations cpuid_fops = { + llseek: cpuid_seek, + read: cpuid_read, + open: cpuid_open, + release: cpuid_release, +}; + +int __init cpuid_init(void) +{ + if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) { + printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n", + CPUID_MAJOR); + return -EBUSY; + } + + return 0; +} + +void __exit cpuid_exit(void) +{ +} + +module_init(cpuid_init); +module_exit(cpuid_exit) + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("H. Peter Anvin "); +MODULE_DESCRIPTION("x86 generic CPUID driver"); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.3.99-pre9/linux/arch/i386/kernel/entry.S Wed Apr 26 16:34:06 2000 +++ linux/arch/i386/kernel/entry.S Wed May 24 14:23:29 2000 @@ -413,6 +413,11 @@ pushl $ SYMBOL_NAME(do_spurious_interrupt_bug) jmp error_code +ENTRY(xmm_fault) + pushl $0 + pushl $ SYMBOL_NAME(do_xmm_fault) + jmp error_code + .data ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c --- v2.3.99-pre9/linux/arch/i386/kernel/i8259.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/i8259.c Wed May 24 18:38:26 2000 @@ -390,10 +390,11 @@ static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs) { + extern void math_error(void *); outb(0,0xF0); if (ignore_irq13 || !boot_cpu_data.hard_math) return; - math_error(); + math_error((void *)regs->eip); } static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c --- v2.3.99-pre9/linux/arch/i386/kernel/msr.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/kernel/msr.c Wed May 24 22:47:48 2000 @@ -0,0 +1,274 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2000 H. Peter Anvin - 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * msr.c + * + * x86 MSR access device + * + * This device is accessed by lseek() to the appropriate register number + * and then read/write in chunks of 8 bytes. A larger size means multiple + * reads or writes of the same register. + * + * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on + * an SMP box will direct the access to CPU %d. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) +{ + int err = 0; + + asm volatile( + "1: wrmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "+r" (err) + : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO)); + + return err; +} + +extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) +{ + int err = 0; + + asm volatile( + "1: rdmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "+r" (err), "=a" (*eax), "=d" (*eax) + : "c" (reg), "i" (-EIO)); + + return err; +} + +#ifdef CONFIG_SMP + +struct msr_command { + int cpu; + int err; + u32 reg; + u32 data[2]; +}; + +static void msr_smp_wrmsr(void *cmd_block) +{ + struct msr_command *cmd = (struct msr_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cmd->err = wrmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); +} + +static void msr_smp_rdmsr(void *cmd_block) +{ + struct msr_command *cmd = (struct msr_command *) cmd_block; + + if ( cmd->cpu == smp_processor_id() ) + cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); +} + +extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) +{ + struct msr_command cmd; + + if ( cpu == smp_processor_id() ) { + return wrmsr_eio(reg, eax, edx); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + cmd.data[0] = eax; + cmd.data[1] = edx; + + smp_call_function(msr_smp_wrmsr, (void *)cmd, 1, 1); + return cmd.err; + } +} + +extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +{ + struct msr_command cmd; + + if ( cpu == smp_processor_id() ) { + return rdmsr_eio(reg, eax, edx); + } else { + cmd.cpu = cpu; + cmd.reg = reg; + + smp_call_function(msr_smp_rdmsr, (void *)cmd, 1, 1); + + *eax = cmd.data[0]; + *edx = cmd.data[1]; + + return cmd.err; + } +} + +#else /* ! CONFIG_SMP */ + +extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) +{ + return wrmsr_eio(reg, eax, edx); +} + +extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +{ + return rdmsr_eio(reg, eax, edx); +} + +#endif /* ! CONFIG_SMP */ + +static loff_t msr_seek(struct file *file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; /* SEEK_END not supported */ + } +} + +static ssize_t msr_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + u32 *tmp = (u32 *)buf; + u32 data[2]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int err; + + if ( count % 8 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 8 ) { + err = do_rdmsr(cpu, reg, &data[0], &data[1]); + if ( err ) + return err; + if ( copy_to_user(tmp,&data,8) ) + return -EFAULT; + tmp += 2; + } + + return ((char *)tmp) - buf; +} + +static ssize_t msr_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + const u32 *tmp = (const u32 *)buf; + u32 data[2]; + size_t rv; + u32 reg = *ppos; + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + int err; + + if ( count % 8 ) + return -EINVAL; /* Invalid chunk size */ + + for ( rv = 0 ; count ; count -= 8 ) { + if ( copy_from_user(&data,tmp,8) ) + return -EFAULT; + err = do_wrmsr(cpu, reg, data[0], data[1]); + if ( err ) + return err; + tmp += 2; + } + + return ((char *)tmp) - buf; +} + +static int msr_open(struct inode *inode, struct file *file) +{ + int cpu = MINOR(file->f_dentry->d_inode->i_rdev); + + if ( !(cpu_online_map & (1UL << cpu)) || + !((cpu_data)[cpu].x86_capability & X86_FEATURE_MSR) ) + return -ENXIO; /* No such CPU */ + + MOD_INC_USE_COUNT; + return 0; +} + +static int msr_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * File operations we support + */ +static struct file_operations msr_fops = { + llseek: msr_seek, + read: msr_read, + write: msr_write, + open: msr_open, + release: msr_release, +}; + +int __init msr_init(void) +{ + if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { + printk(KERN_ERR "msr: unable to get major %d for msr\n", + MSR_MAJOR); + return -EBUSY; + } + + return 0; +} + +void __exit msr_exit(void) +{ +} + +module_init(msr_init); +module_exit(msr_exit) + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("H. Peter Anvin "); +MODULE_DESCRIPTION("x86 generic MSR driver"); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.3.99-pre9/linux/arch/i386/kernel/process.c Wed Apr 26 16:34:06 2000 +++ linux/arch/i386/kernel/process.c Wed May 24 14:05:57 2000 @@ -2,6 +2,8 @@ * linux/arch/i386/kernel/process.c * * Copyright (C) 1995 Linus Torvalds + * Pentium III code by Ingo Molnar with changes and support for + * OS exception support by Goutham Rao */ /* @@ -468,6 +470,94 @@ new_mm->segments = ldt; return; } + +#ifdef CONFIG_X86_FX + +int i387_hard_to_user ( struct _fpstate * user, + struct i387_hard_struct * hard) +{ + int i, err = 0; + short *tmp, *tmp2; + long *ltmp1, *ltmp2; + + err |= put_user(hard->cwd, &user->cw); + err |= put_user(hard->swd, &user->sw); + err |= put_user(fputag_KNIto387(hard->twd), &user->tag); + err |= put_user(hard->fip, &user->ipoff); + err |= put_user(hard->fcs, &user->cssel); + err |= put_user(hard->fdp, &user->dataoff); + err |= put_user(hard->fds, &user->datasel); + err |= put_user(hard->mxcsr, &user->mxcsr); + + tmp = (short *)&user->_st; + tmp2 = (short *)&hard->st_space; + + /* + * Transform the two layouts: + * (we do not mix 32-bit access with 16-bit access because + * thats suboptimal on PPros) + */ + for (i = 0; i < 8; i++) + { + err |= put_user(*tmp2, tmp); tmp++; tmp2++; + err |= put_user(*tmp2, tmp); tmp++; tmp2++; + err |= put_user(*tmp2, tmp); tmp++; tmp2++; + err |= put_user(*tmp2, tmp); tmp++; tmp2++; + err |= put_user(*tmp2, tmp); tmp++; tmp2 += 3; + } + + ltmp1 = (unsigned long *)&(user->_xmm[0]); + ltmp2 = (unsigned long *)&(hard->xmm_space[0]); + for(i = 0; i < 88; i++) + { + err |= put_user(*ltmp2, ltmp1); + ltmp1++; ltmp2++; + } + + return err; +} + +int i387_user_to_hard (struct i387_hard_struct * hard, + struct _fpstate * user) +{ + int i, err = 0; + short *tmp, *tmp2; + long *ltmp1, *ltmp2; + + err |= get_user(hard->cwd, &user->cw); + err |= get_user(hard->swd, &user->sw); + err |= get_user(hard->twd, &user->tag); + hard->twd = fputag_387toKNI(hard->twd); + err |= get_user(hard->fip, &user->ipoff); + err |= get_user(hard->fcs, &user->cssel); + err |= get_user(hard->fdp, &user->dataoff); + err |= get_user(hard->fds, &user->datasel); + err |= get_user(hard->mxcsr, &user->mxcsr); + + tmp2 = (short *)&hard->st_space; + tmp = (short *)&user->_st; + + for (i = 0; i < 8; i++) + { + err |= get_user(*tmp2, tmp); tmp++; tmp2++; + err |= get_user(*tmp2, tmp); tmp++; tmp2++; + err |= get_user(*tmp2, tmp); tmp++; tmp2++; + err |= get_user(*tmp2, tmp); tmp++; tmp2++; + err |= get_user(*tmp2, tmp); tmp++; tmp2 += 3; + } + + ltmp1 = (unsigned long *)(&user->_xmm[0]); + ltmp2 = (unsigned long *)(&hard->xmm_space[0]); + for(i = 0; i < (88); i++) + { + err |= get_user(*ltmp2, ltmp1); + ltmp2++; ltmp1++; + } + + return err; +} + +#endif /* * Save a segment. diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.3.99-pre9/linux/arch/i386/kernel/ptrace.c Thu May 11 15:30:06 2000 +++ linux/arch/i386/kernel/ptrace.c Wed May 24 15:07:29 2000 @@ -1,5 +1,6 @@ /* ptrace.c */ /* By Ross Biro 1/23/92 */ +/* FXSAVE/FXRSTOR support by Ingo Molnar and modifications by Goutham Rao */ /* edited by Linus Torvalds */ #include /* for CONFIG_MATH_EMULATION */ @@ -398,14 +399,14 @@ ret = 0; if ( !child->used_math ) { /* Simulate an empty FPU. */ - child->thread.i387.hard.cwd = 0xffff037f; - child->thread.i387.hard.swd = 0xffff0000; - child->thread.i387.hard.twd = 0xffffffff; - } + i387_set_cwd(child->thread.i387.hard, 0x037f); + i387_set_swd(child->thread.i387.hard, 0x0000); + i387_set_twd(child->thread.i387.hard, 0xffff); + } #ifdef CONFIG_MATH_EMULATION if ( boot_cpu_data.hard_math ) { #endif - __copy_to_user((void *)data, &child->thread.i387.hard, sizeof(struct user_i387_struct)); + i387_hard_to_user((struct _fpstate *)data, &child->thread.i387.hard); #ifdef CONFIG_MATH_EMULATION } else { save_i387_soft(&child->thread.i387.soft, (struct _fpstate *)data); @@ -423,7 +424,7 @@ #ifdef CONFIG_MATH_EMULATION if ( boot_cpu_data.hard_math ) { #endif - __copy_from_user(&child->thread.i387.hard, (void *)data, sizeof(struct user_i387_struct)); + i387_user_to_hard(&child->thread.i387.hard,(struct _fpstate *)data); #ifdef CONFIG_MATH_EMULATION } else { restore_i387_soft(&child->thread.i387.soft, (struct _fpstate *)data); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.99-pre9/linux/arch/i386/kernel/setup.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/setup.c Wed May 24 18:29:30 2000 @@ -39,7 +39,8 @@ * Detection for Celeron coppermine, identify_cpu() overhauled, * and a few other clean ups. * Dave Jones , April 2000 - * + * Pentium-III code by Ingo Molnar and modifications by Goutham Rao + * */ /* @@ -800,14 +801,30 @@ conswitchp = &dummy_con; #endif #endif +#ifdef CONFIG_X86_FX + if (boot_cpu_data.x86_capability & X86_FEATURE_FXSR) + { + printk("Enabling extended fast FPU save and restore ... "); + set_in_cr4(X86_CR4_OSFXSR); + printk("done.\n"); + } + if (boot_cpu_data.x86_capability & X86_FEATURE_XMM) + { + printk("Enabling KNI unmasked exception support ... "); + set_in_cr4(X86_CR4_OSXMMEXCPT); + printk("done.\n"); + } +#endif } static int __init get_model_name(struct cpuinfo_x86 *c) { unsigned int n, dummy, *v; - /* Actually we must have cpuid or we could never have - * figured out that this was AMD/Cyrix from the vendor info :-). + /* + * Actually we must have cpuid or we could never have + * figured out that this was AMD/Cyrix/Transmeta + * from the vendor info :-). */ cpuid(0x80000000, &n, &dummy, &dummy, &dummy); @@ -1196,6 +1213,86 @@ sprintf( c->x86_model_id, "WinChip %s", name ); } +static void __init transmeta_model(struct cpuinfo_x86 *c) +{ + unsigned int cap_mask, uk, max, dummy, n, ecx, edx; + unsigned int cms_rev1, cms_rev2; + unsigned int cpu_rev, cpu_freq, cpu_flags; + char cpu_info[65]; + + get_model_name(c); /* Same as AMD/Cyrix */ + + /* Print CMS and CPU revision */ + cpuid(0x80860000, &max, &dummy, &dummy, &dummy); + if ( max >= 0x80860001 ) { + cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); + printk("CPU: Processor revision %u.%u.%u.%u, %u MHz%s%s\n", + (cpu_rev >> 24) & 0xff, + (cpu_rev >> 16) & 0xff, + (cpu_rev >> 8) & 0xff, + cpu_rev & 0xff, + cpu_freq, + (cpu_flags & 1) ? " [recovery]" : "", + (cpu_flags & 2) ? " [longrun]" : ""); + } + if ( max >= 0x80860002 ) { + cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy); + printk("CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n", + (cms_rev1 >> 24) & 0xff, + (cms_rev1 >> 16) & 0xff, + (cms_rev1 >> 8) & 0xff, + cms_rev1 & 0xff, + cms_rev2); + } + if ( max >= 0x80860006 ) { + cpuid(0x80860003, + (void *)&cpu_info[0], + (void *)&cpu_info[4], + (void *)&cpu_info[8], + (void *)&cpu_info[12]); + cpuid(0x80860004, + (void *)&cpu_info[16], + (void *)&cpu_info[20], + (void *)&cpu_info[24], + (void *)&cpu_info[28]); + cpuid(0x80860005, + (void *)&cpu_info[32], + (void *)&cpu_info[36], + (void *)&cpu_info[40], + (void *)&cpu_info[44]); + cpuid(0x80860006, + (void *)&cpu_info[48], + (void *)&cpu_info[52], + (void *)&cpu_info[56], + (void *)&cpu_info[60]); + cpu_info[64] = '\0'; + printk("CPU: %s\n", cpu_info); + } + + /* Unhide possibly hidden flags */ + rdmsr(0x80860004, cap_mask, uk); + wrmsr(0x80860004, ~0, uk); + cpuid(0x00000001, &dummy, &dummy, &dummy, &c->x86_capability); + wrmsr(0x80860004, cap_mask, uk); + + + /* L1/L2 cache */ + cpuid(0x80000000, &n, &dummy, &dummy, &dummy); + + if (n >= 0x80000005) { + cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); + printk("CPU: L1 I Cache: %dK L1 D Cache: %dK\n", + ecx>>24, edx>>24); + c->x86_cache_size=(ecx>>24)+(edx>>24); + } + if (n >= 0x80000006) { + cpuid(0x80000006, &dummy, &dummy, &ecx, &edx); + printk("CPU: L2 Cache: %dK\n", ecx>>16); + c->x86_cache_size=(ecx>>16); + } +} + + void __init get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; @@ -1214,6 +1311,8 @@ c->x86_vendor = X86_VENDOR_NEXGEN; else if (!strcmp(v, "RiseRiseRise")) c->x86_vendor = X86_VENDOR_RISE; + else if (!strcmp(v, "GenuineTMx86")) + c->x86_vendor = X86_VENDOR_TRANSMETA; else c->x86_vendor = X86_VENDOR_UNKNOWN; } @@ -1263,6 +1362,9 @@ { X86_VENDOR_RISE, 5, { "mP6", "mP6", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + { X86_VENDOR_TRANSMETA, 5, + { NULL, NULL, NULL, "Crusoe", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, }; void __init identify_cpu(struct cpuinfo_x86 *c) @@ -1275,6 +1377,16 @@ get_cpu_vendor(c); + /* It should be possible for the user to override this. */ + if(c->x86_capability&(1<<18)) { + /* Disable processor serial number */ + unsigned long lo,hi; + rdmsr(0x119,lo,hi); + lo |= 0x200000; + wrmsr(0x119,lo,hi); + printk(KERN_INFO "CPU serial number disabled.\n"); + } + switch (c->x86_vendor) { case X86_VENDOR_UNKNOWN: @@ -1296,16 +1408,6 @@ return; case X86_VENDOR_INTEL: - if(c->x86_capability&(1<<18)) { - /* Disable processor serial number on Intel Pentium III - from code by Phil Karn */ - unsigned long lo,hi; - rdmsr(0x119,lo,hi); - lo |= 0x200000; - wrmsr(0x119,lo,hi); - printk(KERN_INFO "Pentium-III serial number disabled.\n"); - } - if (c->cpuid_level > 1) { /* supports eax=2 call */ int edx, dummy; @@ -1374,6 +1476,10 @@ goto name_decoded; break; + + case X86_VENDOR_TRANSMETA: + transmeta_model(c); + return; } @@ -1412,7 +1518,7 @@ static char *cpu_vendor_names[] __initdata = { - "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise" }; + "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" }; void __init print_cpu_info(struct cpuinfo_x86 *c) @@ -1424,7 +1530,7 @@ else if (c->cpuid_level >= 0) vendor = c->x86_vendor_id; - if (vendor) + if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor))) printk("%s ", vendor); if (!c->x86_model_id[0]) @@ -1434,6 +1540,8 @@ if (c->x86_mask || c->cpuid_level>=0) printk(" stepping %02x\n", c->x86_mask); + else + printk("\n"); } /* @@ -1513,7 +1621,9 @@ case X86_VENDOR_INTEL: x86_cap_flags[16] = "pat"; + x86_cap_flags[18] = "pn"; x86_cap_flags[24] = "fxsr"; + x86_cap_flags[25] = "xmm"; break; case X86_VENDOR_CENTAUR: @@ -1522,7 +1632,7 @@ break; default: - /* Unknown CPU manufacturer. Transmeta ? :-) */ + /* Unknown CPU manufacturer or no special handling needed */ break; } diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.3.99-pre9/linux/arch/i386/kernel/signal.c Wed Apr 26 16:34:06 2000 +++ linux/arch/i386/kernel/signal.c Wed May 24 18:38:26 2000 @@ -4,6 +4,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson + * Pentium III support by Ingo Molnar, modifications and OS Exception support + * by Goutham Rao */ #include @@ -30,6 +32,41 @@ int options, unsigned long *ru); asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -155,7 +192,7 @@ { struct task_struct *tsk = current; clear_fpu(tsk); - return __copy_from_user(&tsk->thread.i387.hard, buf, sizeof(*buf)); + return i387_user_to_hard(&tsk->thread.i387.hard, buf); } static inline int restore_i387(struct _fpstate *buf) @@ -309,7 +346,7 @@ unlazy_fpu(tsk); tsk->thread.i387.hard.status = tsk->thread.i387.hard.swd; - if (__copy_to_user(buf, &tsk->thread.i387.hard, sizeof(*buf))) + if (i387_hard_to_user(buf, &tsk->thread.i387.hard)) return -1; return 1; } @@ -491,7 +528,7 @@ &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->info, info); if (err) goto give_sigsegv; diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.3.99-pre9/linux/arch/i386/kernel/smp.c Wed Apr 26 16:34:06 2000 +++ linux/arch/i386/kernel/smp.c Wed May 24 15:46:10 2000 @@ -133,6 +133,11 @@ unsigned int cfg; /* + * Wait for idle. + */ + apic_wait_icr_idle(); + + /* * No need to touch the target chip field */ cfg = __prepare_ICR(shortcut, vector); @@ -171,6 +176,11 @@ __save_flags(flags); __cli(); + + /* + * Wait for idle. + */ + apic_wait_icr_idle(); /* * prepare target chip field diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.3.99-pre9/linux/arch/i386/kernel/smpboot.c Wed Apr 26 16:34:06 2000 +++ linux/arch/i386/kernel/smpboot.c Wed May 24 15:46:10 2000 @@ -502,6 +502,11 @@ for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) { printk("... APIC #%d %s: ", apicid, names[i]); + /* + * Wait for idle. + */ + apic_wait_icr_idle(); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.3.99-pre9/linux/arch/i386/kernel/traps.c Tue May 23 15:31:33 2000 +++ linux/arch/i386/kernel/traps.c Wed May 24 18:38:26 2000 @@ -2,6 +2,7 @@ * linux/arch/i386/traps.c * * Copyright (C) 1991, 1992 Linus Torvalds + * FXSAVE/FXRSTOR support by Ingo Molnar, OS exception support by Goutham Rao */ /* @@ -82,6 +83,20 @@ force_sig(signr, tsk); \ } +#define DO_ERROR_INFO(trapnr, signr, str, name, tsk, sicode, siaddr) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + tsk->thread.error_code = error_code; \ + tsk->thread.trap_no = trapnr; \ + die_if_no_fixup(str,regs,error_code); \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + force_sig_info(signr, &info, tsk); \ +} + #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ @@ -99,6 +114,28 @@ unlock_kernel(); \ } +#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, tsk, sicode, siaddr) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + lock_kernel(); \ + if (regs->eflags & VM_MASK) { \ + if (!handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr)) \ + goto out; \ + /* else fall through */ \ + } \ + tsk->thread.error_code = error_code; \ + tsk->thread.trap_no = trapnr; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + force_sig_info(signr, &info, tsk); \ + die_if_kernel(str,regs,error_code); \ +out: \ + unlock_kernel(); \ +} + void page_exception(void); asmlinkage void divide_error(void); @@ -120,6 +157,7 @@ asmlinkage void reserved(void); asmlinkage void alignment_check(void); asmlinkage void spurious_interrupt_bug(void); +asmlinkage void xmm_fault(void); int kstack_depth_to_print = 24; @@ -260,34 +298,29 @@ } } -DO_VM86_ERROR( 0, SIGFPE, "divide error", divide_error, current) +static inline unsigned long get_cr2(void) +{ + unsigned long address; + + /* get the address */ + __asm__("movl %%cr2,%0":"=r" (address)); + return address; +} + +DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, current, FPE_INTDIV, regs->eip) DO_VM86_ERROR( 3, SIGTRAP, "int3", int3, current) DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow, current) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds, current) -DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current) +DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, current, ILL_ILLOPN, regs->eip) DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available, current) DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current) DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, current) DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) -DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, current, BUS_ADRALN, get_cr2()) DO_ERROR(18, SIGSEGV, "reserved", reserved, current) -/* I don't have documents for this but it does seem to cover the cache - flush from user space exception some people get. */ -DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current) - -asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code) -{ - if (regs->eflags & VM_MASK) { - handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); - return; - } - die_if_kernel("cache flush denied",regs,error_code); - current->thread.error_code = error_code; - current->thread.trap_no = 19; - force_sig(SIGSEGV, current); -} +DO_VM86_ERROR(19, SIGFPE, "XMM fault", xmm_fault, current) asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { @@ -485,6 +518,7 @@ { unsigned int condition; struct task_struct *tsk = current; + siginfo_t info; __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); @@ -519,7 +553,11 @@ /* Ok, finally something we can handle */ tsk->thread.trap_no = 1; tsk->thread.error_code = error_code; - force_sig(SIGTRAP, tsk); + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void *)regs->eip; + force_sig_info(SIGTRAP, &info, tsk); return; debug_vm86: @@ -544,9 +582,10 @@ * the correct behaviour even in the presence of the asynchronous * IRQ13 behaviour */ -void math_error(void) +void math_error(void *eip) { struct task_struct * task; + siginfo_t info; /* * Save the info for the exception handler @@ -556,13 +595,52 @@ save_fpu(task); task->thread.trap_no = 16; task->thread.error_code = 0; - force_sig(SIGFPE, task); + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * (~cwd & swd) will mask out exceptions that are not set to unmasked + * status. 0x3f is the exception bits in these regs, 0x200 is the + * C1 reg you need in case of a stack fault, 0x040 is the stack + * fault bit. We should only be taking one exception at a time, + * so if this combination doesn't produce any single exception, + * then we have a bad program that isn't syncronizing its FPU usage + * and it will suffer the consequences since we won't be able to + * fully reproduce the context of the exception + */ + switch(((~task->thread.i387.hard.cwd) & + task->thread.i387.hard.swd & 0x3f) | + (task->thread.i387.hard.swd & 0x240)) { + case 0x000: + default: + break; + case 0x001: /* Invalid Op */ + case 0x040: /* Stack Fault */ + case 0x240: /* Stack Fault | Direction */ + info.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); } asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) { ignore_irq13 = 1; - math_error(); + math_error((void *)regs->eip); } asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, @@ -586,7 +664,7 @@ __asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */ if(current->used_math) - __asm__("frstor %0": :"m" (current->thread.i387)); + i387_restore_hard(current->thread.i387); else { /* @@ -829,6 +907,8 @@ set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); + set_trap_gate(19,&xmm_fault); + set_system_gate(SYSCALL_VECTOR,&system_call); /* diff -u --recursive --new-file v2.3.99-pre9/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.3.99-pre9/linux/arch/i386/mm/fault.c Thu May 11 15:30:06 2000 +++ linux/arch/i386/mm/fault.c Wed May 24 18:38:26 2000 @@ -124,13 +124,14 @@ unsigned long page; unsigned long fixup; int write; - int si_code = SEGV_MAPERR; + siginfo_t info; /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); tsk = current; mm = tsk->mm; + info.si_code = SEGV_MAPERR; /* * If we're in an interrupt or have no user @@ -165,9 +166,8 @@ * we can handle it.. */ good_area: + info.si_code = SEGV_ACCERR; write = 0; - si_code = SEGV_ACCERR; - switch (error_code & 3) { default: /* 3: write, present */ #ifdef TEST_VERIFY_AREA @@ -225,14 +225,14 @@ /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { - struct siginfo si; tsk->thread.cr2 = address; tsk->thread.error_code = error_code; tsk->thread.trap_no = 14; - si.si_signo = SIGSEGV; - si.si_code = si_code; - si.si_addr = (void*) address; - force_sig_info(SIGSEGV, &si, tsk); + 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, tsk); return; } @@ -309,7 +309,11 @@ tsk->thread.cr2 = address; tsk->thread.error_code = error_code; tsk->thread.trap_no = 14; - force_sig(SIGBUS, tsk); + info.si_code = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + force_sig_info(SIGBUS, &info, tsk); /* Kernel mode? Handle exceptions or die */ if (!(error_code & 4)) diff -u --recursive --new-file v2.3.99-pre9/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c --- v2.3.99-pre9/linux/arch/ia64/ia32/ia32_signal.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/ia32/ia32_signal.c Wed May 24 18:38:26 2000 @@ -48,13 +48,58 @@ int sig; int pinfo; int puc; - struct siginfo info; + siginfo_t32 info; struct ucontext_ia32 uc; struct _fpstate_ia32 fpstate; char retcode[8]; }; static int +copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from) +{ + int err; + + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) + return -EFAULT; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. + This routine must convert siginfo from 64bit to 32bit as well + at the same time. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + if (from->si_code < 0) + err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); + else { + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_uid, &to->si_uid); + break; + case __SI_FAULT >> 16: + err |= __put_user((long)from->si_addr, &to->si_addr); + break; + case __SI_POLL >> 16: + err |= __put_user(from->si_band, &to->si_band); + err |= __put_user(from->si_fd, &to->si_fd); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + } + return err; +} + + + +static int setup_sigcontext_ia32(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, struct pt_regs *regs, unsigned long mask) { @@ -283,7 +328,7 @@ &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user32(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c --- v2.3.99-pre9/linux/arch/ia64/kernel/signal.c Wed Apr 26 16:34:06 2000 +++ linux/arch/ia64/kernel/signal.c Wed May 24 18:38:26 2000 @@ -138,6 +138,43 @@ return err; } +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + case __SI_POLL >> 16: + err |= __put_user(from->si_addr, &to->si_addr); + err |= __put_user(from->si_imm, &to->si_imm); + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * When we get here, ((struct switch_stack *) pt - 1) is a * switch_stack frame that has no defined value. Upon return, we @@ -290,7 +327,7 @@ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err = __copy_to_user(&frame->info, info, sizeof(siginfo_t)); + err = copy_siginfo_to_user(&frame->info, info); err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp); err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c --- v2.3.99-pre9/linux/arch/m68k/kernel/signal.c Tue Feb 1 01:35:43 2000 +++ linux/arch/m68k/kernel/signal.c Wed May 24 18:38:26 2000 @@ -189,6 +189,41 @@ }; +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ static inline int restore_fpu_state(struct sigcontext *sc) @@ -877,7 +912,7 @@ &frame->sig); err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c --- v2.3.99-pre9/linux/arch/mips/kernel/signal.c Tue May 23 15:31:33 2000 +++ linux/arch/mips/kernel/signal.c Wed May 24 18:38:26 2000 @@ -37,6 +37,41 @@ extern asmlinkage int save_fp_context(struct sigcontext *sc); extern asmlinkage int restore_fp_context(struct sigcontext *sc); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -438,7 +473,7 @@ } /* Create siginfo. */ - err |= __copy_to_user(&frame->rs_info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->rs_info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/mips64/kernel/signal.c linux/arch/mips64/kernel/signal.c --- v2.3.99-pre9/linux/arch/mips64/kernel/signal.c Tue May 23 15:31:33 2000 +++ linux/arch/mips64/kernel/signal.c Wed May 24 18:38:26 2000 @@ -38,6 +38,41 @@ extern asmlinkage int save_fp_context(struct sigcontext *sc); extern asmlinkage int restore_fp_context(struct sigcontext *sc); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + err |= __put_user((long)from->si_addr, &to->si_addr); + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_pid, &to->si_pid); + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + static inline int store_fp_context(struct sigcontext *sc) { unsigned int fcr0; @@ -466,7 +501,7 @@ } /* Create siginfo. */ - err |= __copy_to_user(&frame->rs_info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->rs_info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.3.99-pre9/linux/arch/ppc/kernel/signal.c Tue Nov 23 22:42:20 1999 +++ linux/arch/ppc/kernel/signal.c Wed May 24 18:38:26 2000 @@ -58,6 +58,41 @@ extern int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sh/kernel/signal.c linux/arch/sh/kernel/signal.c --- v2.3.99-pre9/linux/arch/sh/kernel/signal.c Tue May 23 15:31:34 2000 +++ linux/arch/sh/kernel/signal.c Wed May 24 18:38:26 2000 @@ -33,6 +33,41 @@ int options, unsigned long *ru); asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -424,7 +459,7 @@ err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); - err |= __copy_to_user(&frame->info, info, sizeof(*info)); + err |= copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v2.3.99-pre9/linux/arch/sparc/kernel/Makefile Tue May 23 15:31:34 2000 +++ linux/arch/sparc/kernel/Makefile Tue May 23 22:34:19 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.54 2000/05/12 23:51:24 davem Exp $ +# $Id: Makefile,v 1.55 2000/05/23 23:09:08 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.3.99-pre9/linux/arch/sparc/kernel/signal.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc/kernel/signal.c Wed May 24 18:38:26 2000 @@ -95,6 +95,38 @@ __siginfo_fpu_t fpu_state; }; +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + /* case __SI_RT: This is not generated by the kernel as of now. */ + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_pid, &to->si_pid); + break; + } + return err; + } +} + /* Align macros */ #define SF_ALIGNEDSZ (((sizeof(struct signal_sframe) + 7) & (~7))) #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) @@ -710,7 +742,7 @@ err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window)); - err |= __copy_to_user(&sf->info, info, sizeof(siginfo_t)); + err |= copy_siginfo_to_user(&sf->info, info); if (err) goto sigsegv; diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.99-pre9/linux/arch/sparc64/defconfig Fri May 12 14:18:55 2000 +++ linux/arch/sparc64/defconfig Tue May 23 22:34:19 2000 @@ -201,6 +201,13 @@ # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDETAPE=m diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.3.99-pre9/linux/arch/sparc64/kernel/Makefile Tue May 23 15:31:34 2000 +++ linux/arch/sparc64/kernel/Makefile Wed May 24 08:29:47 2000 @@ -81,13 +81,11 @@ @echo -e "# error Please issue 'make check_asm' in linux top-level directory first\n# endif\n#endif\n" >> asm_offsets.h @echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h @echo "#include " > tmp.c - @echo "#undef __SMP__" >> tmp.c @echo "#undef CONFIG_SMP" >> tmp.c @echo "#include " >> tmp.c $(CPP) $(CPPFLAGS) tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @echo "#include " >> check_asm.c - @echo "#undef __SMP__" >> check_asm.c @echo "#undef CONFIG_SMP" >> check_asm.c @echo "#include " >> check_asm.c @echo 'struct task_struct _task;' >> check_asm.c @@ -128,7 +126,7 @@ $(SH) ./check_asm.sh thread tmp.i check_asm.c @echo 'return 0; }' >> check_asm.c @rm -f tmp.[ci] - #$(CC) -D__SMP__ -o check_asm check_asm.c + #$(CC) -o check_asm check_asm.c # Until we can do this natively, a hack has to take place $(CC) $(CPPFLAGS) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s @@ -153,7 +151,7 @@ $(SH) ./check_asm.sh thread tmp.i check_asm.c @echo 'return 0; }' >> check_asm.c @rm -f tmp.[ci] - #$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c + #$(CC) -DSPIN_LOCK_DEBUG -o check_asm check_asm.c # Until we can do this natively, a hack has to take place $(CC) $(CPPFLAGS) -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.3.99-pre9/linux/arch/sparc64/kernel/ioctl32.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Tue May 23 22:34:19 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.90 2000/05/22 07:29:39 davem Exp $ +/* $Id: ioctl32.c,v 1.91 2000/05/23 05:25:44 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -2353,6 +2353,542 @@ } #endif +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) +/* This really belongs in include/linux/drm.h -DaveM */ +#include "../../../drivers/char/drm/drm.h" + +typedef struct drm32_version { + int version_major; /* Major version */ + int version_minor; /* Minor version */ + int version_patchlevel;/* Patch level */ + int name_len; /* Length of name buffer */ + u32 name; /* Name of driver */ + int date_len; /* Length of date buffer */ + u32 date; /* User-space buffer to hold date */ + int desc_len; /* Length of desc buffer */ + u32 desc; /* User-space buffer to hold desc */ +} drm32_version_t; +#define DRM32_IOCTL_VERSION DRM_IOWR(0x00, drm32_version_t) + +static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_version_t *uversion = (drm32_version_t *)arg; + char *name_ptr, *date_ptr, *desc_ptr; + u32 tmp1, tmp2, tmp3; + drm_version_t kversion; + mm_segment_t old_fs; + int ret; + + memset(&kversion, 0, sizeof(kversion)); + if (get_user(kversion.name_len, &uversion->name_len) || + get_user(kversion.date_len, &uversion->date_len) || + get_user(kversion.desc_len, &uversion->desc_len) || + get_user(tmp1, &uversion->name) || + get_user(tmp2, &uversion->date) || + get_user(tmp3, &uversion->desc)) + return -EFAULT; + + name_ptr = (char *) A(tmp1); + date_ptr = (char *) A(tmp2); + desc_ptr = (char *) A(tmp3); + + ret = -ENOMEM; + if (kversion.name_len && name_ptr) { + kversion.name = kmalloc(kversion.name_len, GFP_KERNEL); + if (!kversion.name) + goto out; + } + if (kversion.date_len && date_ptr) { + kversion.date = kmalloc(kversion.date_len, GFP_KERNEL); + if (!kversion.date) + goto out; + } + if (kversion.desc_len && desc_ptr) { + kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL); + if (!kversion.desc) + goto out; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion); + set_fs(old_fs); + + if (!ret) { + if ((kversion.name && + copy_to_user(name_ptr, kversion.name, kversion.name_len)) || + (kversion.date && + copy_to_user(date_ptr, kversion.date, kversion.date_len)) || + (kversion.desc && + copy_to_user(desc_ptr, kversion.desc, kversion.desc_len))) + ret = -EFAULT; + if (put_user(kversion.version_major, &uversion->version_major) || + put_user(kversion.version_minor, &uversion->version_minor) || + put_user(kversion.version_patchlevel, &uversion->version_patchlevel) || + put_user(kversion.name_len, &uversion->name_len) || + put_user(kversion.date_len, &uversion->date_len) || + put_user(kversion.desc_len, &uversion->desc_len)) + ret = -EFAULT; + } + +out: + if (kversion.name) + kfree(kversion.name); + if (kversion.date) + kfree(kversion.date); + if (kversion.desc) + kfree(kversion.desc); + return ret; +} + +typedef struct drm32_unique { + size_t unique_len; /* Length of unique */ + u32 unique; /* Unique name for driver instantiation */ +} drm32_unique_t; +#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t) +#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t) + +static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_unique_t *uarg = (drm32_unique_t *)arg; + drm_unique_t karg; + mm_segment_t old_fs; + char *uptr; + u32 tmp; + int ret; + + if (get_user(karg.unique_len, &uarg->unique_len)) + return -EFAULT; + karg.unique = NULL; + + if (get_user(tmp, &uarg->unique)) + return -EFAULT; + + uptr = (char *) A(tmp); + + if (uptr) { + karg.unique = kmalloc(karg.unique_len, GFP_KERNEL); + if (!karg.unique) + return -ENOMEM; + if (cmd == DRM32_IOCTL_SET_UNIQUE && + copy_from_user(karg.unique, uptr, karg.unique_len)) { + kfree(karg.unique); + return -EFAULT; + } + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + if (cmd == DRM32_IOCTL_GET_UNIQUE) + ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg); + else + ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg); + set_fs(old_fs); + + if (!ret) { + if (cmd == DRM32_IOCTL_GET_UNIQUE && + copy_to_user(uptr, karg.unique, karg.unique_len)) + ret = -EFAULT; + if (put_user(karg.unique_len, &uarg->unique_len)) + ret = -EFAULT; + } + + kfree(karg.unique); + + return ret; +} + +typedef struct drm32_map { + u32 offset; /* Requested physical address (0 for SAREA)*/ + u32 size; /* Requested physical size (bytes) */ + drm_map_type_t type; /* Type of memory to map */ + drm_map_flags_t flags; /* Flags */ + u32 handle; /* User-space: "Handle" to pass to mmap */ + /* Kernel-space: kernel-virtual address */ + int mtrr; /* MTRR slot used */ + /* Private data */ +} drm32_map_t; +#define DRM32_IOCTL_ADD_MAP DRM_IOWR(0x15, drm32_map_t) + +static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_map_t *uarg = (drm32_map_t *) arg; + drm_map_t karg; + mm_segment_t old_fs; + u32 tmp; + int ret; + + ret = get_user(karg.offset, &uarg->offset); + ret |= get_user(karg.size, &uarg->size); + ret |= get_user(karg.type, &uarg->type); + ret |= get_user(karg.flags, &uarg->flags); + ret |= get_user(tmp, &uarg->handle); + ret |= get_user(karg.mtrr, &uarg->mtrr); + if (ret) + return -EFAULT; + + karg.handle = (void *) A(tmp); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + ret = put_user(karg.offset, &uarg->offset); + ret |= put_user(karg.size, &uarg->size); + ret |= put_user(karg.type, &uarg->type); + ret |= put_user(karg.flags, &uarg->flags); + tmp = (u32) (long)karg.handle; + ret |= put_user(tmp, &uarg->handle); + ret |= put_user(karg.mtrr, &uarg->mtrr); + if (ret) + ret = -EFAULT; + } + + return ret; +} + +typedef struct drm32_buf_info { + int count; /* Entries in list */ + u32 list; /* (drm_buf_desc_t *) */ +} drm32_buf_info_t; +#define DRM32_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm32_buf_info_t) + +static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg; + drm_buf_desc_t *ulist; + drm_buf_info_t karg; + mm_segment_t old_fs; + int orig_count, ret; + u32 tmp; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->list)) + return -EFAULT; + + ulist = (drm_buf_desc_t *) A(tmp); + + orig_count = karg.count; + + karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL); + if (!karg.list) + return -EFAULT; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (karg.count <= orig_count && + (copy_to_user(ulist, karg.list, + karg.count * sizeof(drm_buf_desc_t)))) + ret = -EFAULT; + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + + kfree(karg.list); + + return ret; +} + +typedef struct drm32_buf_free { + int count; + u32 list; /* (int *) */ +} drm32_buf_free_t; +#define DRM32_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm32_buf_free_t) + +static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg; + drm_buf_free_t karg; + mm_segment_t old_fs; + int *ulist; + int ret; + u32 tmp; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->list)) + return -EFAULT; + + ulist = (int *) A(tmp); + + karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL); + if (!karg.list) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int)))) + goto out; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg); + set_fs(old_fs); + +out: + kfree(karg.list); + + return ret; +} + +typedef struct drm32_buf_pub { + int idx; /* Index into master buflist */ + int total; /* Buffer size */ + int used; /* Amount of buffer in use (for DMA) */ + u32 address; /* Address of buffer (void *) */ +} drm32_buf_pub_t; + +typedef struct drm32_buf_map { + int count; /* Length of buflist */ + u32 virtual; /* Mmaped area in user-virtual (void *) */ + u32 list; /* Buffer information (drm_buf_pub_t *) */ +} drm32_buf_map_t; +#define DRM32_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm32_buf_map_t) + +static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg; + drm32_buf_pub_t *ulist; + drm_buf_map_t karg; + mm_segment_t old_fs; + int orig_count, ret, i; + u32 tmp1, tmp2; + + if (get_user(karg.count, &uarg->count) || + get_user(tmp1, &uarg->virtual) || + get_user(tmp2, &uarg->list)) + return -EFAULT; + + karg.virtual = (void *) A(tmp1); + ulist = (drm32_buf_pub_t *) A(tmp2); + + orig_count = karg.count; + + karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL); + if (!karg.list) + return -ENOMEM; + + ret = -EFAULT; + for (i = 0; i < karg.count; i++) { + if (get_user(karg.list[i].idx, &ulist[i].idx) || + get_user(karg.list[i].total, &ulist[i].total) || + get_user(karg.list[i].used, &ulist[i].used) || + get_user(tmp1, &ulist[i].address)) + goto out; + + karg.list[i].address = (void *) A(tmp1); + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + for (i = 0; i < orig_count; i++) { + tmp1 = (u32) (long) karg.list[i].address; + if (put_user(karg.list[i].idx, &ulist[i].idx) || + put_user(karg.list[i].total, &ulist[i].total) || + put_user(karg.list[i].used, &ulist[i].used) || + put_user(tmp1, &ulist[i].address)) { + ret = -EFAULT; + goto out; + } + } + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + +out: + kfree(karg.list); + return ret; +} + +typedef struct drm32_dma { + /* Indices here refer to the offset into + buflist in drm_buf_get_t. */ + int context; /* Context handle */ + int send_count; /* Number of buffers to send */ + u32 send_indices; /* List of handles to buffers (int *) */ + u32 send_sizes; /* Lengths of data to send (int *) */ + drm_dma_flags_t flags; /* Flags */ + int request_count; /* Number of buffers requested */ + int request_size; /* Desired size for buffers */ + u32 request_indices; /* Buffer information (int *) */ + u32 request_sizes; /* (int *) */ + int granted_count; /* Number of buffers granted */ +} drm32_dma_t; +#define DRM32_IOCTL_DMA DRM_IOWR(0x29, drm32_dma_t) + +/* RED PEN The DRM layer blindly dereferences the send/request + * indice/size arrays even though they are userland + * pointers. -DaveM + */ +static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_dma_t *uarg = (drm32_dma_t *) arg; + int *u_si, *u_ss, *u_ri, *u_rs; + drm_dma_t karg; + mm_segment_t old_fs; + int ret; + u32 tmp1, tmp2, tmp3, tmp4; + + karg.send_indices = karg.send_sizes = NULL; + karg.request_indices = karg.request_sizes = NULL; + + if (get_user(karg.context, &uarg->context) || + get_user(karg.send_count, &uarg->send_count) || + get_user(tmp1, &uarg->send_indices) || + get_user(tmp2, &uarg->send_sizes) || + get_user(karg.flags, &uarg->flags) || + get_user(karg.request_count, &uarg->request_count) || + get_user(karg.request_size, &uarg->request_size) || + get_user(tmp3, &uarg->request_indices) || + get_user(tmp4, &uarg->request_sizes) || + get_user(karg.granted_count, &uarg->granted_count)) + return -EFAULT; + + u_si = (int *) A(tmp1); + u_ss = (int *) A(tmp2); + u_ri = (int *) A(tmp3); + u_rs = (int *) A(tmp4); + + if (karg.send_count) { + karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL); + karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL); + + ret = -ENOMEM; + if (!karg.send_indices || !karg.send_sizes) + goto out; + + ret = -EFAULT; + if (copy_from_user(karg.send_indices, u_si, + (karg.send_count * sizeof(int))) || + copy_from_user(karg.send_sizes, u_ss, + (karg.send_count * sizeof(int)))) + goto out; + } + + if (karg.request_count) { + karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL); + karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL); + + ret = -ENOMEM; + if (!karg.request_indices || !karg.request_sizes) + goto out; + + ret = -EFAULT; + if (copy_from_user(karg.request_indices, u_ri, + (karg.request_count * sizeof(int))) || + copy_from_user(karg.request_sizes, u_rs, + (karg.request_count * sizeof(int)))) + goto out; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (put_user(karg.context, &uarg->context) || + put_user(karg.send_count, &uarg->send_count) || + put_user(karg.flags, &uarg->flags) || + put_user(karg.request_count, &uarg->request_count) || + put_user(karg.request_size, &uarg->request_size) || + put_user(karg.granted_count, &uarg->granted_count)) + ret = -EFAULT; + + if (karg.send_count) { + if (copy_to_user(u_si, karg.send_indices, + (karg.send_count * sizeof(int))) || + copy_to_user(u_ss, karg.send_sizes, + (karg.send_count * sizeof(int)))) + ret = -EFAULT; + } + if (karg.request_count) { + if (copy_to_user(u_ri, karg.request_indices, + (karg.request_count * sizeof(int))) || + copy_to_user(u_rs, karg.request_sizes, + (karg.request_count * sizeof(int)))) + ret = -EFAULT; + } + } + +out: + if (karg.send_indices) + kfree(karg.send_indices); + if (karg.send_sizes) + kfree(karg.send_sizes); + if (karg.request_indices) + kfree(karg.request_indices); + if (karg.request_sizes) + kfree(karg.request_sizes); + + return ret; +} + +typedef struct drm32_ctx_res { + int count; + u32 contexts; /* (drm_ctx_t *) */ +} drm32_ctx_res_t; +#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t) + +static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg; + drm_ctx_t *ulist; + drm_ctx_res_t karg; + mm_segment_t old_fs; + int orig_count, ret; + u32 tmp; + + karg.contexts = NULL; + if (get_user(karg.count, &uarg->count) || + get_user(tmp, &uarg->contexts)) + return -EFAULT; + + ulist = (drm_ctx_t *) A(tmp); + + orig_count = karg.count; + if (karg.count && ulist) { + karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL); + if (!karg.contexts) + return -ENOMEM; + if (copy_from_user(karg.contexts, ulist, + (karg.count * sizeof(drm_ctx_t)))) { + kfree(karg.contexts); + return -EFAULT; + } + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg); + set_fs(old_fs); + + if (!ret) { + if (orig_count) { + if (copy_to_user(ulist, karg.contexts, + (orig_count * sizeof(drm_ctx_t)))) + ret = -EFAULT; + } + if (put_user(karg.count, &uarg->count)) + ret = -EFAULT; + } + + if (karg.contexts) + kfree(karg.contexts); + + return ret; +} + +#endif + static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) { return -EINVAL; @@ -2961,6 +3497,27 @@ COMPATIBLE_IOCTL(LV_SET_STATUS) COMPATIBLE_IOCTL(LV_SET_ALLOCATION) #endif /* LVM */ +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) +COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC) +COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID) +COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC) +COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK) +COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK) +COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL) +COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS) +COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS) +COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX) +COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX) +COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX) +COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX) +COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX) +COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX) +COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW) +COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW) +COMPATIBLE_IOCTL(DRM_IOCTL_LOCK) +COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK) +COMPATIBLE_IOCTL(DRM_IOCTL_FINISH) +#endif /* DRM */ /* elevator */ COMPATIBLE_IOCTL(BLKELVGET) COMPATIBLE_IOCTL(BLKELVSET) @@ -3108,6 +3665,17 @@ HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl) HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl) #endif /* LVM */ +#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) +HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version); +HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique); +HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique); +HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap); +HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs); +HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs); +HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs); +HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma); +HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx); +#endif /* DRM */ IOCTL_TABLE_END unsigned int ioctl32_hash_table[1024]; diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.3.99-pre9/linux/arch/sparc64/kernel/signal.c Wed Apr 26 16:34:07 2000 +++ linux/arch/sparc64/kernel/signal.c Wed May 24 18:38:26 2000 @@ -42,6 +42,38 @@ /* #define DEBUG_SIGNALS_TRACE 1 */ /* #define DEBUG_SIGNALS_MAPS 1 */ +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(*(long *)&from->si_signo, (long *)&to->si_signo); + err |= __put_user((short)from->si_code, &to->si_code); + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + case __SI_FAULT >> 16: + case __SI_POLL >> 16: + err |= __put_user(from->si_trapno, &to->si_trapno); + default: + err |= __put_user(from->si_addr, &to->si_addr); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* {set, get}context() needed for 64-bit SparcLinux userland. */ asmlinkage void sparc64_set_context(struct pt_regs *regs) { @@ -512,7 +544,7 @@ sizeof(struct reg_window)); if (info) - err |= copy_to_user(&sf->info, info, sizeof(siginfo_t)); + err |= copy_siginfo_to_user(&sf->info, info); else { err |= __put_user(signo, &sf->info.si_signo); err |= __put_user(SI_NOINFO, &sf->info.si_code); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.3.99-pre9/linux/arch/sparc64/kernel/signal32.c Wed Apr 26 16:34:07 2000 +++ linux/arch/sparc64/kernel/signal32.c Wed May 24 18:38:26 2000 @@ -108,17 +108,21 @@ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) return -EFAULT; + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. + This routine must convert siginfo from 64bit to 32bit as well + at the same time. */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user(from->si_code, &to->si_code); + err |= __put_user((short)from->si_code, &to->si_code); if (from->si_code < 0) err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { - int signo = from->si_signo; - if (from->si_code == SI_USER || from->si_code == SI_KERNEL) - signo = SIGRTMIN; - switch (signo) { - case SIGCHLD: + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_status, &to->si_status); @@ -126,16 +130,12 @@ err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); break; - case SIGURG: - case SIGIO: - case SIGSEGV: - case SIGILL: - case SIGFPE: - case SIGBUS: - case SIGEMT: + case __SI_FAULT >> 16: + case __SI_POLL >> 16: err |= __put_user(from->si_trapno, &to->si_trapno); err |= __put_user((long)from->si_addr, &to->si_addr); break; + /* case __SI_RT: This is not generated by the kernel as of now. */ } } return err; diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.3.99-pre9/linux/arch/sparc64/kernel/sparc64_ksyms.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Tue May 23 22:34:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.84 2000/05/09 17:40:14 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.85 2000/05/23 02:14:25 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -83,6 +83,7 @@ extern long sparc32_open(const char * filename, int flags, int mode); extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)); extern int unregister_ioctl32_conversion(unsigned int cmd); +extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space); extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); @@ -222,6 +223,9 @@ /* IOCTL32 emulation hooks. */ EXPORT_SYMBOL(register_ioctl32_conversion); EXPORT_SYMBOL(unregister_ioctl32_conversion); + +/* I/O device mmaping on Sparc64. */ +EXPORT_SYMBOL(io_remap_page_range); /* Solaris/SunOS binary compatibility */ EXPORT_SYMBOL(_sigpause_common); diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.3.99-pre9/linux/arch/sparc64/kernel/sys_sparc32.c Tue May 23 15:31:34 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Wed May 24 18:38:26 2000 @@ -2052,43 +2052,84 @@ return ret; } -extern asmlinkage int -sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, - const struct timespec *uts, size_t sigsetsize); - asmlinkage int sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, struct timespec32 *uts, __kernel_size_t32 sigsetsize) { - sigset_t s; - sigset_t32 s32; - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs(); + int ret, sig; + sigset_t these; + sigset_t32 these32; + struct timespec ts; siginfo_t info; - - if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) + long timeout = 0; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user (&these32, uthese, sizeof(sigset_t32))) return -EFAULT; + switch (_NSIG_WORDS) { - case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); - case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); - case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); - case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32); + case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32); + case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32); + case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32); } + + /* + * Invert the set of allowed signals to get those we + * want to block. + */ + sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP)); + signotset(&these); + if (uts) { - ret = get_user (t.tv_sec, &uts->tv_sec); - ret |= __get_user (t.tv_nsec, &uts->tv_nsec); - if (ret) - return -EFAULT; + if (get_user (ts.tv_sec, &uts->tv_sec) || + get_user (ts.tv_nsec, &uts->tv_nsec)) + return -EINVAL; + if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 + || ts.tv_sec < 0) + return -EINVAL; } - set_fs (KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); - set_fs (old_fs); - if (ret >= 0 && uinfo) { - extern int copy_siginfo_to_user32(siginfo_t32 *, siginfo_t *); - if (copy_siginfo_to_user32(uinfo, &info)) - ret = -EFAULT; + + spin_lock_irq(¤t->sigmask_lock); + sig = dequeue_signal(&these, &info); + if (!sig) { + /* None ready -- temporarily unblock those we're interested + in so that we'll be awakened when they arrive. */ + sigset_t oldblocked = current->blocked; + sigandsets(¤t->blocked, ¤t->blocked, &these); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + timeout = MAX_SCHEDULE_TIMEOUT; + if (uts) + timeout = (timespec_to_jiffies(&ts) + + (ts.tv_sec || ts.tv_nsec)); + + current->state = TASK_INTERRUPTIBLE; + timeout = schedule_timeout(timeout); + + spin_lock_irq(¤t->sigmask_lock); + sig = dequeue_signal(&these, &info); + current->blocked = oldblocked; + recalc_sigpending(current); } + spin_unlock_irq(¤t->sigmask_lock); + + if (sig) { + ret = sig; + if (uinfo) { + if (copy_siginfo_to_user32(uinfo, &info)) + ret = -EFAULT; + } + } else { + ret = -EAGAIN; + if (timeout) + ret = -EINTR; + } + return ret; } diff -u --recursive --new-file v2.3.99-pre9/linux/arch/sparc64/mm/modutil.c linux/arch/sparc64/mm/modutil.c --- v2.3.99-pre9/linux/arch/sparc64/mm/modutil.c Tue Aug 4 16:03:35 1998 +++ linux/arch/sparc64/mm/modutil.c Tue May 23 22:34:19 2000 @@ -1,4 +1,4 @@ -/* $Id: modutil.c,v 1.4 1998/07/26 06:29:08 davem Exp $ +/* $Id: modutil.c,v 1.5 2000/05/23 23:09:08 davem Exp $ * arch/sparc64/mm/modutil.c * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -58,7 +58,7 @@ area->next = *p; *p = area; - if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size)) { + if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL)) { vfree(addr); return NULL; } diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.99-pre9/linux/drivers/block/ll_rw_blk.c Fri May 12 14:18:55 2000 +++ linux/drivers/block/ll_rw_blk.c Wed May 24 18:38:26 2000 @@ -757,15 +757,6 @@ bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } -static inline void buffer_IO_error(struct buffer_head * bh) -{ - mark_buffer_clean(bh); - /* - * b_end_io has to clear the BH_Uptodate bitflag in the error case! - */ - bh->b_end_io(bh, 0); -} - int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { unsigned long flags; diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/block/lvm-snap.c linux/drivers/block/lvm-snap.c --- v2.3.99-pre9/linux/drivers/block/lvm-snap.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/lvm-snap.c Wed May 24 18:38:26 2000 @@ -278,12 +278,12 @@ lvm_hash_link(lv_snap->lv_block_exception + idx, org_phys_dev, org_start, lv_snap); lv_snap->lv_remap_ptr = idx + 1; - return 0; + return 1; /* slow path */ out: lvm_drop_snapshot(lv_snap, reason); - return 1; + return -1; fail_out_of_space: reason = "out of space"; diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/block/lvm.c linux/drivers/block/lvm.c --- v2.3.99-pre9/linux/drivers/block/lvm.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/block/lvm.c Wed May 24 18:38:26 2000 @@ -122,7 +122,7 @@ * - avoided "/dev/" in proc filesystem output * - avoided inline strings functions lvm_strlen etc. * 14/02/2000 - support for 2.3.43 - * - integrated Andrea Arcagnelli's snapshot code + * - integrated Andrea Arcangeli's snapshot code * */ @@ -171,9 +171,9 @@ #include #include -#define LVM_CORRECT_READ_AHEAD( a) \ - if ( a < LVM_MIN_READ_AHEAD || \ - a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD; +#define LVM_CORRECT_READ_AHEAD(a) \ + (((a) < LVM_MIN_READ_AHEAD || (a) > LVM_MAX_READ_AHEAD) \ + ? LVM_MAX_READ_AHEAD : (a)) #ifndef WRITEA # define WRITEA WRITE @@ -193,13 +193,11 @@ #define DEVICE_REQUEST lvm_dummy_device_request static int lvm_make_request_fn(request_queue_t *, int, struct buffer_head*); +static void lvm_plug_device_noop(request_queue_t *, kdev_t); static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); static int lvm_blk_open(struct inode *, struct file *); -static ssize_t lvm_blk_read(struct file *, char *, size_t, loff_t *); -static ssize_t lvm_blk_write(struct file *, const char *, size_t, loff_t *); - static int lvm_chr_open(struct inode *, struct file *); static int lvm_chr_close(struct inode *, struct file *); @@ -298,7 +296,6 @@ static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait); static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; -static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; static struct file_operations lvm_chr_fops = { @@ -307,18 +304,6 @@ ioctl: lvm_chr_ioctl, }; -static struct file_operations lvm_blk_fops = -{ - open: lvm_blk_open, - release: blkdev_close, - read: lvm_blk_read, - write: lvm_blk_write, - ioctl: lvm_blk_ioctl, - fsync: block_fsync, -}; - -#define BLOCK_DEVICE_OPERATIONS -/* block device operations structure needed for 2.3.38? and above */ static struct block_device_operations lvm_blk_dops = { open: lvm_blk_open, @@ -370,11 +355,7 @@ printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); return -EIO; } -#ifdef BLOCK_DEVICE_OPERATIONS if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) -#else - if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0) -#endif { printk("%s -- register_blkdev failed\n", lvm_name); if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) @@ -410,6 +391,7 @@ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); + blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_plug_device_noop); /* optional read root VGDA */ /* if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg); @@ -488,8 +470,6 @@ loadtime = CURRENT_TIME; - lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; - pe_lock_req.lock = UNLOCK_PE; pe_lock_req.data.lv_dev = \ pe_lock_req.data.pv_dev = \ @@ -724,8 +704,19 @@ sizeof(pv_flush_req)) != 0) return -EFAULT; - fsync_dev(pv_flush_req.pv_dev); - invalidate_buffers(pv_flush_req.pv_dev); + for ( v = 0; v < ABS_MAX_VG; v++) { + unsigned int p; + if ( vg[v] == NULL) continue; + for ( p = 0; p < vg[v]->pv_max; p++) { + if ( vg[v]->pv[p] != NULL && + strcmp ( vg[v]->pv[p]->pv_name, + pv_flush_req.pv_name) == 0) { + fsync_dev ( vg[v]->pv[p]->pv_dev); + invalidate_buffers ( vg[v]->pv[p]->pv_dev); + return 0; + } + } + } return 0; default: @@ -813,10 +804,6 @@ if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES; } -#ifdef BLOCK_DEVICE_OPERATIONS - file->f_op = &lvm_blk_fops; -#endif - /* be sure to increment VG counter */ if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; lv_ptr->lv_open++; @@ -837,34 +824,6 @@ /* - * block device read - */ -static ssize_t lvm_blk_read(struct file *file, char *buffer, - size_t size, loff_t * offset) -{ - int minor = MINOR(file->f_dentry->d_inode->i_rdev); - - read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] = - vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead; - return block_read(file, buffer, size, offset); -} - - -/* - * block device write - */ -static ssize_t lvm_blk_write(struct file *file, const char *buffer, - size_t size, loff_t * offset) -{ - int minor = MINOR(file->f_dentry->d_inode->i_rdev); - - read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] = - vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead; - return block_write(file, buffer, size, offset); -} - - -/* * block device i/o-control routine */ static int lvm_blk_ioctl(struct inode *inode, struct file *file, @@ -906,6 +865,7 @@ "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name); #endif fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); break; @@ -921,7 +881,7 @@ if ((long) arg < LVM_MIN_READ_AHEAD || (long) arg > LVM_MAX_READ_AHEAD) return -EINVAL; - lv_ptr->lv_read_ahead = (long) arg; + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = (long) arg; break; @@ -1293,7 +1253,6 @@ static int lvm_map(struct buffer_head *bh, int rw) { int minor = MINOR(bh->b_rdev); - int ret = 0; ulong index; ulong pe_start; ulong size = bh->b_size >> 9; @@ -1308,7 +1267,7 @@ printk(KERN_ALERT "%s - lvm_map: ll_rw_blk for inactive LV %s\n", lvm_name, lv->lv_name); - return -1; + goto error; } /* if ( lv->lv_access & LV_SNAPSHOT) @@ -1323,7 +1282,7 @@ (rw == WRITEA || rw == WRITE)) { printk ( "%s -- doing snapshot write for %02d:%02d[%02d:%02d] b_blocknr: %lu b_rsector: %lu\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), MAJOR ( bh->b_rdev), MINOR ( bh->b_rdev), bh->b_blocknr, bh->b_rsector); - return 0; + goto error; } if ((rw == WRITE || rw == WRITEA) && @@ -1331,7 +1290,7 @@ printk(KERN_CRIT "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", lvm_name, lv->lv_name); - return -1; + goto error; } #ifdef DEBUG_MAP printk(KERN_DEBUG @@ -1347,7 +1306,7 @@ printk(KERN_ALERT "%s - lvm_map *rsector: %lu or size: %lu wrong for" " minor: %2d\n", lvm_name, rsector_tmp, size, minor); - return -1; + goto error; } rsector_sav = rsector_tmp; rdev_sav = rdev_tmp; @@ -1444,11 +1403,11 @@ pe_start, lv_ptr)) { /* create a new mapping */ - ret = lvm_snapshot_COW(rdev_tmp, - rsector_tmp, - pe_start, - rsector_sav, - lv_ptr); + lvm_snapshot_COW(rdev_tmp, + rsector_tmp, + pe_start, + rsector_sav, + lv_ptr); } rdev_tmp = rdev_sav; rsector_tmp = rsector_sav; @@ -1467,7 +1426,11 @@ bh->b_rdev = rdev_tmp; bh->b_rsector = rsector_tmp; - return ret; + return 1; + + error: + buffer_IO_error(bh); + return -1; } /* lvm_map() */ @@ -1519,6 +1482,12 @@ return 1; } +/* + * plug device function is a noop because plugging has to happen + * in the queue of the physical blockdevice to allow the + * elevator to do a better job. + */ +static void lvm_plug_device_noop(request_queue_t *q, kdev_t dev) { } /******************************************************************** * @@ -2090,7 +2059,7 @@ lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number; vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number; - LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); vg_ptr->lv_cur++; lv_ptr->lv_status = lv_status_save; @@ -2328,7 +2297,7 @@ lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; /* vg_lv_map array doesn't have to be changed here */ - LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); lv_ptr->lv_status = lv_status_save; return 0; diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.3.99-pre9/linux/drivers/block/md.c Fri May 12 14:18:55 2000 +++ linux/drivers/block/md.c Wed May 24 18:38:26 2000 @@ -220,8 +220,7 @@ if (mddev && mddev->pers) return mddev->pers->make_request(q, mddev, rw, bh); else { - mark_buffer_clean(bh); - bh->b_end_io(bh, 0); + buffer_IO_error(bh); return -1; } } diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.3.99-pre9/linux/drivers/block/rd.c Thu May 11 15:30:06 2000 +++ linux/drivers/block/rd.c Wed May 24 17:52:43 2000 @@ -666,10 +666,12 @@ } infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos); outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos); +#if !defined(CONFIG_ARCH_S390) if (!(i % 16)) { printk("%c\b", rotator[rotate & 0x3]); rotate++; } +#endif } printk("done.\n"); kfree(buf); diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v2.3.99-pre9/linux/drivers/cdrom/aztcd.c Tue Mar 14 19:10:39 2000 +++ linux/drivers/cdrom/aztcd.c Wed May 24 19:28:05 2000 @@ -1727,7 +1727,8 @@ return -EIO; } - for (count = 0; count < AZT_TIMEOUT; count++); + for (count = 0; count < AZT_TIMEOUT; count++) + barrier(); /* Stop gcc 2.96 being smart */ if ((st=getAztStatus())==-1) { printk("aztcd: Drive Status Error Status=%x\n",st); diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.99-pre9/linux/drivers/char/Config.in Tue May 23 15:31:34 2000 +++ linux/drivers/char/Config.in Wed May 24 08:29:47 2000 @@ -157,6 +157,7 @@ tristate 'Video For Linux' CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_DEV" != "n" ]; then + bool ' V4L information in proc filesystem' CONFIG_VIDEO_PROC_FS Y dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C comment 'Radio Adapters' dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.99-pre9/linux/drivers/char/bttv.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/bttv.c Wed May 24 17:52:43 2000 @@ -276,7 +276,7 @@ void * mem; unsigned long adr, page; - mem=vmalloc(size); + mem=vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, no junk to the user */ diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/char/cpia.c linux/drivers/char/cpia.c --- v2.3.99-pre9/linux/drivers/char/cpia.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/char/cpia.c Wed May 24 17:52:43 2000 @@ -230,7 +230,7 @@ size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); - mem = vmalloc(size); + mem = vmalloc_32(size); if (!mem) return NULL; diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.3.99-pre9/linux/drivers/char/sx.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/sx.c Wed May 24 17:52:43 2000 @@ -1028,7 +1028,7 @@ if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail) c = SERIAL_XMIT_SIZE - port->gs.xmit_tail; - sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) \n", + sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%ld) \n", c, SERIAL_XMIT_SIZE- port->gs.xmit_tail); /* If for one reason or another, we can't copy more data, we're done! */ diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.3.99-pre9/linux/drivers/char/videodev.c Tue May 23 15:31:34 2000 +++ linux/drivers/char/videodev.c Wed May 24 08:29:47 2000 @@ -11,7 +11,8 @@ * * Author: Alan Cox, * - * Fixes: + * Fixes: 20000516 Claudio Matsuoka + * - Added procfs support */ #include @@ -40,6 +41,27 @@ static struct video_device *video_device[VIDEO_NUM_DEVICES]; + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + +#include + +struct videodev_proc_data { + struct list_head proc_list; + char name[16]; + struct video_device *vdev; + struct proc_dir_entry *proc_entry; + struct video_capability vcap; +}; + +static struct proc_dir_entry *video_dev_proc_entry = NULL; +struct proc_dir_entry *video_proc_entry = NULL; +EXPORT_SYMBOL(video_proc_entry); +LIST_HEAD(videodev_proc_list); + +#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ + + #ifdef CONFIG_VIDEO_BT848 extern int i2c_tuner_init(struct video_init *); #endif @@ -215,6 +237,152 @@ return -EINVAL; } +/* + * /proc support + */ + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + +/* Hmm... i'd like to see video_capability information here, but + * how can I access it (without changing the other drivers? -claudio + */ +static int videodev_proc_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *out = page; + struct video_device *vfd = data; + struct videodev_proc_data *d; + struct list_head *tmp; + int len; + char c = ' '; + + list_for_each (tmp, &videodev_proc_list) { + d = list_entry(tmp, struct videodev_proc_data, proc_list); + if (vfd == d->vdev) + break; + } + + /* Sanity check */ + if (tmp == &videodev_proc_list) + goto skip; + +#define PRINT_VID_TYPE(x) do { if (vfd->type & x) \ + out += sprintf (out, "%c%s", c, #x); c='|';} while (0) + + out += sprintf (out, "name : %s\n", vfd->name); + out += sprintf (out, "type :"); + PRINT_VID_TYPE(VID_TYPE_CAPTURE); + PRINT_VID_TYPE(VID_TYPE_TUNER); + PRINT_VID_TYPE(VID_TYPE_TELETEXT); + PRINT_VID_TYPE(VID_TYPE_OVERLAY); + PRINT_VID_TYPE(VID_TYPE_CHROMAKEY); + PRINT_VID_TYPE(VID_TYPE_CLIPPING); + PRINT_VID_TYPE(VID_TYPE_FRAMERAM); + PRINT_VID_TYPE(VID_TYPE_SCALES); + PRINT_VID_TYPE(VID_TYPE_MONOCHROME); + PRINT_VID_TYPE(VID_TYPE_SUBCAPTURE); + PRINT_VID_TYPE(VID_TYPE_MPEG_DECODER); + PRINT_VID_TYPE(VID_TYPE_MPEG_ENCODER); + PRINT_VID_TYPE(VID_TYPE_MJPEG_DECODER); + PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER); + out += sprintf (out, "\n"); + out += sprintf (out, "hardware : 0x%x\n", vfd->hardware); +#if 0 + out += sprintf (out, "channels : %d\n", d->vcap.channels); + out += sprintf (out, "audios : %d\n", d->vcap.audios); + out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth); + out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight); + out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth); + out += sprintf (out, "minheight : %d\n", d->vcap.minheight); +#endif + +skip: + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + + *start = page + off; + + return len; +} + +static void videodev_proc_create(void) +{ + video_proc_entry = create_proc_entry("video", S_IFDIR, &proc_root); + + if (video_proc_entry == NULL) { + printk("video_dev: unable to initialise /proc/video\n"); + return; + } + + video_proc_entry->owner = THIS_MODULE; + video_dev_proc_entry = create_proc_entry("dev", S_IFDIR, video_proc_entry); + + if (video_dev_proc_entry == NULL) { + printk("video_dev: unable to initialise /proc/video/dev\n"); + return; + } + + video_dev_proc_entry->owner = THIS_MODULE; +} + +static void videodev_proc_destroy(void) +{ + if (video_dev_proc_entry != NULL) + remove_proc_entry("dev", video_proc_entry); + + if (video_proc_entry != NULL) + remove_proc_entry("video", &proc_root); +} + +static void videodev_proc_create_dev (struct video_device *vfd, char *name) +{ + struct videodev_proc_data *d; + struct proc_dir_entry *p; + + if (video_dev_proc_entry == NULL) + return; + + d = kmalloc (sizeof (struct videodev_proc_data), GFP_KERNEL); + if (!d) + return; + + p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry); + p->data = vfd; + p->read_proc = videodev_proc_read; + + d->proc_entry = p; + d->vdev = vfd; + strcpy (d->name, name); + + /* How can I get capability information ? */ + + list_add (&d->proc_list, &videodev_proc_list); +} + +static void videodev_proc_destroy_dev (struct video_device *vfd) +{ + struct list_head *tmp; + struct videodev_proc_data *d; + + list_for_each (tmp, &videodev_proc_list) { + d = list_entry(tmp, struct videodev_proc_data, proc_list); + if (vfd == d->vdev) { + remove_proc_entry(d->name, video_dev_proc_entry); + list_del (&d->proc_list); + kfree (d); + break; + } + } +} + +#endif /* CONFIG_VIDEO_PROC_FS */ + extern struct file_operations video_fops; /** @@ -306,6 +474,13 @@ VIDEO_MAJOR, vfd->minor, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &video_fops, NULL); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + sprintf (name, "%s%d", name_base, i - base); + videodev_proc_create_dev (vfd, name); +#endif + + return 0; } } @@ -324,6 +499,11 @@ { if(video_device[vfd->minor]!=vfd) panic("vfd: bad unregister"); + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + videodev_proc_destroy_dev (vfd); +#endif + devfs_unregister (vfd->devfs_handle); video_device[vfd->minor]=NULL; MOD_DEC_USE_COUNT; @@ -361,6 +541,10 @@ * Init kernel installed video drivers */ +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + videodev_proc_create (); +#endif + while(vfli->init!=NULL) { vfli->init(vfli); @@ -377,6 +561,10 @@ void cleanup_module(void) { +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + videodev_proc_destroy (); +#endif + devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture"); } diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c --- v2.3.99-pre9/linux/drivers/i2o/i2o_core.c Thu May 11 15:30:07 2000 +++ linux/drivers/i2o/i2o_core.c Wed May 24 17:52:43 2000 @@ -189,7 +189,7 @@ * I2O configuration spinlock. This isnt a big deal for contention * so we have one only */ -static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED; +static struct semaphore i2o_configuration_lock; /* * Event spinlock. Used to keep event queue sane and from @@ -215,7 +215,7 @@ /* * I2O Core reply handler */ -void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, +static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) { u32 *msg=(u32 *)m; @@ -297,29 +297,44 @@ return; } -/* +/** + * i2o_install_handler - install a message handler + * @h: Handler structure + * * Install an I2O handler - these handle the asynchronous messaging - * from the card once it has initialised. + * from the card once it has initialised. If the table of handlers is + * full then -ENOSPC is returned. On a success 0 is returned and the + * context field is set by the function. The structure is part of the + * system from this time onwards. It must not be freed until it has + * been uninstalled */ int i2o_install_handler(struct i2o_handler *h) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); for(i=0;icontext = i; i2o_handlers[i]=h; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } } - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -ENOSPC; } +/** + * i2o_remove_handler - remove an i2o message handler + * @h: handler + * + * Remove a message handler previously installed with i2o_install_handler. + * After this function returns the handler object can be freed or re-used + */ + int i2o_remove_handler(struct i2o_handler *h) { i2o_handlers[h->context]=NULL; @@ -332,12 +347,24 @@ * Each device has a pointer to it's LCT entry to be used * for fun purposes. */ + +/** + * i2o_install_device - attach a device to a controller + * @c: controller + * @d: device + * + * Add a new device to an i2o controller. This can be called from + * non interrupt contexts only. It adds the device and marks it as + * unclaimed. The device memory becomes part of the kernel and must + * be uninstalled before being freed or reused. Zero is returned + * on success. + */ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); d->controller=c; d->owner=NULL; d->next=c->devices; @@ -347,7 +374,7 @@ for(i = 0; i < I2O_MAX_MANAGERS; i++) d->managers[i] = NULL; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } @@ -411,11 +438,22 @@ return -EINVAL; } +/** + * i2o_delete_device - remove an i2o device + * @d: device to remove + * + * This function unhooks a device from a controller. The device + * will not be unhooked if it has an owner who does not wish to free + * it, or if the owner lacks a dev_del_notify function. In that case + * -EBUSY is returned. On success 0 is returned. Other errors cause + * negative errno values to be returned + */ + int i2o_delete_device(struct i2o_device *d) { int ret; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); /* * Seek, locate @@ -423,23 +461,37 @@ ret = __i2o_delete_device(d); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return ret; } -/* - * Add and remove controllers from the I2O controller list +/** + * i2o_install_controller - attach a controller + * @c: controller + * + * Add a new controller to the i2o layer. This can be called from + * non interrupt contexts only. It adds the controller and marks it as + * unused with no devices. If the tables are full or memory allocations + * fail then a negative errno code is returned. On success zero is + * returned and the controller is bound to the system. The structure + * must not be freed or reused until being uninstalled. */ int i2o_install_controller(struct i2o_controller *c) { int i; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); for(i=0;idlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); + if(c->dlct==NULL) + { + up(&i2o_configuration_lock); + return -ENOMEM; + } i2o_controllers[i]=c; c->devices = NULL; c->next=i2o_controller_chain; @@ -448,20 +500,28 @@ c->page_frame = NULL; c->hrt = NULL; c->lct = NULL; - c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); c->status_block = NULL; sprintf(c->name, "i2o/iop%d", i); i2o_num_controllers++; init_MUTEX_LOCKED(&c->lct_sem); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } } printk(KERN_ERR "No free i2o controller slots.\n"); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } +/** + * i2o_delete_controller - delete a controller + * @c: controller + * + * Remove an i2o controller from the system. If the controller or its + * devices are busy then -EBUSY is returned. On a failure a negative + * errno code is returned. On success zero is returned. + */ + int i2o_delete_controller(struct i2o_controller *c) { struct i2o_controller **p; @@ -477,12 +537,12 @@ if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) i2o_event_register(c, core_context, 0, 0, 0); - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if((users=atomic_read(&c->users))) { dprintk(KERN_INFO "I2O: %d users for controller %s\n", users, c->name); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } while(c->devices) @@ -491,7 +551,7 @@ { /* Shouldnt happen */ c->bus_disable(c); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } } @@ -528,7 +588,7 @@ c->destructor(c); *p=c->next; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); if(c->page_frame) kfree(c->page_frame); @@ -551,16 +611,33 @@ } p=&((*p)->next); } - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); return -ENOENT; } +/** + * i2o_unlock_controller - unlock a controller + * @c: controller to unlock + * + * Take a lock on an i2o controller. This prevents it being deleted. + * i2o controllers are not refcounted so a deletion of an in use device + * will fail, not take affect on the last dereference. + */ + void i2o_unlock_controller(struct i2o_controller *c) { atomic_dec(&c->users); } +/** + * i2o_find_controller - return a locked controller + * @n: controller number + * + * Returns a pointer to the controller object. The controller is locked + * on return. NULL is returned if the controller is not found. + */ + struct i2o_controller *i2o_find_controller(int n) { struct i2o_controller *c; @@ -568,17 +645,28 @@ if(n<0 || n>=MAX_I2O_CONTROLLERS) return NULL; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); c=i2o_controllers[n]; if(c!=NULL) atomic_inc(&c->users); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return c; } -/* - * Issue UTIL_CLAIM or UTIL_RELEASE message +/** + * i2o_issue_claim - claim or release a device + * @cmd: command + * @c: controller to claim for + * @tid: i2o task id + * @type: type of claim + * + * Issue I2O UTIL_CLAIM and UTIL_RELEASE messages. The message to be sent + * is set by cmd. The tid is the task id of the object to claim and the + * type is the claim type (see the i2o standard) + * + * Zero is returned on success. */ + static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type) { u32 msg[5]; @@ -592,54 +680,70 @@ } /* - * Claim a device for use by an OSM + * i2o_claim_device - claim a device for use by an OSM + * @d: device to claim + * @h: handler for this device + * + * Do the leg work to assign a device to a given OSM on Linux. The + * kernel updates the internal handler data for the device and then + * performs an I2O claim for the device, attempting to claim the + * device as primary. If the attempt fails a negative errno code + * is returned. On success zero is returned. */ + int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h) { - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if (d->owner) { printk(KERN_INFO "Device claim called, but dev allready owned by %s!", h->name); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } + d->owner=h; if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, I2O_CLAIM_PRIMARY)) { - spin_unlock(&i2o_configuration_lock); + d->owner = NULL; return -EBUSY; } - - d->owner=h; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } -/* - * Release a device that the OSM is using +/** + * i2o_release_device - release a device that the OSM is using + * @d: device to claim + * @h: handler for this device + * + * Drop a claim by an OSM on a given I2O device. The handler is cleared + * and 0 is returned on success. + * */ + int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) { int err = 0; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if (d->owner != h) { printk(KERN_INFO "Claim release called, but not owned by %s!", h->name); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -ENOENT; } + d->owner = NULL; + if(i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) { err = -ENXIO; + d->owner = h; } - d->owner = NULL; - - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return err; } @@ -994,7 +1098,10 @@ return 0; } -/* +/** + * i2o_run_queue - process pending events on a controller + * @c: controller to process + * * This is called by the bus specific driver layer when an interrupt * or poll of this card interface is desired. */ @@ -1046,9 +1153,13 @@ } -/* - * Do i2o class name lookup +/** + * i2o_get_class_name - do i2o class name lookup + * @class: class number + * + * Return a descriptive string for an i2o class */ + const char *i2o_get_class_name(int class) { int idx = 16; @@ -1112,8 +1223,18 @@ } -/* - * Wait up to 5 seconds for a message slot to be available. +/** + * i2o_wait_message + * @c: controller + * @why: explanation + * + * This function waits up to 5 seconds for a message slot to be + * available. If no message is available it prints an error message + * that is expected to be what the message will be used for (eg + * "get_status"). 0xFFFFFFFF is returned on a failure. + * + * On a success the message is returned. This is the physical page + * frame offset address from the read port. (See the i2o spec) */ u32 i2o_wait_message(struct i2o_controller *c, char *why) @@ -1134,8 +1255,14 @@ return m; } -/* - * Dump the information block associated with a given unit (TID) +/** + * i2o_report_controller_unit - print information about a tid + * @c: controller + * @d: device + * + * Dump an information block associated with a given unit (TID). The + * tables are read and a block of text is output to printk that is + * formatted intended for the user. */ void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) @@ -1341,10 +1468,14 @@ } -/* - * Quiesce IOP. Causes IOP to make external operation quiescend. - * Internal operation of the IOP continues normally. +/** + * i2o_quiesce_controller - quiesce controller + * @c: controller + * + * Quiesce an IOP. Causes IOP to make external operation quiescent + * (i2o 'READY' state). Internal operation of the IOP continues normally. */ + int i2o_quiesce_controller(struct i2o_controller *c) { u32 msg[4]; @@ -1373,14 +1504,18 @@ dprintk(KERN_INFO "%s: Quiesced.\n", c->name); i2o_status_get(c); // Entered READY state - - return ret; - + return ret; } -/* - * Enable IOP. Allows the IOP to resume external operations. +/** + * i2o_enable_controller - move controller from ready to operational + * @c: controller + * + * Enable IOP. This allows the IOP to resume external operations and + * reverses the effect of a quiesce. In the event of an error a negative + * errno code is returned. */ + int i2o_enable_controller(struct i2o_controller *c) { u32 msg[4]; @@ -1395,7 +1530,7 @@ msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; - /* How long of a timeout do we need? */ + /* How long of a timeout do we need? */ if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) printk(KERN_ERR "%s: Could not enable (status=%#x).\n", @@ -1408,12 +1543,16 @@ return ret; } -/* - * Clear an IOP to HOLD state, ie. terminate external operations, clear all - * input queues and prepare for a system restart. IOP's internal operation - * continues normally and the outbound queue is alive. - * IOP is not expected to rebuild its LCT. +/** + * i2o_clear_controller - clear a controller + * @c: controller + * + * Clear an IOP to HOLD state, ie. terminate external operations, clear all + * input queues and prepare for a system restart. IOP's internal operation + * continues normally and the outbound queue is alive. + * The IOP is not expected to rebuild its LCT. */ + int i2o_clear_controller(struct i2o_controller *c) { struct i2o_controller *iop; @@ -1447,12 +1586,16 @@ } -/* - * Reset the IOP into INIT state and wait until IOP gets into RESET state. - * Terminate all external operations, clear IOP's inbound and outbound - * queues, terminate all DDMs, and reload the IOP's operating environment - * and all local DDMs. IOP rebuilds its LCT. +/** + * i2o_reset_controller + * @c: controller to reset + * + * Reset the IOP into INIT state and wait until IOP gets into RESET state. + * Terminate all external operations, clear IOP's inbound and outbound + * queues, terminate all DDMs, and reload the IOP's operating environment + * and all local DDMs. The IOP rebuilds its LCT. */ + static int i2o_reset_controller(struct i2o_controller *c) { struct i2o_controller *iop; @@ -1556,9 +1699,16 @@ } -/* - * Get the status block for the IOP +/** + * i2o_status_get - get the status block for the IOP + * @c: controller + * + * Issue a status query on the controller. This updates the + * attached status_block. If the controller fails to reply or an + * error occurs then a negative errno code is returned. On success + * zero is returned and the status_blok is updated. */ + int i2o_status_get(struct i2o_controller *c) { long time; @@ -1743,7 +1893,7 @@ /* * Initialize I2O subsystem. */ -static void __init i2o_sys_init() +static void __init i2o_sys_init(void) { struct i2o_controller *iop, *niop = NULL; @@ -1806,9 +1956,13 @@ } } -/* - * Shutdown I2O system +/** + * i2o_sys_shutdown - shutdown I2O system + * + * Bring down each i2o controller and then return. Each controller + * is taken through an orderly shutdown */ + static void i2o_sys_shutdown(void) { struct i2o_controller *iop, *niop; @@ -1822,9 +1976,16 @@ } } -/* - * Bring an I2O controller into HOLD state. See the spec. +/** + * i2o_activate_controller - bring controller up to HOLD + * @iop: controller + * + * This function brings an I2O controller into HOLD state. The adapter + * is reset if neccessary and then the queues and resource table + * are read. -1 is returned on a failure, 0 on success. + * */ + int i2o_activate_controller(struct i2o_controller *iop) { /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ @@ -1872,9 +2033,14 @@ } -/* - * Clear and (re)initialize IOP's outbound queue +/** + * i2o_init_outbound_queue - setup the outbound queue + * @c: controller + * + * Clear and (re)initialize IOP's outbound queue. Returns 0 on + * success or a negative errno code on a failure. */ + int i2o_init_outbound_q(struct i2o_controller *c) { u8 *status; @@ -1938,6 +2104,15 @@ return 0; } +/** + * i2o_post_outbound_messages - fill message queue + * @c: controller + * + * Allocate a message frame and load the messages into the IOP. The + * function returns zero on success or a negative errno code on + * failure. + */ + int i2o_post_outbound_messages(struct i2o_controller *c) { int i; @@ -3071,6 +3246,9 @@ int __init i2o_init(void) { printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n"); + + init_MUTEX(&i2o_configuration_lock); + if (i2o_install_handler(&i2o_core_handler) < 0) { printk(KERN_ERR diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/Config.in linux/drivers/ide/Config.in --- v2.3.99-pre9/linux/drivers/ide/Config.in Tue May 23 15:31:34 2000 +++ linux/drivers/ide/Config.in Wed May 24 08:40:41 2000 @@ -41,7 +41,6 @@ bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD dep_bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI - define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL $CONFIG_EXPERIMENTAL dep_bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP dep_bool ' AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI @@ -82,12 +81,14 @@ dep_bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC $CONFIG_BLK_DEV_IDE_PMAC dep_bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC + define_bool CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_BLK_DEV_IDEDMA_PMAC fi if [ "$CONFIG_ARCH_ACORN" = "y" ]; then dep_bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_ARCH_ACORN dep_bool ' ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS $CONFIG_BLK_DEV_IDE_ICSIDE dep_bool ' Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO $CONFIG_BLK_DEV_IDEDMA_ICS define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_ICS + define_bool CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_BLK_DEV_IDEDMA_ICS dep_bool ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_ARCH_ACORN fi if [ "$CONFIG_AMIGA" = "y" ]; then diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/Makefile linux/drivers/ide/Makefile --- v2.3.99-pre9/linux/drivers/ide/Makefile Wed Apr 26 16:34:07 2000 +++ linux/drivers/ide/Makefile Wed May 24 08:40:41 2000 @@ -97,7 +97,7 @@ IDE_OBJS += icside.o endif -ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) +ifeq ($(CONFIG_BLK_DEV_IDEDMA_PCI),y) IDE_OBJS += ide-dma.o endif diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/hd.c linux/drivers/ide/hd.c --- v2.3.99-pre9/linux/drivers/ide/hd.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/hd.c Wed May 24 08:40:41 2000 @@ -778,6 +778,8 @@ #endif for (drive=0 ; drive < NR_HD ; drive++) { + hd[drive<<6].nr_sects = hd_info[drive].head * + hd_info[drive].sect * hd_info[drive].cyl; printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a', hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl, hd_info[drive].head, hd_info[drive].sect); @@ -890,3 +892,4 @@ return 0; } __setup("hd=", parse_hd_setup); + diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c --- v2.3.99-pre9/linux/drivers/ide/ide-features.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/ide-features.c Wed May 24 14:40:19 2000 @@ -12,6 +12,7 @@ * May be copied or modified under the terms of the GNU General Public License */ +#include #define __NO_VERSION__ #include #include @@ -257,11 +258,12 @@ { ide_hwif_t *hwif = HWIF(drive); int i, error = 1; - byte unit = (drive->select.b.unit & 0x01); byte stat; +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI + 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_PCI */ /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, @@ -324,11 +326,13 @@ drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI 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_PCI */ switch(speed) { case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break; diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/ide-geometry.c linux/drivers/ide/ide-geometry.c --- v2.3.99-pre9/linux/drivers/ide/ide-geometry.c Mon Mar 27 08:08:24 2000 +++ linux/drivers/ide/ide-geometry.c Wed May 24 08:40:41 2000 @@ -3,7 +3,7 @@ */ #include -#ifdef CONFIG_IDE +#if defined(CONFIG_IDE) && !defined(CONFIG_BLK_DEV_HD) #include #include @@ -211,4 +211,4 @@ drive->bios_cyl, drive->bios_head, drive->bios_sect); return ret; } -#endif /* CONFIG_IDE */ +#endif /* (CONFIG_IDE) && !(CONFIG_BLK_DEV_HD) */ diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/ide-pnp.c linux/drivers/ide/ide-pnp.c --- v2.3.99-pre9/linux/drivers/ide/ide-pnp.c Wed Apr 26 16:34:07 2000 +++ linux/drivers/ide/ide-pnp.c Wed May 24 18:38:26 2000 @@ -100,7 +100,7 @@ /* * Probe for ISA PnP IDE interfaces. */ -void pnpide_init(int enable) +void __init pnpide_init(int enable) { struct pci_dev *dev = NULL; struct pnp_dev_t *dev_type; diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c --- v2.3.99-pre9/linux/drivers/ide/ide-probe.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/ide-probe.c Wed May 24 08:40:41 2000 @@ -425,10 +425,10 @@ if (hwif->io_ports[IDE_CONTROL_OFFSET]) region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); - +#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (hwif->io_ports[IDE_IRQ_OFFSET]) region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); - +#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ /* * If any errors are return, we drop the hwif interface. */ @@ -437,8 +437,8 @@ static void hwif_register (ide_hwif_t *hwif) { - if ((hwif->io_ports[IDE_DATA_OFFSET] | 7) == - (hwif->io_ports[IDE_STATUS_OFFSET])) { + if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) == + ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) { ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name); hwif->straight8 = 1; goto jump_straight8; @@ -464,8 +464,10 @@ jump_straight8: if (hwif->io_ports[IDE_CONTROL_OFFSET]) ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name); +#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (hwif->io_ports[IDE_IRQ_OFFSET]) ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name); +#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ } /* diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c --- v2.3.99-pre9/linux/drivers/ide/ide-tape.c Thu May 11 15:30:07 2000 +++ linux/drivers/ide/ide-tape.c Wed May 24 08:40:41 2000 @@ -3912,8 +3912,12 @@ #endif clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); position = idetape_read_position(drive); - printk(KERN_INFO "ide-tape: %s: blank block detected, positioning tape to block %d\n", tape->name, position + 60); - idetape_position_tape(drive, position + 60, 0, 1); + if (position >= 2980 && position < 3000) + position = 3000; + else + position += 60; + printk(KERN_INFO "ide-tape: %s: blank block detected, positioning tape to block %d\n", tape->name, position); + idetape_position_tape(drive, position, 0, 1); cnt += 40; continue; } else diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.3.99-pre9/linux/drivers/ide/ide.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/ide.c Wed May 24 08:40:41 2000 @@ -824,7 +824,7 @@ if (drive->media == ide_disk) { printk(" { "); if (err & ABRT_ERR) printk("DriveStatusError "); - if (err & ICRC_ERR) printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); + 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 "); @@ -1896,8 +1896,10 @@ jump_eight: if (hwif->io_ports[IDE_CONTROL_OFFSET]) ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); +#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (hwif->io_ports[IDE_IRQ_OFFSET]) ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); +#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ } void ide_unregister (unsigned int index) @@ -2006,12 +2008,12 @@ else hwgroup->hwif = HWIF(hwgroup->drive); -#ifdef CONFIG_BLK_DEV_IDEDMA +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI if (hwif->dma_base) { (void) ide_release_dma(hwif); hwif->dma_base = 0; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ /* * Remove us from the kernel's knowledge @@ -2087,9 +2089,11 @@ case IDE_CONTROL_OFFSET: hw->io_ports[i] = ctrl; break; +#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) case IDE_IRQ_OFFSET: hw->io_ports[i] = intr; break; +#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ default: hw->io_ports[i] = 0; break; @@ -2552,8 +2556,6 @@ if ((HWIF(drive)->speedproc) != NULL) HWIF(drive)->speedproc(drive, xfer_rate); ide_driveid_update(drive); - } else { - printk("%s: \n", drive->name); } abort: if (copy_to_user((void *)arg, argbuf, argsize)) @@ -3617,10 +3619,10 @@ for (index = 0; index < MAX_HWIFS; ++index) { ide_unregister(index); -#ifdef CONFIG_BLK_DEV_IDEDMA +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI if (ide_hwifs[index].dma_base) (void) ide_release_dma(&ide_hwifs[index]); -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ } #ifdef CONFIG_PROC_FS diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/piix.c linux/drivers/ide/piix.c --- v2.3.99-pre9/linux/drivers/ide/piix.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/piix.c Wed May 24 08:40:41 2000 @@ -86,7 +86,7 @@ u32 bibma = bmide_dev->resource[4].start; u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0; u8 c0 = 0, c1 = 0; - u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0; + u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0; pci_read_config_word(bmide_dev, 0x40, ®40); pci_read_config_word(bmide_dev, 0x42, ®42); @@ -95,6 +95,7 @@ pci_read_config_byte(bmide_dev, 0x4a, ®4a); pci_read_config_byte(bmide_dev, 0x4b, ®4b); pci_read_config_byte(bmide_dev, 0x54, ®54); + pci_read_config_byte(bmide_dev, 0x55, ®55); psitre = (reg40 & 0x4000) ? 1 : 0; ssitre = (reg42 & 0x4000) ? 1 : 0; @@ -264,13 +265,15 @@ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; byte maslave = hwif->channel ? 0x42 : 0x40; - int a_speed = 2 << (drive->dn * 4); + int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; - int v_flag = 0x10 << 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; pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; @@ -278,6 +281,7 @@ pci_read_config_word(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); pci_read_config_word(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); switch(speed) { case XFER_UDMA_4: @@ -294,6 +298,7 @@ if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_word(dev, 0x48, reg48|u_flag); + pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag); if (!(reg4a & u_speed)) { pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); pci_write_config_word(dev, 0x4a, reg4a|u_speed); @@ -313,6 +318,8 @@ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); if (reg54 & v_flag) pci_write_config_word(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag); } piix_tune_drive(drive, piix_dma_2_pio(speed)); @@ -404,10 +411,11 @@ unsigned int __init ata66_piix (ide_hwif_t *hwif) { byte reg54h = 0, reg55h = 0, ata66 = 0; - byte mask = hwif->channel ? 0x0c : 0x03; + byte mask = hwif->channel ? 0xc0 : 0x30; pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); + ata66 = (reg54h & mask) ? 1 : 0; return ata66; @@ -415,8 +423,10 @@ void __init ide_init_piix (ide_hwif_t *hwif) { +#ifndef CONFIG_IA64 if (!hwif->irq) hwif->irq = hwif->channel ? 15 : 14; +#endif /* CONFIG_IA64 */ hwif->tuneproc = &piix_tune_drive; hwif->drives[0].autotune = 1; diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c --- v2.3.99-pre9/linux/drivers/ide/via82cxxx.c Tue May 23 15:31:34 2000 +++ linux/drivers/ide/via82cxxx.c Wed May 24 08:40:41 2000 @@ -243,7 +243,7 @@ #define arraysize(x) (sizeof(x)/sizeof(*(x))) -#define DISPLAY_VIA_TIMINGS +#undef DISPLAY_VIA_TIMINGS #if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) #include @@ -657,6 +657,7 @@ struct pci_dev *dev = hwif->pci_dev; struct chipset_bus_clock_list_entry * temp_table = NULL; + byte unit = (drive->select.b.unit & 0x01) ? 1 : 0; byte ata2_pci = 0x00; byte ata3_pci = 0x00; byte timing = 0x00; @@ -677,7 +678,9 @@ return -1; } - if ((via82cxxx_table == via82cxxx_type_four) && (speed <= XFER_UDMA_2)) { + if ((via82cxxx_table == via82cxxx_type_four) && + (!(hwif->udma_four)) && + (speed <= XFER_UDMA_2)) { temp_table = via82cxxx_type_three; } else { temp_table = via82cxxx_table; @@ -689,6 +692,8 @@ pci_read_config_byte(dev, ata3_pci, &ultra); ultra = pci_bus_clock_list_ultra(speed, bus_speed, temp_table); + if ((unit) && (hwif->udma_four)) + ultra |= 0x04; pci_write_config_byte(dev, ata3_pci, ultra); if (!drive->init_speed) diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.3.99-pre9/linux/drivers/net/dgrs.c Thu May 11 15:30:07 2000 +++ linux/drivers/net/dgrs.c Wed May 24 19:28:05 2000 @@ -1092,6 +1092,7 @@ for (i = jiffies + 8 * HZ; time_after(i, jiffies); ) { + barrier(); /* Gcc 2.95 needs this */ if (priv0->bcomm->bc_status >= BC_RUN) break; } diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.3.99-pre9/linux/drivers/pci/pci.ids Tue May 23 15:31:35 2000 +++ linux/drivers/pci/pci.ids Wed May 24 17:52:52 2000 @@ -2932,7 +2932,10 @@ 1277 Comstream 1278 Transtech Parallel Systems Ltd. 1279 Transmeta Corporation - 0295 Virtual Northbridge + 0295 Northbridge + 0395 LongRun Northbridge + 0396 SDRAM controller + 0397 BIOS scratchpad 127a Rockwell International 1002 HCF 56k V90 FaxModem 127a 1002 HCF 56k V90 Modem diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.3.99-pre9/linux/drivers/sound/es1370.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/es1370.c Wed May 24 11:22:16 2000 @@ -2455,9 +2455,8 @@ { SOUND_MIXER_WRITE_OGAIN, 0x4040 } }; -#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ - ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) -#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) +#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ + pci_resource_flags((dev), (num)) & IORESOURCE_IO) static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { @@ -2488,7 +2487,7 @@ spin_lock_init(&s->lock); s->magic = ES1370_MAGIC; s->dev = pcidev; - s->io = RSRCADDRESS(pcidev, 0); + s->io = pci_resource_start(pcidev, 0); s->irq = pcidev->irq; if (!request_region(s->io, ES1370_EXTENT, "es1370")) { printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); @@ -2616,12 +2615,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; printk(KERN_INFO "es1370: version v0.33 time " __TIME__ " " __DATE__ "\n"); - if (!pci_register_driver(&es1370_driver)) { - pci_unregister_driver(&es1370_driver); - return -ENODEV; - } - return 0; - + return pci_module_init(&es1370_driver); } static void __exit cleanup_es1370(void) diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.3.99-pre9/linux/drivers/sound/es1371.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/es1371.c Wed May 24 11:22:16 2000 @@ -100,6 +100,8 @@ * Tim Janik's BSE (Bedevilled Sound Engine) found this * 07.02.2000 0.24 Use pci_alloc_consistent and pci_register_driver * 07.02.2000 0.25 Use ac97_codec + * 01.03.2000 0.26 SPDIF patch by Mikael Bouillot + * Use pci_module_init */ /*****************************************************************************/ @@ -205,6 +207,7 @@ static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; +#define CTRL_RECEN_B 0x08000000 /* 1 = don't mix analog in to digital out */ #define CTRL_SPDIFEN_B 0x04000000 #define CTRL_JOY_SHIFT 24 #define CTRL_JOY_MASK 3 @@ -344,22 +347,6 @@ #define SCTRL_P1FMT 0x00000003 /* format mask */ #define SCTRL_SH_P1FMT 0 -/* codec constants */ - -#define CODEC_ID_DEDICATEDMIC 0x001 -#define CODEC_ID_MODEMCODEC 0x002 -#define CODEC_ID_BASSTREBLE 0x004 -#define CODEC_ID_SIMULATEDSTEREO 0x008 -#define CODEC_ID_HEADPHONEOUT 0x010 -#define CODEC_ID_LOUDNESS 0x020 -#define CODEC_ID_18BITDAC 0x040 -#define CODEC_ID_20BITDAC 0x080 -#define CODEC_ID_18BITADC 0x100 -#define CODEC_ID_20BITADC 0x200 - -#define CODEC_ID_SESHIFT 10 -#define CODEC_ID_SEMASK 0x1f - /* misc stuff */ #define POLL_COUNT 0x1000 @@ -405,6 +392,9 @@ u16 device; u8 rev; /* the chip revision */ + /* options */ + int spdif_volume; /* S/PDIF output is enabled if != -1 */ + #ifdef ES1371_DEBUG /* debug /proc entry */ struct proc_dir_entry *ps; @@ -1135,6 +1125,67 @@ /* --------------------------------------------------------------------- */ +/* Conversion table for S/PDIF PCM volume emulation through the SRC */ +/* dB-linear table of DAC vol values; -0dB to -46.5dB with mute */ +static const unsigned short DACVolTable[101] = +{ + 0x1000, 0x0f2a, 0x0e60, 0x0da0, 0x0cea, 0x0c3e, 0x0b9a, 0x0aff, + 0x0a6d, 0x09e1, 0x095e, 0x08e1, 0x086a, 0x07fa, 0x078f, 0x072a, + 0x06cb, 0x0670, 0x061a, 0x05c9, 0x057b, 0x0532, 0x04ed, 0x04ab, + 0x046d, 0x0432, 0x03fa, 0x03c5, 0x0392, 0x0363, 0x0335, 0x030b, + 0x02e2, 0x02bc, 0x0297, 0x0275, 0x0254, 0x0235, 0x0217, 0x01fb, + 0x01e1, 0x01c8, 0x01b0, 0x0199, 0x0184, 0x0170, 0x015d, 0x014b, + 0x0139, 0x0129, 0x0119, 0x010b, 0x00fd, 0x00f0, 0x00e3, 0x00d7, + 0x00cc, 0x00c1, 0x00b7, 0x00ae, 0x00a5, 0x009c, 0x0094, 0x008c, + 0x0085, 0x007e, 0x0077, 0x0071, 0x006b, 0x0066, 0x0060, 0x005b, + 0x0057, 0x0052, 0x004e, 0x004a, 0x0046, 0x0042, 0x003f, 0x003c, + 0x0038, 0x0036, 0x0033, 0x0030, 0x002e, 0x002b, 0x0029, 0x0027, + 0x0025, 0x0023, 0x0021, 0x001f, 0x001e, 0x001c, 0x001b, 0x0019, + 0x0018, 0x0017, 0x0016, 0x0014, 0x0000 +}; + +/* + * when we are in S/PDIF mode, we want to disable any analog output so + * we filter the mixer ioctls + */ +static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg) +{ + struct es1371_state *s = (struct es1371_state *)codec->private_data; + int val; + unsigned long flags; + unsigned int left, right; + + VALIDATE_STATE(s); + /* filter mixer ioctls to catch PCM and MASTER volume when in S/PDIF mode */ + if (s->spdif_volume == -1) + return codec->mixer_ioctl(codec, cmd, arg); + switch (cmd) { + case SOUND_MIXER_WRITE_VOLUME: + return 0; + + case SOUND_MIXER_WRITE_PCM: /* use SRC for PCM volume */ + get_user_ret(val, (int *)arg, -EFAULT); + right = ((val >> 8) & 0xff); + left = (val & 0xff); + if (right > 100) + right = 100; + if (left > 100) + left = 100; + s->spdif_volume = (right << 8) | left; + spin_lock_irqsave(&s->lock, flags); + src_write(s, SRCREG_VOL_DAC2, DACVolTable[100 - left]); + src_write(s, SRCREG_VOL_DAC2+1, DACVolTable[100 - right]); + spin_unlock_irqrestore(&s->lock, flags); + return 0; + + case SOUND_MIXER_READ_PCM: + return put_user(s->spdif_volume, (int *)arg); + } + return codec->mixer_ioctl(codec, cmd, arg); +} + +/* --------------------------------------------------------------------- */ + /* * AC97 Mixer Register to Connections mapping of the Concert 97 board * @@ -1180,8 +1231,10 @@ static int es1371_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct ac97_codec *codec = &((struct es1371_state *)file->private_data)->codec; - return codec->mixer_ioctl(codec, cmd, arg); + struct es1371_state *s = (struct es1371_state *)file->private_data; + struct ac97_codec *codec = &s->codec; + + return mixdev_ioctl(codec, cmd, arg); } static /*const*/ struct file_operations es1371_mixer_fops = { @@ -1778,7 +1831,7 @@ return -EINVAL; } - return s->codec.mixer_ioctl(&s->codec, cmd, arg); + return mixdev_ioctl(&s->codec, cmd, arg); } static int es1371_open(struct inode *inode, struct file *file) @@ -2181,7 +2234,7 @@ return -EINVAL; } - return s->codec.mixer_ioctl(&s->codec, cmd, arg); + return mixdev_ioctl(&s->codec, cmd, arg); } static int es1371_open_dac(struct inode *inode, struct file *file) @@ -2581,6 +2634,7 @@ static int joystick[NR_DEVICE] = { 0, }; static int spdif[NR_DEVICE] = { 0, }; +static int nomix[NR_DEVICE] = { 0, }; static unsigned int devindex = 0; @@ -2588,6 +2642,8 @@ MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)"); MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i"); MODULE_PARM_DESC(spdif, "if 1 the output is in S/PDIF digital mode"); +MODULE_PARM(nomix, "1-" __MODULE_STRING(NR_DEVICE) "i"); +MODULE_PARM_DESC(nomix, "if 1 no analog audio is mixed to the digital output"); MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("ES1371 AudioPCI97 Driver"); @@ -2613,9 +2669,8 @@ { SOUND_MIXER_WRITE_IGAIN, 0x4040 } }; -#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ - ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) -#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) +#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ + (pci_resource_flags((dev), (num)) & IORESOURCE_IO)) static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { @@ -2649,7 +2704,7 @@ spin_lock_init(&s->lock); s->magic = ES1371_MAGIC; s->dev = pcidev; - s->io = RSRCADDRESS(pcidev, 0); + s->io = pci_resource_start(pcidev, 0); s->irq = pcidev->irq; s->vendor = pcidev->vendor; s->device = pcidev->device; @@ -2688,6 +2743,10 @@ /* initialize codec registers */ s->ctrl = 0; + if (pcidev->subsystem_vendor == 0x107b && pcidev->subsystem_device == 0x2150) { + s->ctrl |= CTRL_GPIO_OUT0; + printk(KERN_INFO PFX "Running On Gateway 2000 Solo 2510 - Amp On \n"); + } if ((joystick[devindex] & ~0x18) == 0x200) { if (check_region(joystick[devindex], JOY_EXTENT)) printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]); @@ -2697,12 +2756,16 @@ } s->sctrl = 0; cssr = 0; + s->spdif_volume = -1; /* check to see if s/pdif mode is being requested */ if (spdif[devindex]) { if (s->rev >= 4) { printk(KERN_INFO PFX "enabling S/PDIF output\n"); + s->spdif_volume = 0; cssr |= STAT_EN_SPDIF; s->ctrl |= CTRL_SPDIFEN_B; + if (nomix[devindex]) /* don't mix analog inputs to s/pdif output */ + s->ctrl |= CTRL_RECEN_B; } else { printk(KERN_ERR PFX "revision %d does not support S/PDIF\n", s->rev); } @@ -2742,10 +2805,16 @@ fs = get_fs(); set_fs(KERNEL_DS); val = SOUND_MASK_LINE; - s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); + mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { val = initvol[i].vol; - s->codec.mixer_ioctl(&s->codec, initvol[i].mixch, (unsigned long)&val); + mixdev_ioctl(&s->codec, initvol[i].mixch, (unsigned long)&val); + } + /* mute master and PCM when in S/PDIF mode */ + if (s->spdif_volume != -1) { + val = 0x0000; + s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_VOLUME, (unsigned long)&val); + s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_PCM, (unsigned long)&val); } set_fs(fs); /* turn on S/PDIF output driver if requested */ @@ -2820,12 +2889,8 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.25 time " __TIME__ " " __DATE__ "\n"); - if (!pci_register_driver(&es1371_driver)) { - pci_unregister_driver(&es1371_driver); - return -ENODEV; - } - return 0; + printk(KERN_INFO PFX "version v0.26 time " __TIME__ " " __DATE__ "\n"); + return pci_module_init(&es1371_driver); } static void __exit cleanup_es1371(void) diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.3.99-pre9/linux/drivers/sound/esssolo1.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/esssolo1.c Wed May 24 11:22:16 2000 @@ -68,6 +68,7 @@ * Integrated (aka redid 8-)) APM support patch by Zach Brown * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled + * 13.03.2000 0.15 Reintroduce initialization of a couple of PCI config space registers */ /*****************************************************************************/ @@ -2130,6 +2131,14 @@ mm_segment_t fs; int i, val; + /* initialize DDMA base address */ + printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase); + pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1); + /* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */ + pci_write_config_dword(pcidev, 0x50, 0); + /* disable legacy audio address decode */ + pci_write_config_word(pcidev, 0x40, 0x907f); + /* initialize the chips */ if (!reset_ctrl(s)) { printk(KERN_ERR "esssolo1: cannot reset controller\n"); @@ -2190,9 +2199,8 @@ } -#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ - ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) -#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) +#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ + (pci_resource_flags((dev), (num)) & IORESOURCE_IO)) static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { @@ -2229,12 +2237,12 @@ spin_lock_init(&s->lock); s->magic = SOLO1_MAGIC; s->dev = pcidev; - s->iobase = RSRCADDRESS(pcidev, 0); - s->sbbase = RSRCADDRESS(pcidev, 1); - s->vcbase = RSRCADDRESS(pcidev, 2); + s->iobase = pci_resource_start(pcidev, 0); + s->sbbase = pci_resource_start(pcidev, 1); + s->vcbase = pci_resource_start(pcidev, 2); s->ddmabase = s->vcbase + DDMABASE_OFFSET; - s->mpubase = RSRCADDRESS(pcidev, 3); - s->gpbase = RSRCADDRESS(pcidev, 4); + s->mpubase = pci_resource_start(pcidev, 3); + s->gpbase = pci_resource_start(pcidev, 4); s->irq = pcidev->irq; if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) { printk(KERN_ERR "solo1: io ports in use\n"); @@ -2252,13 +2260,12 @@ printk(KERN_ERR "solo1: io ports in use\n"); goto err_region4; } - if (pci_enable_device(pcidev)) - goto err_irq; if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) { printk(KERN_ERR "solo1: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase); + if (pci_enable_device(pcidev)) + goto err_irq; printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1); /* register devices */ if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) @@ -2352,7 +2359,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.14 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "solo1: version v0.15 time " __TIME__ " " __DATE__ "\n"); if (!pci_register_driver(&solo1_driver)) { pci_unregister_driver(&solo1_driver); return -ENODEV; diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.3.99-pre9/linux/drivers/sound/sonicvibes.c Tue May 23 15:31:35 2000 +++ linux/drivers/sound/sonicvibes.c Wed May 24 11:22:16 2000 @@ -2428,9 +2428,8 @@ { SOUND_MIXER_WRITE_PCM, 0x4040 } }; -#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ - ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) -#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) +#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \ + (pci_resource_flags((dev), (num)) & IORESOURCE_IO)) static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { @@ -2484,13 +2483,13 @@ spin_lock_init(&s->lock); s->magic = SV_MAGIC; s->dev = pcidev; - s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB); - s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH); - s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH); - s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI); - s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME); - s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA); - s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA; + s->iosb = pci_resource_start(pcidev, RESOURCE_SB); + s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH); + s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH); + s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI); + s->iogame = pci_resource_start(pcidev, RESOURCE_GAME); + s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA); + s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA; pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", @@ -2655,11 +2654,7 @@ if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); #endif - if (!pci_register_driver(&sv_driver)) { - pci_unregister_driver(&sv_driver); - return -ENODEV; - } - return 0; + return pci_module_init(&sv_driver); } static void __exit cleanup_sonicvibes(void) diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.3.99-pre9/linux/drivers/usb/audio.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/audio.c Wed May 24 14:01:44 2000 @@ -52,14 +52,17 @@ * decent headphones! * "Let's make things better" -> but please Philips start with your * own stuff!!!! - * 1999-11-02: It takes the Philips boxes several seconds to acquire synchronisation + * 1999-11-02: Thomas Sailer + * It takes the Philips boxes several seconds to acquire synchronisation * that means they won't play short sounds. Should probably maintain * the ISO datastream even if there's nothing to play. * Fix counting the total_bytes counter, RealPlayer G2 depends on it. - * 1999-12-20: Fix bad bug in conversion to per interface probing. + * 1999-12-20: Thomas Sailer + * Fix bad bug in conversion to per interface probing. * disconnect was called multiple times for the audio device, * leading to a premature freeing of the audio structures - * 2000-05-13: I don't remember who changed the find_format routine, + * 2000-05-13: Thomas Sailer + * I don't remember who changed the find_format routine, * but the change was completely broken for the Dallas * chip. Anyway taking sampling rate into account in find_format * is bad and should not be done unless there are devices with @@ -72,8 +75,20 @@ * for the Dallas chip. * Also fix a rather long standing problem with applications that * use "small" writes producing no sound at all. - * 2000-05-15: My fears came true, the Philips camera indeed has pretty stupid + * 2000-05-15: Thomas Sailer + * My fears came true, the Philips camera indeed has pretty stupid * audio descriptors. + * 2000-05-17: Thomas Sailer + * Nemsoft spotted my stupid last minute change, thanks + * 2000-05-19: Thomas Sailer + * Fixed FEATURE_UNIT thinkos found thanks to the KC Technology + * Xtend device. Basically the driver treated FEATURE_UNIT's sourced + * by mono terminals as stereo. + * 2000-05-20: Thomas Sailer + * SELECTOR support (and thus selecting record channels from the mixer). + * Somewhat peculiar due to OSS interface limitations. Only works + * for channels where a "slider" is already in front of it (i.e. + * a MIXER unit or a FEATURE unit with volume capability). * */ @@ -211,6 +226,7 @@ __u16 value; __u16 osschannel; /* number of the OSS channel */ __s16 minval, maxval; + __u16 slctunitid; __u8 unitid; __u8 selector; __u8 chnum; @@ -988,7 +1004,7 @@ } spin_lock_irqsave(&as->lock, flags); } - if (u->dma.count <= 0 && !u->dma.mapped) + if (u->dma.count >= u->dma.dmasize && !u->dma.mapped) return 0; u->flags |= FLG_RUNNING; if (!(u->flags & FLG_URB0RUNNING)) { @@ -1719,7 +1735,7 @@ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0) goto err; - if (ch->chnum == 0) + if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) return 0; data[0] = v2; data[1] = v2 >> 8; @@ -1735,7 +1751,7 @@ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0) goto err; - if (ch->chnum == 0) + if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) return 0; data[0] = v2 >> 8; if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, @@ -1754,6 +1770,89 @@ return -1; } +static int get_rec_src(struct usb_mixerdev *ms) +{ + struct usb_device *dev = ms->state->usbdev; + unsigned int mask = 0, retmask = 0; + unsigned int i, j; + unsigned char buf; + int err = 0; + + for (i = 0; i < ms->numch; i++) { + if (!ms->ch[i].slctunitid || (mask & (1 << i))) + continue; + if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) { + err = -EIO; + printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", + dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff); + continue; + } + for (j = i; j < ms->numch; i++) { + if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) + continue; + mask |= 1 << j; + if (buf == (ms->ch[j].slctunitid >> 8)) + retmask |= 1 << ms->ch[j].osschannel; + } + } + if (err) + return -EIO; + return retmask; +} + +static int set_rec_src(struct usb_mixerdev *ms, int srcmask) +{ + struct usb_device *dev = ms->state->usbdev; + unsigned int mask = 0, smask, bmask; + unsigned int i, j; + unsigned char buf; + int err = 0; + + for (i = 0; i < ms->numch; i++) { + if (!ms->ch[i].slctunitid || (mask & (1 << i))) + continue; + if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) { + err = -EIO; + printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", + dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff); + continue; + } + /* first generate smask */ + smask = bmask = 0; + for (j = i; j < ms->numch; i++) { + if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) + continue; + smask |= 1 << ms->ch[j].osschannel; + if (buf == (ms->ch[j].slctunitid >> 8)) + bmask |= 1 << ms->ch[j].osschannel; + mask |= 1 << j; + } + /* check for multiple set sources */ + j = hweight32(srcmask & smask); + if (j == 0) + continue; + if (j > 1) + srcmask &= ~bmask; + for (j = i; j < ms->numch; i++) { + if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) + continue; + if (!(srcmask & (1 << ms->ch[j].osschannel))) + continue; + buf = ms->ch[j].slctunitid >> 8; + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + 0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, HZ) < 0) { + err = -EIO; + printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n", + dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff); + continue; + } + } + } + return err ? -EIO : 0; +} + /* --------------------------------------------------------------------- */ /* @@ -1886,8 +1985,10 @@ if (_IOC_DIR(cmd) == _IOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - /* don't know how to handle this yet */ - return put_user(0, (int *)arg); + val = get_rec_src(ms); + if (val < 0) + return val; + return put_user(val, (int *)arg); case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ for (val = i = 0; i < ms->numch; i++) @@ -1895,9 +1996,11 @@ return put_user(val, (int *)arg); case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - /* don't know how to handle this yet */ - return put_user(0, (int *)arg); - + for (val = i = 0; i < ms->numch; i++) + if (ms->ch[i].slctunitid) + val |= 1 << ms->ch[i].osschannel; + return put_user(val, (int *)arg); + case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ for (val = i = 0; i < ms->numch; i++) if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) @@ -1905,7 +2008,7 @@ return put_user(val, (int *)arg); case SOUND_MIXER_CAPS: - return put_user(0, (int *)arg); + return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); default: i = _IOC_NR(cmd); @@ -1925,8 +2028,7 @@ switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ get_user_ret(val, (int *)arg, -EFAULT); - /* set recording source: val */ - return 0; + return set_rec_src(ms, val); default: i = _IOC_NR(cmd); @@ -2852,7 +2954,7 @@ { unsigned int u; - if ((state->termtype & 0xff00) == 0x0000 && !(state->mixchmask & SOUND_MASK_VOLUME)) + if ((state->termtype & 0xff00) == 0x0000 && (state->mixchmask & SOUND_MASK_VOLUME)) return SOUND_MIXER_VOLUME; if ((state->termtype & 0xff00) == 0x0100) { if (state->mixchmask & SOUND_MASK_PCM) @@ -2864,8 +2966,6 @@ return SOUND_MIXER_MIC; if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER)) return SOUND_MIXER_SPEAKER; - if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER)) - return SOUND_MIXER_SPEAKER; if ((state->termtype & 0xff00) == 0x0500) { if (state->mixchmask & SOUND_MASK_PHONEIN) return SOUND_MIXER_PHONEIN; @@ -2950,7 +3050,7 @@ if (v3 > 100) v3 = 100; ch->value = v3; - if (ch->chnum != 0) { + if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) { if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0) goto err; @@ -2986,7 +3086,7 @@ if (v3 > 100) v3 = 100; ch->value = v3; - if (ch->chnum != 0) { + if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) { if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0) goto err; @@ -3095,15 +3195,24 @@ static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector) { - unsigned int chnum, i; + unsigned int chnum, i, mixch; + struct mixerchannel *mch; if (!selector[4]) { printk(KERN_ERR "usbaudio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]); return; } + mixch = state->nrmixch; usb_audio_recurseunit(state, selector[5]); + if (state->nrmixch != mixch) { + mch = &state->mixch[state->nrmixch-1]; + mch->slctunitid = selector[5] | (1 << 8); + } else { + printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]); + } chnum = state->nrchannels; for (i = 1; i < selector[4]; i++) { + mixch = state->nrmixch; usb_audio_recurseunit(state, selector[5+i]); if (chnum != state->nrchannels) { printk(KERN_ERR "usbaudio: selector unit %u: input pins with varying channel numbers\n", selector[3]); @@ -3112,6 +3221,12 @@ state->nrchannels = 0; return; } + if (state->nrmixch != mixch) { + mch = &state->mixch[state->nrmixch-1]; + mch->slctunitid = selector[5] | ((i + 1) << 8); + } else { + printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1); + } } state->termtype = 0; state->chconfig = 0; @@ -3167,7 +3282,7 @@ ch->unitid = ftr[3]; ch->selector = VOLUME_CONTROL; ch->chnum = 1; - ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT; + ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0; prepmixch(state); } } else if (mchftr & 2) { @@ -3187,7 +3302,7 @@ ch->unitid = ftr[3]; ch->selector = BASS_CONTROL; ch->chnum = 1; - ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT; + ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0; prepmixch(state); } } else if (mchftr & 4) { @@ -3207,7 +3322,7 @@ ch->unitid = ftr[3]; ch->selector = TREBLE_CONTROL; ch->chnum = 1; - ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT; + ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0; prepmixch(state); } } else if (mchftr & 16) { @@ -3239,7 +3354,7 @@ unsigned int i, j; if (test_and_set_bit(unitid, &state->unitbitmap)) { - printk(KERN_ERR "usbaudio: mixer path recursion detected, unit %d!\n", unitid); + printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid); return; } p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif); diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/usb/ibmcam.c linux/drivers/usb/ibmcam.c --- v2.3.99-pre9/linux/drivers/usb/ibmcam.c Tue Apr 11 15:09:20 2000 +++ linux/drivers/usb/ibmcam.c Wed May 24 17:52:43 2000 @@ -7,6 +7,22 @@ * * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap + * + * 5/24/00 Removed optional (and unnecessary) locking of the driver while + * the device remains plugged in. Corrected race conditions in ibmcam_open + * and ibmcam_probe() routines using this as a guideline: + * + * (2) The big kernel lock is automatically released when a process sleeps + * in the kernel and is automatically reacquired on reschedule if the + * process had the lock originally. Any code that can be compiled as + * a module and is entered with the big kernel lock held *MUST* + * increment the use count to activate the indirect module protection + * before doing anything that might sleep. + * + * In practice, this means that all routines that live in modules and + * are invoked under the big kernel lock should do MOD_INC_USE_COUNT + * as their very first action. And all failure paths from that + * routine must do MOD_DEC_USE_COUNT before returning. */ #include @@ -26,21 +42,6 @@ #include "ibmcam.h" -/* - * IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED: This symbol controls - * the locking of the driver. If non-zero, the driver counts the - * probe() call as usage and increments module usage counter; this - * effectively prevents removal of the module (with rmmod) until the - * device is unplugged (then disconnect() callback reduces the module - * usage counter back, and module can be removed). - * - * This behavior may be useful if you prefer to lock the driver in - * memory until device is unplugged. However you can't reload the - * driver if you want to alter some parameters - you'd need to unplug - * the camera first. Therefore, I recommend setting 0. - */ -#define IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED 0 - #define ENABLE_HEXDUMP 0 /* Enable if you need it */ static int debug = 0; @@ -242,7 +243,7 @@ size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); - mem = vmalloc(size); + mem = vmalloc_32(size); if (!mem) return NULL; @@ -2346,6 +2347,7 @@ * camera is also initialized here (once per connect), at * expense of V4L client (it waits on open() call). * 1/27/00 Used IBMCAM_NUMSBUF as number of URB buffers. + * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT). */ static int ibmcam_open(struct video_device *dev, int flags) { @@ -2353,6 +2355,7 @@ const int sb_size = FRAMES_PER_DESC * ibmcam->iso_packet_len; int i, err = 0; + MOD_INC_USE_COUNT; down(&ibmcam->lock); if (ibmcam->user) @@ -2425,14 +2428,13 @@ else err = -EBUSY; } - if (!err) { + if (!err) ibmcam->user++; - MOD_INC_USE_COUNT; - } } } - up(&ibmcam->lock); + if (err) + MOD_DEC_USE_COUNT; return err; } @@ -2446,6 +2448,7 @@ * History: * 1/22/00 Moved scratch buffer deallocation here. * 1/27/00 Used IBMCAM_NUMSBUF as number of URB buffers. + * 5/24/00 Moved MOD_DEC_USE_COUNT outside of code that can sleep. */ static void ibmcam_close(struct video_device *dev) { @@ -2462,13 +2465,13 @@ kfree(ibmcam->sbuf[i].data); ibmcam->user--; - MOD_DEC_USE_COUNT; if (ibmcam->remove_pending) { printk(KERN_INFO "ibmcam_close: Final disconnect.\n"); usb_ibmcam_release(ibmcam); } up(&ibmcam->lock); + MOD_DEC_USE_COUNT; } static int ibmcam_init_done(struct video_device *dev) @@ -2891,7 +2894,7 @@ } /* - * usb_ibmcam_release() + * ibmcam_find_struct() * * This code searches the array of preallocated (static) structures * and returns index of the first one that isn't in use. Returns -1 @@ -2929,6 +2932,7 @@ * History: * 1/22/00 Moved camera init code to ibmcam_open() * 1/27/00 Changed to use static structures, added locking. + * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT). */ static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum) { @@ -2994,10 +2998,14 @@ RESTRICT_TO_RANGE(videosize, VIDEOSIZE_176x144, VIDEOSIZE_352x240); } + /* Code below may sleep, need to lock module while we are here */ + MOD_INC_USE_COUNT; + devnum = ibmcam_find_struct(); if (devnum == -1) { printk(KERN_INFO "IBM USB camera driver: Too many devices!\n"); - return NULL; + ibmcam = NULL; /* Do not free, it's preallocated */ + goto probe_done; } ibmcam = &cams[devnum]; @@ -3017,17 +3025,14 @@ usb_ibmcam_configure_video(ibmcam); up (&ibmcam->lock); -#if IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED - MOD_INC_USE_COUNT; -#endif - if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER) == -1) { printk(KERN_ERR "video_register_device failed\n"); - return NULL; + ibmcam = NULL; /* Do not free, it's preallocated */ } if (debug > 1) printk(KERN_DEBUG "video_register_device() successful\n"); - +probe_done: + MOD_DEC_USE_COUNT; return ibmcam; } @@ -3055,17 +3060,26 @@ * structure (pointed by 'ptr') and after that driver should be removable * with no ill consequences. * - * TODO: This code behaves badly on surprise removal! + * This code handles surprise removal. The ibmcam->user is a counter which + * increments on open() and decrements on close(). If we see here that + * this counter is not 0 then we have a client who still has us opened. + * We set ibmcam->remove_pending flag as early as possible, and after that + * all access to the camera will gracefully fail. These failures should + * prompt client to (eventually) close the video device, and then - in + * ibmcam_close() - we decrement ibmcam->ibmcam_used and usage counter. * * History: * 1/22/00 Added polling of MOD_IN_USE to delay removal until all users gone. * 1/27/00 Reworked to allow pending disconnects; see ibmcam_close() + * 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT). */ static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr) { static const char proc[] = "usb_ibmcam_disconnect"; struct usb_ibmcam *ibmcam = (struct usb_ibmcam *) ptr; + MOD_INC_USE_COUNT; + if (debug > 0) printk(KERN_DEBUG "%s(%p,%p.)\n", proc, dev, ptr); @@ -3077,16 +3091,14 @@ ibmcam->dev = NULL; /* USB device is no more */ -#if IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED - MOD_DEC_USE_COUNT; -#endif if (ibmcam->user) printk(KERN_INFO "%s: In use, disconnect pending.\n", proc); else usb_ibmcam_release(ibmcam); up(&ibmcam->lock); - printk(KERN_INFO "IBM USB camera disconnected.\n"); + + MOD_DEC_USE_COUNT; } static struct usb_driver ibmcam_driver = { diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- v2.3.99-pre9/linux/drivers/usb/ov511.c Tue May 23 15:31:35 2000 +++ linux/drivers/usb/ov511.c Wed May 24 17:52:43 2000 @@ -30,7 +30,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static const char version[] = "1.14"; +static const char version[] = "1.15"; #define __NO_VERSION__ @@ -216,7 +216,7 @@ size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); - mem = vmalloc(size); + mem = vmalloc_32(size); if (!mem) return NULL; @@ -263,9 +263,10 @@ * Based on the CPiA driver version 0.7.4 -claudio **********************************************************************/ -#ifdef CONFIG_PROC_FS +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + static struct proc_dir_entry *ov511_proc_entry = NULL; -static struct proc_dir_entry *video_proc_entry = NULL; +extern struct proc_dir_entry *video_proc_entry; #define YES_NO(x) ((x) ? "yes" : "no") @@ -343,6 +344,7 @@ len = count; *start = page + off; + return len; } @@ -357,12 +359,11 @@ char name[7]; struct proc_dir_entry *ent; - PDEBUG (4, "creating /proc/video/ov511/videoX entry"); if (!ov511_proc_entry || !ov511) return; sprintf(name, "video%d", ov511->vdev.minor); - PDEBUG (4, "creating %s", name); + PDEBUG (4, "creating /proc/video/ov511/%s", name); ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_entry); @@ -372,7 +373,6 @@ ent->data = ov511; ent->read_proc = ov511_read_proc; ent->write_proc = ov511_write_proc; - ent->size = 3626; /* FIXME */ ov511->proc_entry = ent; } @@ -391,22 +391,13 @@ static void proc_ov511_create(void) { - struct proc_dir_entry *p = NULL; - /* No current standard here. Alan prefers /proc/video/ as it keeps * /proc "less cluttered than /proc/randomcardifoundintheshed/" * -claudio */ - PDEBUG (3, "creating /proc/video"); - video_proc_entry = proc_mkdir("video", p); - if (!video_proc_entry) { - if (!p) { - err("Unable to initialise /proc/video\n"); - return; - } else { /* FIXME - this doesn't work */ - PDEBUG (3, "/proc/video already exists"); - video_proc_entry = p; - } + if (video_proc_entry == NULL) { + err("Unable to initialise /proc/video/ov511"); + return; } ov511_proc_entry = create_proc_entry("ov511", S_IFDIR, video_proc_entry); @@ -414,16 +405,19 @@ if (ov511_proc_entry) ov511_proc_entry->owner = THIS_MODULE; else - err("Unable to initialise /proc/video/ov511\n"); + err("Unable to initialise /proc/ov511"); } static void proc_ov511_destroy(void) { PDEBUG (3, "removing /proc/video/ov511"); + + if (ov511_proc_entry == NULL) + return; + remove_proc_entry("ov511", video_proc_entry); - remove_proc_entry("video", NULL); } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ /********************************************************************** @@ -852,7 +846,7 @@ return 0; } -/* FIXME: add 176x144, 160x140 */ +/* FIXME: add 400x300, 176x144, 160x140 */ static struct mode_list mlist[] = { { 640, 480, VIDEO_PALETTE_GREY, 0x4f, 0x3d, 0x00, 0x00, 0x4f, 0x3d, 0x00, 0x00, 0x04, 0x03, 0x24, 0x04, 0x9e }, @@ -866,6 +860,14 @@ 0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, { 352, 288, VIDEO_PALETTE_RGB24,0x2b, 0x25, 0x00, 0x00, 0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, + { 384, 288, VIDEO_PALETTE_GREY, 0x2f, 0x25, 0x00, 0x00, + 0x2f, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, + { 384, 288, VIDEO_PALETTE_RGB24,0x2f, 0x25, 0x00, 0x00, + 0x2f, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, + { 448, 336, VIDEO_PALETTE_GREY, 0x37, 0x29, 0x00, 0x00, + 0x37, 0x29, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, + { 448, 336, VIDEO_PALETTE_RGB24,0x37, 0x29, 0x00, 0x00, + 0x37, 0x29, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e }, { 0, 0 } }; @@ -1302,158 +1304,190 @@ int i, totlen = 0; int aPackNum[10]; struct ov511_frame *frame; + unsigned char *pData; + int iPix; - PDEBUG(4, "ov511_move_data"); + PDEBUG (4, "Moving %d packets", urb->number_of_packets); for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; int st = urb->iso_frame_desc[i].status; + urb->iso_frame_desc[i].actual_length = 0; urb->iso_frame_desc[i].status = 0; + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1; - if (!n || ov511->curframe == -1) continue; + if (!n || ov511->curframe == -1) + continue; if (st) PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); frame = &ov511->frame[ov511->curframe]; - /* Can we find a frame end */ + /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th + * byte non-zero. The EOF packet has image width/height in the + * 10th and 11th packets. The 9th bit is given as follows: + * + * bit 7: EOF + * 6: compression enabled + * 5: 422/420/400 modes + * 4: 422/420/400 modes + * 3: 1 + * 2: snapshot bottom on + * 1: snapshot frame + * 0: even/odd field + */ + + /* Check for SOF/EOF packet */ if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | - cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 && - (cdata[8] & 8) && (cdata[8] & 0x80)) { + cdata[4] | cdata[5] | cdata[6] | cdata[7]) || + (~cdata[8] & 0x08)) + goto check_middle; + + /* Frame end */ + if (cdata[8] & 0x80) { +#if 0 + struct timeval *ts; + + ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE); + do_gettimeofday (ts); +#endif + + PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d", + ov511->curframe, (int)(cdata[ov511->packet_size - 1]), + (int)(cdata[9]), (int)(cdata[10])); - struct timeval *ts; - ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE); - do_gettimeofday(ts); - - PDEBUG(4, "Frame End, curframe = %d, packnum=%d, hw=%d, vw=%d", - ov511->curframe, (int)(cdata[ov511->packet_size - 1]), - (int)(cdata[9]), (int)(cdata[10])); + if (frame->scanstate == STATE_LINES) { + int iFrameNext; - if (frame->scanstate == STATE_LINES) { - int iFrameNext; if (fix_rgb_offset) fixFrameRGBoffset(frame); frame->grabstate = FRAME_DONE; - if (waitqueue_active(&frame->wq)) { - frame->grabstate = FRAME_DONE; - wake_up_interruptible(&frame->wq); + + if (waitqueue_active(&frame->wq)) { + frame->grabstate = FRAME_DONE; + wake_up_interruptible(&frame->wq); } - /* If next frame is ready or grabbing, point to it */ + + /* If next frame is ready or grabbing, + * point to it */ iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; - if (ov511->frame[iFrameNext].grabstate== FRAME_READY || - ov511->frame[iFrameNext].grabstate== FRAME_GRABBING) { - ov511->curframe = iFrameNext; - ov511->frame[iFrameNext].scanstate = STATE_SCANNING; + if (ov511->frame[iFrameNext].grabstate == FRAME_READY + || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) { + ov511->curframe = iFrameNext; + ov511->frame[iFrameNext].scanstate = STATE_SCANNING; } else { + if (frame->grabstate == FRAME_DONE) { + PDEBUG(4, "Frame done! congratulations"); + } else { + PDEBUG(4, "Frame not ready? state = %d", + ov511->frame[iFrameNext].grabstate); + } - PDEBUG(4, "Frame not ready? state = %d", - ov511->frame[iFrameNext].grabstate); - - ov511->curframe = -1; + ov511->curframe = -1; } - } - } - - /* Can we find a frame start */ - else if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | - cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 && - (cdata[8] & 8)) { - - PDEBUG(4, "ov511: Found Frame Start!, framenum = %d", - ov511->curframe); + } + /* Image corruption caused by misplaced frame->segment = 0 + * fixed by carlosf@conectiva.com.br + */ + } else { + /* Frame start */ + PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); /* Check to see if it's a snapshot frame */ /* FIXME?? Should the snapshot reset go here? Performance? */ if (cdata[8] & 0x02) { frame->snapshot = 1; - PDEBUG(3, "ov511_move_data: snapshot detected"); + PDEBUG(3, "snapshot detected"); } frame->scanstate = STATE_LINES; frame->segment = 0; } +check_middle: /* Are we in a frame? */ - if (frame->scanstate == STATE_LINES) { - unsigned char * pData; - int iPix; - - /* Deal with leftover from last segment, if any */ - if (frame->segment) { - pData = ov511->scratch; - iPix = - ov511->scratchlen; - memmove(pData + ov511->scratchlen, cdata, - iPix+frame->segsize); - } else { - pData = &cdata[iPix = 9]; - } + if (frame->scanstate != STATE_LINES) + continue; - /* Parse the segments */ - while(iPix <= (ov511->packet_size - 1) - frame->segsize && - frame->segment < frame->width * frame->height / 256) { - int iSegY; - int iSegUV; - int iY, jY, iUV, jUV; - int iOutY, iOutUV; - unsigned char * pOut; - - iSegY = iSegUV = frame->segment; - pOut = frame->data; - - frame->segment++; - iPix += frame->segsize; - - if (frame->sub_flag) { - int iSeg1; - iSeg1 = iSegY / (ov511->subw / 32); - iSeg1 *= frame->width / 32; - iSegY = iSeg1 + (iSegY % (ov511->subw / 32)); - if (iSegY >= frame->width * ov511->subh / 256) - break; - - iSeg1 = iSegUV / (ov511->subw / 16); - iSeg1 *= frame->width / 16; - iSegUV = iSeg1 + (iSegUV % (ov511->subw / 16)); - - pOut += (ov511->subx + - ov511->suby * frame->width) * frame->depth; - } - - iY = iSegY / (frame->width / WDIV); - jY = iSegY - iY * (frame->width / WDIV); - iOutY = (iY*HDIV*frame->width + jY*WDIV) * frame->depth; - iUV = iSegUV / (frame->width / WDIV * 2); - jUV = iSegUV - iUV * (frame->width / WDIV * 2); - iOutUV = (iUV*HDIV*2*frame->width + jUV*WDIV/2) * frame->depth; - - if (frame->format == VIDEO_PALETTE_GREY) { - ov511_parse_data_grey(pData, pOut, iOutY, frame->width); - } else if (frame->format == VIDEO_PALETTE_RGB24) { - ov511_parse_data_rgb24(pData, pOut, iOutY, iOutUV, iY & 1, - frame->width); - } - pData = &cdata[iPix]; - } + /* Deal with leftover from last segment, if any */ + if (frame->segment) { + pData = ov511->scratch; + iPix = -ov511->scratchlen; + memmove(pData + ov511->scratchlen, cdata, + iPix+frame->segsize); + } else { + pData = &cdata[iPix = 9]; + } + + /* Parse the segments */ + while (iPix <= (ov511->packet_size - 1) - frame->segsize && + frame->segment < frame->width * frame->height / 256) { + int iSegY, iSegUV; + int iY, jY, iUV, jUV; + int iOutY, iOutUV; + unsigned char *pOut; + + iSegY = iSegUV = frame->segment; + pOut = frame->data; + frame->segment++; + iPix += frame->segsize; + + /* Handle subwindow */ + if (frame->sub_flag) { + int iSeg1; + + iSeg1 = iSegY / (ov511->subw / 32); + iSeg1 *= frame->width / 32; + iSegY = iSeg1 + (iSegY % (ov511->subw / 32)); + if (iSegY >= frame->width * ov511->subh / 256) + break; + + iSeg1 = iSegUV / (ov511->subw / 16); + iSeg1 *= frame->width / 16; + iSegUV = iSeg1 + (iSegUV % (ov511->subw / 16)); - /* Save extra data for next time */ - if (frame->segment < frame->width * frame->height / 256) { - ov511->scratchlen = (ov511->packet_size - 1) - iPix; - if (ov511->scratchlen < frame->segsize) { - memmove(ov511->scratch, pData, ov511->scratchlen); - } else { - ov511->scratchlen = 0; - } + pOut += (ov511->subx + ov511->suby * frame->width) * + (frame->depth >> 3); } + + /* + * iY counts segment lines + * jY counts segment columns + * iOutY is the offset (in bytes) of the segment upper left corner + */ + iY = iSegY / (frame->width / WDIV); + jY = iSegY - iY * (frame->width / WDIV); + iOutY = (iY*HDIV*frame->width + jY*WDIV) * (frame->depth >> 3); + iUV = iSegUV / (frame->width / WDIV * 2); + jUV = iSegUV - iUV * (frame->width / WDIV * 2); + iOutUV = (iUV*HDIV*2*frame->width + jUV*WDIV/2) * (frame->depth >> 3); + + if (frame->format == VIDEO_PALETTE_GREY) + ov511_parse_data_grey (pData, pOut, iOutY, frame->width); + else if (frame->format == VIDEO_PALETTE_RGB24) + ov511_parse_data_rgb24 (pData, pOut, iOutY, iOutUV, + iY & 1, frame->width); + + pData = &cdata[iPix]; + } + + /* Save extra data for next time */ + if (frame->segment < frame->width * frame->height / 256) { + ov511->scratchlen = (ov511->packet_size - 1) - iPix; + if (ov511->scratchlen < frame->segsize) + memmove(ov511->scratch, pData, + ov511->scratchlen); + else + ov511->scratchlen = 0; } } - - PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d\n", + PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d", aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4], aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]); @@ -1472,8 +1506,6 @@ if (!ov511->streaming) { PDEBUG(2, "hmmm... not streaming, but got interrupt"); return; - } else { - PDEBUG(5, "streaming. got interrupt"); } sbuf = &ov511->sbuf[ov511->cursbuf]; @@ -1723,7 +1755,7 @@ static int ov511_init_done(struct video_device *dev) { -#ifdef CONFIG_PROC_FS +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) create_proc_ov511_cam((struct usb_ov511 *)dev); #endif @@ -1749,6 +1781,8 @@ { struct video_capability b; + PDEBUG (4, "VIDIOCGCAP"); + strcpy(b.name, "OV511 USB Camera"); b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; b.channels = 1; @@ -1798,6 +1832,8 @@ { struct video_picture p; + PDEBUG (4, "VIDIOCGPICT"); + if (ov7610_get_picture(ov511, &p)) return -EIO; @@ -1809,18 +1845,33 @@ case VIDIOCSPICT: { struct video_picture p; + int i; + + PDEBUG (4, "VIDIOCSPICT"); if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; - + if (ov7610_set_picture(ov511, &p)) return -EIO; + /* FIXME: check validity */ + + PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette); + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov511->frame[i].depth = p.depth; + ov511->frame[i].format = p.palette; + ov511->frame[i].segsize = GET_SEGSIZE(p.palette); + } + return 0; } case VIDIOCGCAPTURE: { int vf; + + PDEBUG (4, "VIDIOCGCAPTURE"); + if (copy_from_user(&vf, arg, sizeof(vf))) return -EFAULT; ov511->sub_flag = vf; @@ -1836,16 +1887,25 @@ return -EINVAL; if (vc.decimation) return -EINVAL; +#if 0 vc.x /= 4; vc.x *= 4; vc.y /= 2; vc.y *= 2; vc.width /= 32; vc.width *= 32; - if (vc.width == 0) vc.width = 32; +#else + vc.x &= ~3L; + vc.y &= ~1L; + vc.y &= ~31L; +#endif + if (vc.width == 0) + vc.width = 32; + vc.height /= 16; vc.height *= 16; - if (vc.height == 0) vc.height = 16; + if (vc.height == 0) + vc.height = 16; ov511->subx = vc.x; ov511->suby = vc.y; @@ -1857,9 +1917,15 @@ case VIDIOCSWIN: { struct video_window vw; + int i, result; if (copy_from_user(&vw, arg, sizeof(vw))) return -EFAULT; + + PDEBUG (4, "VIDIOCSWIN: width=%d, height=%d", + vw.width, vw.height); + +#if 0 if (vw.flags) return -EINVAL; if (vw.clipcount) @@ -1868,8 +1934,22 @@ return -EINVAL; if (vw.width != DEFAULT_WIDTH) return -EINVAL; +#endif - ov511->compress = 0; + /* If we're collecting previous frame wait + before changing modes */ + interruptible_sleep_on(&ov511->wq); + if (signal_pending(current)) return -EINTR; + + result = ov511_mode_init_regs(ov511, vw.width, vw.height, + ov511->frame[0].format, ov511->sub_flag); + if (result < 0) + return result; + + for (i = 0; i < OV511_NUMFRAMES; i++) { + ov511->frame[i].width = vw.width; + ov511->frame[i].height = vw.height; + } return 0; } @@ -1877,13 +1957,15 @@ { struct video_window vw; - vw.x = 0; + vw.x = 0; /* FIXME */ vw.y = 0; - vw.width = DEFAULT_WIDTH; - vw.height = DEFAULT_HEIGHT; + vw.width = ov511->frame[0].width; + vw.height = ov511->frame[0].height; vw.chromakey = 0; vw.flags = 30; + PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height); + if (copy_to_user(arg, &vw, sizeof(vw))) return -EFAULT; @@ -1935,19 +2017,16 @@ before changing modes */ interruptible_sleep_on(&ov511->wq); if (signal_pending(current)) return -EINTR; - ov511_mode_init_regs(ov511, - vm.width, vm.height, - vm.format, ov511->sub_flag); + ov511_mode_init_regs(ov511, vm.width, vm.height, + vm.format, ov511->sub_flag); } ov511->frame[vm.frame].width = vm.width; ov511->frame[vm.frame].height = vm.height; ov511->frame[vm.frame].format = vm.format; ov511->frame[vm.frame].sub_flag = ov511->sub_flag; - ov511->frame[vm.frame].segsize = - vm.format == VIDEO_PALETTE_RGB24 ? 384 : 256; - ov511->frame[vm.frame].depth = - vm.format == VIDEO_PALETTE_RGB24 ? 3 : 1; + ov511->frame[vm.frame].segsize = GET_SEGSIZE(vm.format); + ov511->frame[vm.frame].depth = GET_DEPTH(vm.format); /* Mark it as ready */ ov511->frame[vm.frame].grabstate = FRAME_READY; @@ -1965,11 +2044,11 @@ ov511->frame[frame].grabstate); switch (ov511->frame[frame].grabstate) { - case FRAME_UNUSED: - return -EINVAL; - case FRAME_READY: - case FRAME_GRABBING: - case FRAME_ERROR: + case FRAME_UNUSED: + return -EINVAL; + case FRAME_READY: + case FRAME_GRABBING: + case FRAME_ERROR: redo: if (!ov511->dev) return -EIO; @@ -1989,23 +2068,21 @@ if ((ret = ov511_new_frame(ov511, frame)) < 0) return ret; goto redo; - } - case FRAME_DONE: - ov511->frame[frame].grabstate = FRAME_UNUSED; - break; - } - - ov511->frame[frame].grabstate = FRAME_UNUSED; - - /* Reset the hardware snapshot button */ - /* FIXME - Is this the best place for this? */ - if ((ov511->snap_enabled) && - (ov511->frame[frame].snapshot)) { - ov511->frame[frame].snapshot = 0; - ov511_reg_write(ov511->dev, 0x52, 0x01); - ov511_reg_write(ov511->dev, 0x52, 0x03); - ov511_reg_write(ov511->dev, 0x52, 0x01); - } + } + case FRAME_DONE: + ov511->frame[frame].grabstate = FRAME_UNUSED; + + /* Reset the hardware snapshot button */ + /* FIXME - Is this the best place for this? */ + if ((ov511->snap_enabled) && + (ov511->frame[frame].snapshot)) { + ov511->frame[frame].snapshot = 0; + ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); + ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03); + ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); + } + break; + } /* end switch */ return 0; } @@ -2038,7 +2115,7 @@ return -EINVAL; default: return -ENOIOCTLCMD; - } /* End switch(cmd) */ + } /* end switch */ return 0; } @@ -2610,7 +2687,7 @@ ov511->sbuf[0].urb = NULL; } -#ifdef CONFIG_PROC_FS +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) destroy_proc_ov511_cam(ov511); #endif @@ -2637,8 +2714,7 @@ static int __init usb_ov511_init(void) { -#ifdef CONFIG_PROC_FS - PDEBUG(3, "creating /proc/ov511"); +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) proc_ov511_create(); #endif @@ -2655,7 +2731,7 @@ usb_deregister(&ov511_driver); info("ov511 driver deregistered"); -#ifdef CONFIG_PROC_FS +#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) proc_ov511_destroy(); #endif } diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.3.99-pre9/linux/drivers/video/Config.in Wed Apr 26 16:34:08 2000 +++ linux/drivers/video/Config.in Wed May 24 18:38:26 2000 @@ -220,7 +220,8 @@ "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o \ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ - "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then + "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ + "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ @@ -236,7 +237,7 @@ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ - "$CONFIG_FB_SA1100" = "m" ]; then + "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB8 m fi fi @@ -250,7 +251,8 @@ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ - "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then + "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ + "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -262,7 +264,7 @@ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ - "$CONFIG_FB_CYBER2000" = "m" ]; then + "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m fi fi @@ -288,7 +290,7 @@ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ - "$CONFIG_FB_3DFX" = "y" ]; then + "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" ]; then define_tristate CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -297,7 +299,7 @@ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_ATY128" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" ]; then + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then define_tristate CONFIG_FBCON_CFB32 m fi fi diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.99-pre9/linux/drivers/video/Makefile Thu May 11 15:30:08 2000 +++ linux/drivers/video/Makefile Wed May 24 18:38:26 2000 @@ -88,6 +88,7 @@ obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o +obj-$(CONFIG_FB_SIS) += sisfb.o ifeq ($(CONFIG_FB_MATROX),y) SUB_DIRS += matrox diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- v2.3.99-pre9/linux/drivers/video/fbmem.c Wed Apr 26 16:34:08 2000 +++ linux/drivers/video/fbmem.c Thu May 25 09:35:27 2000 @@ -111,6 +111,8 @@ extern int rivafb_setup(char*); extern int tdfxfb_init(void); extern int tdfxfb_setup(char*); +extern int sisfb_init(void); +extern int sisfb_setup(char*); static struct { const char *name; @@ -230,6 +232,9 @@ #ifdef CONFIG_GSP_RESOLVER /* Not a real frame buffer device... */ { "resolver", NULL, resolver_video_setup }, +#endif +#ifdef CONFIG_FB_SIS + { "sisfb", sisfb_init, sisfb_setup }, #endif #ifdef CONFIG_FB_VIRTUAL /* Must be last to avoid that vfb becomes your primary display */ diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/video/sisfb.c linux/drivers/video/sisfb.c --- v2.3.99-pre9/linux/drivers/video/sisfb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sisfb.c Wed May 24 18:38:26 2000 @@ -0,0 +1,2982 @@ +/* + * SiS 300/630/540 frame buffer device For Kernal 2.3.x + * + * This driver is partly based on the VBE 2.0 compliant graphic + * boards framebuffer driver, which is + * + * (c) 1998 Gerd Knorr + * + */ + +#define EXPORT_SYMTAB +#undef SISFBDEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include