From b40190e68114b5621428817d633d79f785b437bc Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:32:30 -0500 Subject: [PATCH] Import 2.3.50pre3 --- Documentation/Configure.help | 18 +- Documentation/filesystems/devfs/ChangeLog | 17 + Documentation/filesystems/devfs/README | 29 +- Documentation/video4linux/bttv/CARDLIST | 6 +- Documentation/video4linux/bttv/Insmod-options | 18 +- Documentation/video4linux/bttv/README | 7 + Documentation/zorro.txt | 116 ++ arch/alpha/kernel/Makefile | 2 +- arch/alpha/kernel/osf_sys.c | 18 +- arch/arm/Makefile | 4 +- arch/arm/boot/compressed/Makefile | 2 +- arch/i386/Makefile | 6 +- arch/i386/boot/compressed/Makefile | 3 + arch/i386/config.in | 1 + arch/i386/defconfig | 7 +- arch/ia64/Makefile | 2 +- arch/mips/kernel/sysirix.c | 52 +- arch/sh/Makefile | 2 +- arch/sparc/kernel/sys_sunos.c | 28 +- arch/sparc64/kernel/entry.S | 14 +- arch/sparc64/kernel/head.S | 13 +- arch/sparc64/kernel/smp.c | 12 +- arch/sparc64/kernel/sys_sparc32.c | 28 +- arch/sparc64/kernel/sys_sunos32.c | 26 +- drivers/block/ide-probe.c | 7 +- drivers/block/ide.c | 6 + drivers/char/Config.in | 4 +- drivers/char/Makefile | 6 +- drivers/char/agp/agp.h | 1 + drivers/char/agp/agpgart_be.c | 3 + drivers/char/bttv.c | 1232 ++++++++++------- drivers/char/bttv.h | 165 +-- drivers/char/console.c | 2 +- drivers/char/msp3400.c | 41 +- drivers/char/ppdev.c | 10 +- drivers/char/pty.c | 5 +- drivers/char/sh-sci.h | 1 + drivers/char/tda9855.c | 455 ------ drivers/char/tda985x.c | 532 +++++++ drivers/char/tty_io.c | 15 +- drivers/char/tuner.c | 5 + drivers/net/Makefile | 2 + drivers/net/aironet4500_core.c | 14 +- drivers/net/aironet4500_proc.c | 10 +- drivers/net/pcmcia/aironet4500_cs.c | 11 +- drivers/scsi/pci2000.c | 7 +- drivers/scsi/pci2220i.c | 7 +- drivers/scsi/sg.c | 255 ++-- drivers/usb/Config.in | 12 +- drivers/usb/devices.c | 4 +- drivers/usb/inode.c | 4 +- drivers/usb/usb.c | 8 +- drivers/video/Config.in | 1 + drivers/video/fbcmap.c | 45 +- drivers/video/hgafb.c | 17 +- drivers/video/vgacon.c | 2 + drivers/zorro/Makefile | 21 +- drivers/zorro/proc.c | 18 +- drivers/zorro/zorro.c | 12 +- drivers/zorro/zorrosyms.c | 20 - fs/adfs/dir.c | 8 +- fs/affs/namei.c | 6 +- fs/autofs/root.c | 4 +- fs/binfmt_elf.c | 2 + fs/binfmt_em86.c | 4 + fs/buffer.c | 19 +- fs/coda/dir.c | 10 +- fs/devfs/base.c | 112 +- fs/devpts/root.c | 4 +- fs/exec.c | 3 + fs/fat/fatfs_syms.c | 1 + fs/hfs/sysdep.c | 10 +- fs/hpfs/dentry.c | 6 +- fs/isofs/inode.c | 24 +- fs/minix/namei.c | 6 +- fs/msdos/namei.c | 8 +- fs/namei.c | 217 +-- fs/ncpfs/dir.c | 8 +- fs/nfs/dir.c | 9 +- fs/nfsd/nfsfh.c | 5 +- fs/nfsd/vfs.c | 106 +- fs/ntfs/fs.c | 1 + fs/pipe.c | 1 - fs/proc/base.c | 17 +- fs/proc/generic.c | 5 +- fs/readdir.c | 73 +- fs/smbfs/dir.c | 8 +- fs/umsdos/dir.c | 6 +- fs/vfat/namei.c | 26 +- include/asm-i386/hw_irq.h | 4 + include/asm-sh/pgalloc.h | 1 - include/asm-sparc/pgtable.h | 2 +- include/asm-sparc64/pgtable.h | 2 +- include/asm-sparc64/system.h | 13 +- include/linux/devfs_fs_kernel.h | 36 +- include/linux/fs.h | 7 + include/linux/netfilter.h | 1 - include/linux/skbuff.h | 28 + include/linux/zorro.h | 1 - include/scsi/sg.h | 26 +- include/video/fbcon-hga.h | 32 + kernel/ksyms.c | 7 + mm/page_alloc.c | 2 + net/core/skbuff.c | 11 +- net/ipv4/ip_output.c | 8 +- 105 files changed, 2421 insertions(+), 1860 deletions(-) create mode 100644 Documentation/zorro.txt delete mode 100644 drivers/char/tda9855.c create mode 100644 drivers/char/tda985x.c delete mode 100644 drivers/zorro/zorrosyms.c create mode 100644 include/video/fbcon-hga.h diff --git a/Documentation/Configure.help b/Documentation/Configure.help index f660890446d9..dc7103e36d0b 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -8565,9 +8565,9 @@ CONFIG_USB_ACM USB Serial converter support CONFIG_USB_SERIAL Say Y here if you want to connect a Connect Tech WhiteHEAT - multi-port USB to serial converter; a Belkin, Peracom, or eTek - single port USB to serial converter; or a Handspring Visor. - Please read Documentation/usb/usb-serial.txt for more information. + multi-port USB to serial converter; a FTDI or Keyspan single port + USB to serial converter; or a Handspring Visor. Please read + Documentation/usb/usb-serial.txt for more information. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8592,6 +8592,16 @@ CONFIG_USB_SERIAL_VISOR its USB docking station. See http://usbvisor.sourceforge.net for more information on using this driver. +USB FTDI Single Port Serial Driver +CONFIG_USB_SERIAL_FTDI_SIO + Say Y here if you want to use a FTDI SIO single port USB to serial + converter device. + +USB FTDI Single Port Serial Driver +CONFIG_USB_SERIAL_KEYSPAN_PDA + Say Y here if you want to use a Keyspan PDA single port USB to serial + converter device. + USB Printer support CONFIG_USB_PRINTER Say Y here if you want to connect a USB printer to your computer's USB @@ -8663,7 +8673,7 @@ CONFIG_USB_PEGASUS This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called ov511.o. If you want to compile it as a + The module will be called pegasus.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. USB Kodak DC-2xx Camera support diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog index 7d8e58890495..2b8a0d2f0c93 100644 --- a/Documentation/filesystems/devfs/ChangeLog +++ b/Documentation/filesystems/devfs/ChangeLog @@ -1463,3 +1463,20 @@ Work sponsored by SGI - Fixed arch/i386/kernel/mtrr.c if procfs and devfs not enabled - Fixed drivers/char/stallion.c +=============================================================================== +Changes for patch v161 + +Work sponsored by SGI + +- Remove /dev/ide when ide-mod is unloaded + +- Fixed bug in drivers/block/ide-probe.c when secondary but no primary + +- Added DEVFS_FL_NO_PERSISTENCE flag + +- Used new DEVFS_FL_NO_PERSISTENCE flag for Unix98 pty slaves + +- Removed unnecessary call to in + + +- Only set auto-ownership for /dev/pty/s* diff --git a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README index b3ab9ffa6f8d..b0633ef5f276 100644 --- a/Documentation/filesystems/devfs/README +++ b/Documentation/filesystems/devfs/README @@ -4,7 +4,7 @@ Richard Gooch - 11-NOV-1999 + 3-MAR-2000 Conventions used in this document
@@ -22,6 +22,9 @@ There is also an optional daemon that may be used with devfs. You can find out more about it at: http://www.atnf.csiro.au/~rgooch/linux/ +NEWFLASH: The official 2.3.46 kernel has included the devfs +patch. Future patches will be released which build on this. + What is it?
=========== @@ -128,14 +131,13 @@ slow things down a lot. There is an existing programme called scsidev which will automatically create device nodes for SCSI devices. It can do this by scanning files in /proc/scsi. Unfortunately, to extend this idea to other device -nodes would require would require significant modifications to -existing drivers (so they too would provide information in -/proc). This is a non-trivial change (I should know: devfs has had to -do something similar). Once you go to this much effort, you may as -well use devfs itself (which also provides this information). -Furthermore, such a system would likely be implemented in an ad-hoc -fashion, as different drivers will provide their information in -different ways. +nodes would require significant modifications to existing drivers (so +they too would provide information in /proc). This is a non-trivial +change (I should know: devfs has had to do something similar). Once +you go to this much effort, you may as well use devfs itself (which +also provides this information). Furthermore, such a system would +likely be implemented in an ad-hoc fashion, as different drivers will +provide their information in different ways. Devfs is much cleaner, because it (natually) has a uniform mechanism to provide this information: the device nodes themselves! @@ -349,8 +351,8 @@ Who else does it?
FreeBSD-current now has a devfs implementation. Solaris 2 has a pseudo-devfs (something akin to scsidev but for all devices, with some -unspecified kernel support). BeOS and Plan9 also have it. SGI's IRIX -6.4 and above also have a device filesystem. +unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's +IRIX 6.4 and above also have a device filesystem. While we shouldn't just automatically do something because others do it, we should not ignore the work of others either. FreeBSD has a lot @@ -875,10 +877,7 @@ avoid any possible conflicts with existing official allocations. Please note that using dynamically allocated block device numbers may break the NFS daemons (both user and kernel mode), which expect dev_t -for a given device to be constant over reboots. A simple reboot, with -no change in your hardware layout, would result in the same device -numbers being allocated, and hence will not cause a problem for NFS -daemons. +for a given device to be constant over the lifetime of remote mounts. A final note on this scheme: since it doesn't increase the size of device numbers, there are no compatibility issues with userspace. diff --git a/Documentation/video4linux/bttv/CARDLIST b/Documentation/video4linux/bttv/CARDLIST index 0176ecf0ea90..495eb7e3d19c 100644 --- a/Documentation/video4linux/bttv/CARDLIST +++ b/Documentation/video4linux/bttv/CARDLIST @@ -1,5 +1,5 @@ bttv.o - card=0 - unknown + card=0 - *** UNKNOWN *** card=1 - MIRO PCTV card=2 - Hauppauge old card=3 - STB @@ -33,6 +33,10 @@ bttv.o card=31 - iProTV card=32 - Intel Create and Share PCI card=33 - Terratec TerraTValue + card=34 - Leadtek WinFast 2000 + card=35 - Chronos Video Shuttle II + card=36 - Typhoon TView TV/FM Tuner + card=37 - PixelView PlayTV pro tuner.o type=0 - Temic PAL diff --git a/Documentation/video4linux/bttv/Insmod-options b/Documentation/video4linux/bttv/Insmod-options index 838413146dd0..5d1774a32ecd 100644 --- a/Documentation/video4linux/bttv/Insmod-options +++ b/Documentation/video4linux/bttv/Insmod-options @@ -14,11 +14,19 @@ bttv.o but this might also help with other chipsets bigendian=n Set the endianness of the gfx framebuffer. Default is native endian. - fieldnr=1 Count fields. Some TV descrambling software + fieldnr=0/1 Count fields. Some TV descrambling software needs this, for others it only generates - 50 useless IRQs/sec. + 50 useless IRQs/sec. default is 0 (off). autoload=0/1 autoload helper modules (tuner, audio). default is 1 (on). + verbose=0/1/2 verbose level (at insmod time, while looking at + the hardware). default is 1. + debug=0/1 debug messages (for capture). + default is 0 (off). + gbuffers=2-64 number of capture buffers for mmap'ed capture. + default is 2. + gbufsize=n size of capture buffers. default and + maximum value is 0x208000 (~2MB) remap, card, radio and pll accept up to four comma-separated arguments (for multiple boards). @@ -59,12 +67,12 @@ tda8425.o insmod args: debug=1 print some debug info to the syslog. -tda9855.o - The driver for the tda9855 audio chip. Afaik, only the - Diamond DTV2000 has this chip. +tda985x.o + The driver for the tda9850/55 audio chips. insmod args: debug=1 print some debug info to the syslog. + chip=9850/9855 set the chip type. tuner.o The tuner driver. You need this unless you want to use only diff --git a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README index 8b9170e3d8a6..9d0709a576c6 100644 --- a/Documentation/video4linux/bttv/README +++ b/Documentation/video4linux/bttv/README @@ -12,6 +12,13 @@ newer than 2.3.34 have this already included. If you have a older kernel, download it from: http://www2.lm-sensors.nu/~lm78/download.html +You'll need at least these i2c config options for bttv: +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m + +The latest bttv version is available here: + http://www.in-berlin.de/User/kraxel/v4l/ + You'll find Ralphs original (mostly outdated) documentation in the ralphs-doc subdirectory. diff --git a/Documentation/zorro.txt b/Documentation/zorro.txt new file mode 100644 index 000000000000..ed77a047c2cf --- /dev/null +++ b/Documentation/zorro.txt @@ -0,0 +1,116 @@ + Writing Device Drivers for Zorro Devices + ---------------------------------------- + +Written by Geert Uytterhoeven +Last revised: February 27, 2000 + + +1. Introduction +--------------- + +The Zorro bus is the bus used in the Amiga family of computers. Thanks to +AutoConfig(tm), it's is 100% Plug-and-Play. + +There are two types of Zorro busses, Zorro II and Zorro III: + + - The Zorro II address space is 24-bit and lies within the first 16 MB of the + Amiga's address map. + + - Zorro III is a 32-bit extension of Zorro II, which is backwards compatible + with Zorro II. The Zorro III address space lies outside the first 16 MB. + + +2. Probing for Zorro Devices +---------------------------- + +Zorro devices are found by calling `zorro_find_device()', which returns a +pointer to the `next' Zorro device with the specified Zorro ID. A probe loop +for the board with Zorro ID `ZORRO_PROD_xxx' looks like: + + struct zorro_dev *z = NULL; + + while ((z = zorro_find_device(ZORRO_PROD_xxx, z))) { + if (!zorro_request_region(z->resource.start+MY_START, MY_SIZE, + "My explanation")) + strcpy(z->name, "My board name"); + ... + } + +`ZORRO_WILDCARD' acts as a wildcard and finds any Zorro device. If your driver +supports different types of boards, you can use a construct like: + + struct zorro_dev *z = NULL; + + while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { + if (z->id != ZORRO_PROD_xxx1 && z->id != ZORRO_PROD_xxx2 && ...) + continue; + if (!zorro_request_region(z->resource.start+MY_START, MY_SIZE, + "My explanation")) + ... + } + + +3. Zorro Resources +------------------ + +Before you can access a Zorro device's registers, you have to make sure it's +not yet in use. This is done using the I/O memory space resource management +functions: + + request_mem_region() + check_mem_region() (deprecated) + release_mem_region() + +Shortcuts to claim the whole device's address space are provided as well: + + zorro_request_device + zorro_check_device (deprecated) + zorro_release_device + + +4. Accessing the Zorro Address Space +------------------------------------ + +The address regions in the Zorro device resources are Zorro bus address +regions. Due to the identity bus-physical address mapping on the Zorro bus, +they are CPU physical addresses as well. + +The treatment of these regions depends on the type of Zorro space: + + - Zorro II address space is always mapped and does not have to be mapped + explicitly using ioremap(). + + Conversion from bus/physical Zorro II addresses to kernel virtual addresses + and vice versa is done using: + + virt_addr = ZTWO_VADDR(bus_addr); + bus_addr = ZTWO_PADDR(virt_addr); + + - Zorro III address space must be mapped explicitly using ioremap() first + before it can be accessed: + + virt_addr = ioremap(bus_addr, size); + ... + iounmap(virt_addr); + + +5. Zorro Device Naming +---------------------- + +Since we think generic device naming is something for userspace (zorroutils), +we don't keep a Zorro device name database in the kernel. +However, device drivers are allowed to store the expansion board name in struct +zorro_dev. + + +6. References +------------- + +linux/include/linux/zorro.h +linux/include/linux/ioport.h +linux/include/asm-m68k/io.h +linux/include/asm-m68k/amigahw.h +linux/include/asm-ppc/io.h +linux/driver/zorro +/proc/bus/zorro + diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 309a308a44c7..6c538f4bafb5 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -132,7 +132,7 @@ asm_offsets: check_asm ./check_asm > $(TOPDIR)/include/asm-alpha/asm_offsets.h check_asm: check_asm.c - gcc -o $@ $< -I$(TOPDIR)/include -D__KERNEL__ -ffixed-8 + $(HOSTCC) -o $@ $< $(CPPFLAGS) -ffixed-8 clean:: rm -f check_asm diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index d9af71414f3e..6a2ff8a9b1e4 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -135,10 +135,8 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, { int error; struct file *file; - struct inode *inode; struct osf_dirent_callback buf; - lock_kernel(); error = -EBADF; file = fget(fd); if (!file) @@ -149,18 +147,8 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, buf.count = count; buf.error = 0; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - /* - * Get the inode's semaphore to prevent changes - * to the directory while we read it. - */ - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, osf_filldir); - up(&inode->i_sem); + lock_kernel(); + error = vfs_readdir(file, osf_filldir, &buf); if (error < 0) goto out_putf; @@ -169,9 +157,9 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent, error = count - buf.count; out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 0df16ffa48cf..bb0a34f9265a 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -100,7 +100,7 @@ ifeq ($(CONFIG_CPU_32),y) endif endif -GCCLIB := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) +LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) ifeq ($(CONFIG_ARCH_A5K),y) MACHINE = a5k @@ -146,7 +146,7 @@ HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib \ arch/arm/special arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) -LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(GCCLIB) +LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC) DRIVERS += arch/arm/special/special.a ifeq ($(CONFIG_NWFPE),y) diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index d92f2b093fb8..fca3e8c92208 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -73,7 +73,7 @@ endif all: vmlinux vmlinux: $(HEAD) $(OBJS) piggy.o vmlinux.lds - $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(GCCLIB) -o vmlinux + $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(LIBGCC) -o vmlinux $(HEAD): $(HEAD:.o=.S) $(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S) diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 4ba71ba06236..2a84bf05feed 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -21,12 +21,10 @@ OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S LDFLAGS=-e stext LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS) -CFLAGS_PIPE := -pipe +CFLAGS += -pipe # only work around strength reduction bug(s) on older gcc versions -CFLAGS_NSR := $(shell if $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo ""; else echo "-fno-strength-reduce"; fi) - -CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR) +CFLAGS += $(shell if ! $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strength-reduce"; fi) # prevent gcc from keeping the stack 16 byte aligned CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi) diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile index 6e4b4998df57..b4b7de13382e 100644 --- a/arch/i386/boot/compressed/Makefile +++ b/arch/i386/boot/compressed/Makefile @@ -33,6 +33,9 @@ bvmlinux: piggy.o $(OBJECTS) head.o: head.S $(CC) $(AFLAGS) -traditional -c head.S +misc.o: misc.c + $(CC) $(CFLAGS) -c misc.c + piggy.o: $(SYSTEM) tmppiggy=_tmp_$$$$piggy; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ diff --git a/arch/i386/config.in b/arch/i386/config.in index 1d5c0d5f72f7..11a98fc58eda 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -47,6 +47,7 @@ if [ "$CONFIG_MK7" = "y" ]; then define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_USE_3DNOW y + define_bool CONFIG_X86_PGE y fi if [ "$CONFIG_DEVFS_FS" = "y" ]; then diff --git a/arch/i386/defconfig b/arch/i386/defconfig index f2517c27d222..aa04c36851bf 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -76,6 +76,10 @@ CONFIG_BINFMT_MISC=y CONFIG_PM=y CONFIG_ACPI=y # CONFIG_APM is not set + +# +# Parallel port support +# # CONFIG_PARPORT is not set # @@ -282,6 +286,7 @@ CONFIG_NET_ETHERNET=y CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set # CONFIG_DE4X5 is not set # CONFIG_TULIP is not set # CONFIG_DGRS is not set @@ -308,7 +313,7 @@ CONFIG_EEPRO100=y # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 7dd3caabc895..24e274aa0af7 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -88,7 +88,7 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot vmlinux: arch/$(ARCH)/vmlinux.lds arch/$(ARCH)/vmlinux.lds: arch/$(ARCH)/vmlinux.lds.S FORCE - gcc -D__ASSEMBLY__ -E -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \ + $(CPP) -D__ASSEMBLY__ -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \ arch/$(ARCH)/vmlinux.lds.S > $@ FORCE: ; diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 23a5efba7289..66b8ad4a2107 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -2025,12 +2025,10 @@ static int irix_filldir32(void *__buf, const char *name, int namlen, asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob) { struct file *file; - struct inode *inode; struct irix_dirent32 *lastdirent; struct irix_dirent32_callback buf; int error; - lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%ld] ngetdents(%d, %p, %d, %p) ", current->comm, current->pid, fd, dirent, count, eob); @@ -2040,26 +2038,14 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count if (!file) goto out; - inode = file->f_dentry->d_inode; - if (!inode) - goto out_putf; + lock_kernel(); buf.current_dir = (struct irix_dirent32 *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - /* - * Get the inode's semaphore to prevent changes - * to the directory while we read it. - */ - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, irix_filldir32); - up(&inode->i_sem); + error = vfs_readdir(file, irix_filldir32, &buf); if (error < 0) goto out_putf; error = buf.error; @@ -2081,9 +2067,9 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count error = count - buf.count; out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } @@ -2134,12 +2120,10 @@ static int irix_filldir64(void * __buf, const char * name, int namlen, asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) { struct file *file; - struct inode *inode; struct irix_dirent64 *lastdirent; struct irix_dirent64_callback buf; int error; - lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%d] getdents64(%d, %p, %d) ", current->comm, current->pid, fd, dirent, cnt); @@ -2148,13 +2132,7 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) if (!(file = fget(fd))) goto out; - inode = file->f_dentry->d_inode; - if (!inode) - goto out_f; - - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_f; + lock_kernel(); error = -EFAULT; if(!access_ok(VERIFY_WRITE, dirent, cnt)) @@ -2168,9 +2146,7 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) buf.previous = NULL; buf.count = cnt; buf.error = 0; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, irix_filldir64); - up(&inode->i_sem); + error = vfs_readdir(file, irix_filldir64, &buf); if (error < 0) goto out_f; lastdirent = buf.previous; @@ -2185,21 +2161,19 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) error = cnt - buf.count; out_f: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) { struct file *file; - struct inode *inode; struct irix_dirent64 *lastdirent; struct irix_dirent64_callback buf; int error; - lock_kernel(); #ifdef DEBUG_GETDENTS printk("[%s:%d] ngetdents64(%d, %p, %d) ", current->comm, current->pid, fd, dirent, cnt); @@ -2208,13 +2182,7 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) if (!(file = fget(fd))) goto out; - inode = file->f_dentry->d_inode; - if (!inode) - goto out_f; - - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_f; + lock_kernel(); error = -EFAULT; if(!access_ok(VERIFY_WRITE, dirent, cnt) || @@ -2230,9 +2198,7 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) buf.previous = NULL; buf.count = cnt; buf.error = 0; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, irix_filldir64); - up(&inode->i_sem); + error = vfs_readdir(file, irix_filldir64, &buf); if (error < 0) goto out_f; lastdirent = buf.previous; @@ -2247,9 +2213,9 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) error = cnt - buf.count; out_f: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff --git a/arch/sh/Makefile b/arch/sh/Makefile index b0b694d8380a..83591c86cd09 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -73,7 +73,7 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot vmlinux: arch/sh/vmlinux.lds arch/sh/vmlinux.lds: arch/sh/vmlinux.lds.S FORCE - gcc -E -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds + $(CPP) -C -P -I$(HPATH) -Ush arch/sh/vmlinux.lds.S >arch/sh/vmlinux.lds FORCE: ; diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 82b5ac65361c..54c701768441 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -432,12 +432,10 @@ static int sunos_filldir(void * __buf, const char * name, int namlen, asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) { struct file * file; - struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; - lock_kernel(); if (fd >= SUNOS_NR_OPEN) goto out; @@ -445,10 +443,7 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) if (!file) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - + lock_kernel(); error = -EINVAL; if (cnt < (sizeof(struct sunos_dirent) + 255)) goto out_putf; @@ -458,10 +453,7 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) buf.count = cnt; buf.error = 0; - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, sunos_filldir); - up(&inode->i_sem); + error = vfs_readdir(file, sunos_filldir, &buf); if (error < 0) goto out_putf; @@ -473,9 +465,9 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } @@ -521,12 +513,10 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen, asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep) { struct file * file; - struct inode * inode; struct sunos_direntry * lastdirent; struct sunos_direntry_callback buf; int error = -EBADF; - lock_kernel(); if (fd >= SUNOS_NR_OPEN) goto out; @@ -534,10 +524,7 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi if (!file) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - + lock_kernel(); error = -EINVAL; if(cnt < (sizeof(struct sunos_direntry) + 255)) goto out_putf; @@ -547,10 +534,7 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi buf.count = cnt; buf.error = 0; - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, sunos_filldirentry); - up(&inode->i_sem); + error = vfs_readdir(file, sunos_filldirentry, &buf); if (error < 0) goto out_putf; @@ -562,9 +546,9 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsi } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index df636ec6f9f3..2ab8b70d4c0b 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.112 2000/01/14 07:12:31 davem Exp $ +/* $Id: entry.S,v 1.113 2000/03/06 22:33:42 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -927,7 +927,17 @@ ret_from_syscall: nop ldx [%g6 + AOFF_task_thread + AOFF_thread_pcr_reg], %o7 wr %g0, %o7, %pcr - wr %g0, %g0, %pic + + /* Blackbird errata workaround. See commentary in + * smp.c:smp_percpu_timer_interrupt() for more + * information. + */ + ba,pt %xcc, 99f + nop + .align 64 +99: wr %g0, %g0, %pic + rd %pic, %g0 + 1: b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 sparc_exit: rdpr %otherwin, %g1 diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 47a170f5469a..7eefa9f6599e 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.63 1999/11/19 05:52:49 davem Exp $ +/* $Id: head.S,v 1.64 2000/03/06 22:33:42 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -262,7 +262,16 @@ sun4u_init: /* Setup "Linux Current Register", thanks Sun 8-) */ wr %g0, 0x1, %pcr - wr %g6, 0x0, %pic + + /* Blackbird errata workaround. See commentary in + * smp.c:smp_percpu_timer_interrupt() for more + * information. + */ + ba,pt %xcc, 99f + nop + .align 64 +99: wr %g6, %g0, %pic + rd %pic, %g0 #endif wr %g0, ASI_P, %asi diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 1753728775f2..96360b010746 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -312,6 +312,13 @@ static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, un smp_processor_id(), data0, data1, data2, target); #endif again: + /* Ok, this is the real Spitfire Errata #54. + * One must read back from a UDB internal register + * after writes to the UDB interrupt dispatch, but + * before the membar Sync for that write. + * So we use the high UDB control register (ASI 0x7f, + * ADDR 0x20) for the dummy read. -DaveM + */ tmp = 0x40; __asm__ __volatile__(" wrpr %1, %2, %%pstate @@ -321,10 +328,13 @@ again: stxa %6, [%0+%8] %3 membar #Sync stxa %%g0, [%7] %3 + mov 0x20, %%g1 + ldxa [%%g1] 0x7f, %%g0 membar #Sync" : "=r" (tmp) : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W), - "r" (data0), "r" (data1), "r" (data2), "r" (target), "r" (0x10), "0" (tmp)); + "r" (data0), "r" (data1), "r" (data2), "r" (target), "r" (0x10), "0" (tmp) + : "g1"); /* NOTE: PSTATE_IE is still clear. */ stuck = 100000; diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 6e2d566b22b3..d3f02ae5407c 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1257,10 +1257,8 @@ asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, { int error = -EBADF; struct file * file; - struct inode * inode; struct readdir_callback32 buf; - lock_kernel(); file = fget(fd); if (!file) goto out; @@ -1268,22 +1266,16 @@ asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, buf.count = 0; buf.dirent = dirent; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, fillonedir); - up(&inode->i_sem); + lock_kernel(); + error = vfs_readdir(file, fillonedir, &buf); if (error < 0) goto out_putf; error = buf.count; out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } @@ -1328,12 +1320,10 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count) { struct file * file; - struct inode * inode; struct linux_dirent32 * lastdirent; struct getdents_callback32 buf; int error = -EBADF; - lock_kernel(); file = fget(fd); if (!file) goto out; @@ -1343,14 +1333,8 @@ asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, un buf.count = count; buf.error = 0; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, filldir); - up(&inode->i_sem); + lock_kernel(); + error = vfs_readdir(file, filldir, &buf); if (error < 0) goto out_putf; lastdirent = buf.previous; @@ -1360,9 +1344,9 @@ asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, un error = count - buf.count; } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index c5101248ab70..d977c7952efa 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -388,13 +388,11 @@ static int sunos_filldir(void * __buf, const char * name, int namlen, asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) { struct file * file; - struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; void *dirent = (void *)A(u_dirent); - lock_kernel(); if(fd >= SUNOS_NR_OPEN) goto out; @@ -402,9 +400,7 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) if(!file) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; + lock_kernel(); error = -EINVAL; if(cnt < (sizeof(struct sunos_dirent) + 255)) @@ -415,10 +411,7 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) buf.count = cnt; buf.error = 0; - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, sunos_filldir); - up(&inode->i_sem); + error = vfs_readdir(file, sunos_filldir, &buf); if (error < 0) goto out_putf; @@ -430,9 +423,9 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } @@ -481,12 +474,10 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, void *dirent = (void *) A(u_dirent); unsigned int *basep = (unsigned int *)A(u_basep); struct file * file; - struct inode * inode; struct sunos_direntry * lastdirent; int error = -EBADF; struct sunos_direntry_callback buf; - lock_kernel(); if(fd >= SUNOS_NR_OPEN) goto out; @@ -494,9 +485,7 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, if(!file) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; + lock_kernel(); error = -EINVAL; if(cnt < (sizeof(struct sunos_direntry) + 255)) @@ -507,10 +496,7 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, buf.count = cnt; buf.error = 0; - inode = file->f_dentry->d_inode; - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, sunos_filldirentry); - up(&inode->i_sem); + error = vfs_readdir(file, sunos_filldirentry, &buf); if (error < 0) goto out_putf; @@ -522,9 +508,9 @@ asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 24eef80b7c8d..a51d6ee15fdd 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -686,6 +686,7 @@ static void init_gendisk (ide_hwif_t *hwif) struct gendisk *gd, **gdp; unsigned int unit, units, minors; int *bs, *max_sect, *max_ra; + extern devfs_handle_t ide_devfs_handle; /* figure out maximum drive number on the interface */ for (units = MAX_DRIVES; units > 0; --units) { @@ -742,11 +743,11 @@ static void init_gendisk (ide_hwif_t *hwif) char name[64]; ide_add_generic_settings(hwif->drives + unit); - sprintf (name, "ide/host%d/bus%d/target%d/lun%d", - hwif->channel ? hwif->mate->index : hwif->index, + sprintf (name, "host%d/bus%d/target%d/lun%d", + (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index, hwif->channel, unit, 0); hwif->drives[unit].de = - devfs_mk_dir (NULL, name, 0, NULL); + devfs_mk_dir (ide_devfs_handle, name, 0, NULL); } } } diff --git a/drivers/block/ide.c b/drivers/block/ide.c index b820924524c0..987093e5615b 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -143,6 +143,7 @@ #include #include #include +#include #include #include @@ -3456,6 +3457,8 @@ EXPORT_SYMBOL(ide_spin_wait_hwgroup); /* * Probe module */ +devfs_handle_t ide_devfs_handle = NULL; + EXPORT_SYMBOL(ide_probe); EXPORT_SYMBOL(drive_is_flashcard); EXPORT_SYMBOL(ide_timer_expiry); @@ -3464,6 +3467,7 @@ EXPORT_SYMBOL(ide_fops); EXPORT_SYMBOL(ide_get_queue); EXPORT_SYMBOL(do_ide0_request); EXPORT_SYMBOL(ide_add_generic_settings); +EXPORT_SYMBOL(ide_devfs_handle); #if MAX_HWIFS > 1 EXPORT_SYMBOL(do_ide1_request); #endif /* MAX_HWIFS > 1 */ @@ -3545,6 +3549,7 @@ int __init ide_init (void) if (!banner_printed) { printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); + ide_devfs_handle = devfs_mk_dir (NULL, "ide", 3, NULL); banner_printed = 1; } @@ -3602,6 +3607,7 @@ void cleanup_module (void) #ifdef CONFIG_PROC_FS proc_ide_destroy(); #endif + devfs_unregister (ide_devfs_handle); } #else /* !MODULE */ diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 11f10b785426..92054676397c 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -197,7 +197,9 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c fi comment 'Video Adapters' - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI + if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT + fi dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 4eae5919654a..dd8fb35bd378 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -38,7 +38,7 @@ obj-y += tty_io.o n_tty.o tty_ioctl.o mem.o raw.o pty.o misc.o random.o export-objs := busmouse.o console.o i2c-old.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o videodev.o \ - tty_io.o + tty_io.o bttv.o KEYMAP =defkeymap.o KEYBD =pc_keyb.o @@ -194,13 +194,11 @@ else endif endif -obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o +obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda985x.o tea6300.o ifeq ($(CONFIG_VIDEO_BT848),y) -L_I2C=y L_TUNERS=y else ifeq ($(CONFIG_VIDEO_BT848),m) - L_I2C=m L_TUNERS=m endif endif diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 31f481065514..21a638fe2659 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -226,6 +226,7 @@ struct agp_bridge_data { #define AMD_MMBASE 0x14 #define AMD_APSIZE 0xac #define AMD_MODECNTL 0xb0 +#define AMD_MODECNTL2 0xb2 #define AMD_GARTENABLE 0x02 /* In mmio region (16-bit register) */ #define AMD_ATTBASE 0x04 /* In mmio region (32-bit register) */ #define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */ diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index c478395f8fdc..fc4312f64603 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -1449,6 +1449,9 @@ static int amd_irongate_configure(void) /* Write the Sync register */ pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); + + /* Set indexing mode */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x02); /* Write the enable register */ enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index c21198356048..82f545eccf01 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -3,7 +3,7 @@ Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999 Gerd Knorr + (c) 1999,2000 Gerd Knorr 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 @@ -20,6 +20,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include #include #include #include @@ -40,27 +42,28 @@ #include #include #include -#include #include #include -#include -#include -#include - +#ifdef LOCK_I2C_BUS +# error INSTALL ERROR +# error gcc uses the old, obsolete i2c.h include file. Please install the \ + new i2c stack. Please install it by patching the kernel, otherwise \ + gcc will not find the new header files. +#endif #include "bttv.h" #include "tuner.h" #define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ +#define IDEBUG(x) /* Debug interrupt handler */ #define MIN(a,b) (((a)>(b))?(b):(a)) #define MAX(a,b) (((a)>(b))?(a):(b)) /* Anybody who uses more than four? */ #define BTTV_MAX 4 -static void bt848_set_risc_jmps(struct bttv *btv); +static void bt848_set_risc_jmps(struct bttv *btv, int state); static int bttv_num; /* number of Bt848s in use */ static struct bttv bttvs[BTTV_MAX]; @@ -74,7 +77,20 @@ MODULE_PARM(card,"1-4i"); MODULE_PARM(pll,"1-4i"); MODULE_PARM(bigendian,"i"); MODULE_PARM(fieldnr,"i"); +MODULE_PARM(verbose,"i"); +MODULE_PARM(debug,"i"); MODULE_PARM(autoload,"i"); +MODULE_PARM(gbuffers,"i"); +MODULE_PARM(gbufsize,"i"); + +EXPORT_SYMBOL(bttv_get_id); +EXPORT_SYMBOL(bttv_gpio_enable); +EXPORT_SYMBOL(bttv_read_gpio); +EXPORT_SYMBOL(bttv_write_gpio); +EXPORT_SYMBOL(bttv_get_gpio_queue); + +MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards"); +MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); #if defined(__sparc__) || defined(__powerpc__) static unsigned int bigendian=1; @@ -87,7 +103,15 @@ static unsigned int radio[BTTV_MAX]; static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0}; static unsigned int fieldnr = 0; +static unsigned int verbose = 1; +static unsigned int debug = 0; +static unsigned int gbuffers = 2; +static unsigned int gbufsize = BTTV_MAX_FBUF; +#ifdef MODULE static unsigned int autoload = 1; +#else +static unsigned int autoload = 0; +#endif #define I2C_TIMING (0x7<<4) @@ -100,6 +124,101 @@ static unsigned int autoload = 1; #define BURSTOFFSET 76 +/* ----------------------------------------------------------------------- */ +/* Exported functions - for other modules which want to access the */ +/* gpio ports (IR for example) */ +/* see bttv.h for comments */ + +int bttv_get_id(unsigned int card) +{ + if (card >= bttv_num) { + return -1; + } + + return bttvs[card].type; +} + +int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + down(&btv->lock); + btaor(data, ~mask, BT848_GPIO_OUT_EN); + up(&btv->lock); + + return 0; +} + +int bttv_read_gpio(unsigned int card, unsigned long *data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + + if(btv->shutdown) { + return -ENODEV; + } + + down(&btv->lock); + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because we set direct input on init */ + + *data = btread(BT848_GPIO_DATA); + + up(&btv->lock); + + return 0; +} + +int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + + down(&btv->lock); + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because direct input is set on init */ + + btaor(data & mask, ~mask, BT848_GPIO_DATA); + + up(&btv->lock); + + return 0; +} + +WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return NULL; + } + + btv = &bttvs[card]; + + if (bttvs[card].shutdown) { + return NULL; + } + + return &btv->gpioq; +} + /*******************************/ /* Memory management functions */ /*******************************/ @@ -176,11 +295,11 @@ static inline unsigned long kvirt_to_pa(unsigned long adr) return ret; } -static void * rvmalloc(unsigned long size) +static void * rvmalloc(signed long size) { void * mem; unsigned long adr, page; - + mem=vmalloc(size); if (mem) { @@ -197,7 +316,7 @@ static void * rvmalloc(unsigned long size) return mem; } -static void rvfree(void * mem, unsigned long size) +static void rvfree(void * mem, signed long size) { unsigned long adr, page; @@ -227,7 +346,7 @@ static void rvfree(void * mem, unsigned long size) static int fbuffer_alloc(struct bttv *btv) { if(!btv->fbuffer) - btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); else printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", btv->nr); @@ -320,7 +439,8 @@ static int attach_inform(struct i2c_client *client) } if (btv->tuner_type != -1) call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); + if (verbose) + printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); return 0; } @@ -328,8 +448,9 @@ static int detach_inform(struct i2c_client *client) { struct bttv *btv = (struct bttv*)client->adapter->data; int i; - - printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); + + if (verbose) + printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); for (i = 0; i < I2C_CLIENTS_MAX; i++) { if (NULL != btv->i2c_clients[i] && btv->i2c_clients[i]->driver->id == client->driver->id) { @@ -395,19 +516,20 @@ static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) { unsigned char buffer = 0; - if (NULL != probe_for) + if (verbose && NULL != probe_for) printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", btv->nr,probe_for,addr); btv->i2c_client.addr = addr >> 1; if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { - if (NULL != probe_for) - printk("not found\n"); - else + if (NULL != probe_for) { + if (verbose) + printk("not found\n"); + } else printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", btv->nr,addr); return -1; } - if (NULL != probe_for) + if (verbose && NULL != probe_for) printk("found\n"); return buffer; } @@ -481,31 +603,70 @@ hauppauge_tuner[] = { TUNER_PHILIPS_PAL, "Philips FM1216" }, { TUNER_ABSENT, "Philips FM1216MF" }, { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_ABSENT, "Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_PAL, "Temic 4006FH5" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_ABSENT, "Temic 4039FR5" }, + { TUNER_ABSENT, "Philips FQ1216 ME" }, + { TUNER_TEMIC_PAL_I, "Temic 4066FY5" }, + { TUNER_ABSENT, "Philips TD1536" }, + { TUNER_ABSENT, "Philips TD1536D" }, + { TUNER_ABSENT, "Philips FMR1236" }, + { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_ABSENT, "Temic 4006FN5" }, + { TUNER_ABSENT, "Temic 4009FR5" }, + { TUNER_ABSENT, "Temic 4046FM5" }, }; static void hauppauge_eeprom(struct bttv *btv) { - readee(btv, eeprom_data, 0xa0); if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; - printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, - hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); + if (verbose) + printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, + hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); } } static void -hauppauge_msp_reset(struct bttv *btv) +hauppauge_boot_msp34xx(struct bttv *btv) { - /* Reset the MSP on some Hauppauge cards */ + int i; + + /* reset/enable the MSP on some Hauppauge cards */ /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */ - /* Can this hurt cards without one? What about Miros with MSP? */ btaor(32, ~32, BT848_GPIO_OUT_EN); btaor(0, ~32, BT848_GPIO_DATA); udelay(2500); btaor(32, ~32, BT848_GPIO_DATA); - /* btaor(0, ~32, BT848_GPIO_OUT_EN); */ + + if (verbose) + printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr); + + /* look if the msp3400 driver is already registered */ + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] != NULL && + btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) { + return; + } + } + + /* if not: look for the chip ... */ + if (I2CRead(btv, I2C_MSP3400, "MSP34xx")) { + /* ... if found re-register to trigger a i2c bus rescan, */ + /* this time with the msp34xx chip activated */ + i2c_bit_del_bus(&btv->i2c_adap); + i2c_bit_add_bus(&btv->i2c_adap); + } } @@ -528,7 +689,15 @@ static void init_PXC200(struct bttv *btv) /* GPIO inputs are pulled up, so no need to drive * reset pin any longer */ btwrite(0,BT848_GPIO_OUT_EN); - + + /* we could/should try and reset/control the AD pots? but + right now we simply turned off the crushing. Without + this the AGC drifts drifts + remember the EN is reverse logic --> + setting BT848_ADC_AGC_EN disable the AGC + tboult@eecs.lehigh.edu + */ + btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); /* Initialise MAX517 DAC */ printk(KERN_INFO "Setting DAC reference voltage level ...\n"); @@ -555,19 +724,34 @@ static struct VENDOR { int id; char *name; } vendors[] = { - { 0x0070, "Hauppauge" }, - { 0x144f, "Askey" }, + { 0x0001, "ATI Technologies Inc" }, + { 0x10b4, "STB Systems Inc" }, + { 0x13eb, "Hauppauge Computer Works Inc" }, + { 0x1461, "Avermedia" }, + { 0x1850, "Chronos" }, + { 0x1852, "Typhoon" }, + { 0x3000, "Askey" }, + { 0x3002, "Askey" }, + { 0x6606, "Leadtek" }, { -1, NULL } }; static struct CARD { - int id; int vid; + int id; int cardnr; char *name; } cards[] = { - { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV Theater" }, - { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" }, + { 0x0001, 0x1002, BTTV_HAUPPAUGE878, "TV Wonder" }, + { 0x10b4, 0x2636, BTTV_HAUPPAUGE878, "???" }, + { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV" }, + { 0x1461, 0x0002, BTTV_AVERMEDIA98, "TVCapture 98" }, + { 0x1850, 0x1851, BTTV_CHRONOS_VS2, "Video Shuttle II" }, + { 0x1852, 0x1852, BTTV_TYPHOON_TVIEW, "TView TV/FM Tuner" }, + { 0x3000, 0x14ff, BTTV_MAGICTVIEW061, "TView 99" }, + { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" }, + { 0x3002, 0x14ff, BTTV_PHOEBE_TVMAS, "TV Master" }, + { 0x6606, 0x217d, BTTV_WINFAST2000, "WinFast TV 2000" }, { -1, -1, -1, NULL } }; @@ -594,7 +778,7 @@ struct tvcard static struct tvcard tvcards[] = { /* 0x00 */ - { "unknown", + { " *** UNKNOWN *** ", 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, 1,1,1,1,0 }, { "MIRO PCTV", @@ -614,7 +798,7 @@ static struct tvcard tvcards[] = 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, 1,1,1,1,0 }, { "AVerMedia TVPhone", - 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0},0, + 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0, 1,1,1,1,0 }, { "MATRIX-Vision MV-Delta", 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, @@ -713,16 +897,32 @@ static struct tvcard tvcards[] = { "Terratec TerraTValue", 3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0, 1,1,1,1,0 }, + { "Leadtek WinFast 2000", + 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0}, + { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0, + 1,1,1,1,1 }, + { "Chronos Video Shuttle II", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0, + 1,1,1,1,0 }, + + { "Typhoon TView TV/FM Tuner", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0, + 1,1,1,1,0 }, + { "PixelView PlayTV pro", + 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 }, + { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 } }; #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) static void -dump_eeprom(struct bttv *btv, int addr) +dump_eeprom(struct bttv *btv,int addr) { - int i,id1,id2,n1,n2; + int i; + if (verbose < 2) + return; + /* for debugging: dump eeprom to syslog */ printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr); - readee(btv, eeprom_data,addr); for (i = 0; i < 256;) { printk(KERN_DEBUG " %02x:",i); do { @@ -730,35 +930,47 @@ dump_eeprom(struct bttv *btv, int addr) } while (i % 16); printk("\n"); } - id1 = (eeprom_data[252] << 8) | (eeprom_data[253]); - id2 = (eeprom_data[254] << 8) | (eeprom_data[255]); - if (id1 != 0 && id1 != 0xffff && - id2 != 0 && id2 != 0xffff) { - n1 = -1; - n2 = -1; - for (i = 0; vendors[i].id != -1; i++) - if (vendors[i].id == id2) - n2 = i; - for (i = 0; cards[i].id != -1; i++) - if (cards[i].id == id1 && - cards[i].vid == id2) - n1 = i; - if (n1 != -1 && n2 != -1) { - printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n", - cards[n1].name,id1,vendors[n2].name,id2); - printk(KERN_INFO " => card=%d (%s)\n", - cards[n1].cardnr,tvcards[cards[n1].cardnr].name); -#if 1 - /* not yet, but that's the plan for autodetect... */ - btv->type = cards[n1].cardnr; -#endif - } else { - printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n", - (n1 != -1) ? cards[n1].name : "unknown", id1, - (n2 != -1) ? vendors[n2].name : "unknown", id2); - printk(KERN_INFO " please mail card type, id + vendor to "); - printk(" kraxel@goldbach.in-berlin.de\n"); - } +} + +static int +idcard_eeprom(struct bttv *btv) +{ + int i,id1,id2,n1,n2; + + id1 = (eeprom_data[254] << 8) | (eeprom_data[255]); + id2 = (eeprom_data[252] << 8) | (eeprom_data[253]); + if (id1 == 0 || id1 == 0xffff || + id2 == 0 || id2 == 0xffff) + return -1; + + /* look for the card */ + n1 = -1; n2 = -1; + for (i = 0; vendors[i].id != -1; i++) + if (vendors[i].id == id2) + n2 = i; + for (i = 0; cards[i].id != -1; i++) + if (cards[i].id == id1 && + cards[i].vid == id2) + n1 = i; + + if (n1 != -1 && n2 != -1) { + /* found it */ + printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n", + btv->nr,cards[n1].name,id1,vendors[n2].name,id2); + if (verbose) + printk(KERN_INFO "bttv%d: => card=%d (%s)\n", + btv->nr,cards[n1].cardnr, + tvcards[cards[n1].cardnr].name); + return cards[n1].cardnr; + } else { + /* 404 */ + printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n", + btv->nr, "unknown", id1, + (n2 != -1) ? vendors[n2].name : "unknown", id2); + printk(KERN_INFO "please mail id + vendor, board name and " + "the correct card= insmod option to " + "kraxel@goldbach.in-berlin.de\n"); + return -1; } } @@ -810,21 +1022,6 @@ extern inline void bt848_dma(struct bttv *btv, uint state) } -static void bt848_cap(struct bttv *btv, uint state) -{ - if (state) - { - btv->cap|=3; - bt848_set_risc_jmps(btv); - } - else - { - btv->cap&=~3; - bt848_set_risc_jmps(btv); - } -} - - /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/ /* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C @@ -885,9 +1082,10 @@ static int set_pll(struct bttv *btv) /* printk("bttv%d: PLL: no change required\n",btv->nr); */ return 1; } - - printk("bttv%d: PLL: %d => %d ... ",btv->nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); + + if (verbose) + printk("bttv%d: PLL: %d => %d ... ",btv->nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); @@ -907,13 +1105,15 @@ static int set_pll(struct bttv *btv) { btwrite(0x08,BT848_TGCTRL); btv->pll.pll_current = btv->pll.pll_ofreq; - printk("ok\n"); + if (verbose) + printk("ok\n"); return 1; } mdelay(10); } btv->pll.pll_current = 0; - printk("oops\n"); + if (verbose) + printk("oops\n"); return -1; } @@ -1010,10 +1210,9 @@ static void make_vbitab(struct bttv *btv) unsigned int *po=(unsigned int *) btv->vbi_odd; unsigned int *pe=(unsigned int *) btv->vbi_even; - DEBUG(printk(KERN_DEBUG "vbiodd: 0x%lx\n",(long)btv->vbi_odd)); - DEBUG(printk(KERN_DEBUG "vbievn: 0x%lx\n",(long)btv->vbi_even)); - DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po)); - DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); + if (debug) + printk("bttv%d: vbi: po=%08lx pe=%08lx\n", + btv->nr,virt_to_bus(po), virt_to_bus(pe)); *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; for (i=0; i<16; i++) @@ -1036,11 +1235,11 @@ static void make_vbitab(struct bttv *btv) DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); } -int fmtbppx2[16] = { +static int fmtbppx2[16] = { 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 }; -int palette2fmt[] = { +static int palette2fmt[] = { 0, BT848_COLOR_FMT_Y8, BT848_COLOR_FMT_RGB8, @@ -1082,7 +1281,7 @@ static int make_rawrisctab(struct bttv *btv, unsigned int *ro, *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); - *(re++)=cpu_to_le32(kvirt_to_bus(vadr+BTTV_MAX_FBUF/2)); + *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2)); vadr+=bpl; } @@ -1108,6 +1307,9 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, unsigned long vadr=(unsigned long) vbuf; int shift, csize; + if (debug) + printk("bttv%d: prisc: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); switch(fmt) { @@ -1140,7 +1342,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, } cbadr=vadr+(width*height); cradr=cbadr+csize; - inter = (height>btv->win.cropheight/2) ? 1 : 0; + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0; @@ -1158,7 +1360,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, if (inter) rp= (line&1) ? &re : &ro; else - rp= (line>=height) ? &re : &ro; + rp= (line>=height) ? &ro : &re; if(line&lmask) @@ -1222,9 +1424,12 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, return make_rawrisctab(btv, ro, re, vbuf); if (palette>=VIDEO_PALETTE_PLANAR) return make_prisctab(btv, ro, re, vbuf, width, height, palette); - - - inter = (height>btv->win.cropheight/2) ? 1 : 0; + + if (debug) + printk("bttv%d: vrisc: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); @@ -1237,7 +1442,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, if (inter) rp= (line&1) ? &re : &ro; else - rp= (line>=height) ? &re : &ro; + rp= (line>=height) ? &ro : &re; bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); if (bpl<=bl) @@ -1335,32 +1540,31 @@ static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) { - int i, line, x, y, bpl, width, height, inter; + int i, line, x, y, bpl, width, height, inter, maxw; unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len; unsigned long adr; - unsigned char *clipmap, cbit, lastbit, outofmem; + unsigned char *clipmap, *clipline, cbit, lastbit, outofmem; - if (btv->win.use_yuv) { - /* yuv-to-offscreen (BT848_COLOR_FMT_YUY2) */ - bpp = 2; - bpl = btv->win.win2.pitch; - adr = btv->win.vidadr + btv->win.win2.start; - } else { - bpp=btv->win.bpp; - if (bpp==15) /* handle 15bpp as 16bpp in calculations */ - bpp++; - bpl=btv->win.bpl; - adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; - } + /* take care: bpp != btv->win.bpp is allowed here */ + bpp = fmtbppx2[btv->win.color_fmt&0xf]/2; + bpl=btv->win.bpl; + adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl; inter=(btv->win.interlace&1)^1; width=btv->win.width; height=btv->win.height; + if (debug) + printk("bttv%d: make_clip: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + btv->nr,btv->picture.palette,width,height,bpl,bpp); if(width > 1023) width = 1023; /* sanity check */ if(height > 625) height = 625; /* sanity check */ - ro=btv->risc_odd; - re=btv->risc_even; + ro=btv->risc_scr_odd; + re=btv->risc_scr_even; + + if (debug) + printk("bttv%d: clip: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ @@ -1380,16 +1584,15 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) /* clip against viewing window AND screen so we do not have to rely on the user program */ - if (!btv->win.use_yuv) { - clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? - (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); - clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? - (btv->win.sheight-btv->win.y) : height,1024,768); - if (btv->win.x<0) - clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); - if (btv->win.y<0) - clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); - } + maxw = (bpl - btv->win.x * btv->win.bpp) / bpp; + clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width, + 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? + (btv->win.sheight-btv->win.y) : height,1024,768); + if (btv->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); + if (btv->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=cpu_to_le32(0); @@ -1401,12 +1604,30 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) { y = line>>inter; rp= (line&1) ? &re : &ro; - lastbit=(clipmap[y<<7]&1); - for(x=dx=1,sx=0; x<=width && !outofmem; x++) { - cbit = (clipmap[(y<<7)+(x>>3)] & (1<<(x&7))); - if (x < width && !lastbit == !cbit) + clipline = clipmap + (y<<7); /* running pointers ... */ + lastbit = *clipline & 1; + for(x=dx=0,sx=0; x<=width && !outofmem;) { + if (0 == (x&7)) { + /* check bytes not bits if we can ... */ + if (lastbit) { + while (0xff==*clipline && xrisc_odd > RISCMEM_LEN/2 - 16) + if (ro - btv->risc_scr_odd>RISCMEM_LEN/2 - 16) outofmem++; - if (re - btv->risc_even > RISCMEM_LEN/2 - 16) + if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16) outofmem++; } + x++; + if (0 == (x&7)) + clipline++; } if ((!inter)||(line&1)) adr+=bpl; @@ -1475,29 +1699,25 @@ static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc, } -static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, - u16 fmt, int no_irq_context) +static void bt848_set_geo(struct bttv *btv, + int no_irq_context) { u16 vscale, hscale; u32 xsf, sr; - u16 hdelay, vdelay; - u16 hactive, vactive; + u16 ewidth, eheight, owidth, oheight; + u16 format, bswap; + u16 hdelay; + u16 hactive; u16 inter; u8 crop, vtc; struct tvnorm *tvn; unsigned long flags; - if (!width || !height) - return; - save_flags(flags); cli(); tvn=&tvnorms[btv->win.norm]; - btv->win.cropheight=tvn->sheight; - btv->win.cropwidth=tvn->swidth; - btwrite(tvn->adelay, BT848_ADELAY); btwrite(tvn->bdelay, BT848_BDELAY); btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); @@ -1508,59 +1728,84 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, if (no_irq_context) set_pll(btv); - btwrite(fmt, BT848_COLOR_FMT); - if (bigendian && - fmt == BT848_COLOR_FMT_RGB32) { - btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_WSWAP_ODD | - BT848_COLOR_CTL_WSWAP_EVEN | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } else if (bigendian && - (fmt == BT848_COLOR_FMT_RGB16 || - fmt == BT848_COLOR_FMT_RGB15)) { - btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } else { - btwrite(0x10, BT848_COLOR_CTL); - } - hactive=width; - vtc=0; /* Some people say interpolation looks bad ... */ /* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */ - btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0; - inter=(btv->win.interlace&1)^1; - vdelay=btv->win.cropy+tvn->vdelay; - - xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth; - hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; + + if (0 == btv->risc_cap_odd && + 0 == btv->risc_cap_even) { + /* overlay only */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->win.width; + eheight = btv->win.height; + format = btv->win.color_fmt; + bswap = btv->fb_color_ctl; + } else if (-1 != btv->gq_grab && + 0 == btv->risc_cap_odd && + !btv->win.interlace && + btv->scr_on) { + /* odd field -> overlay, even field -> capture */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = (btv->win.color_fmt & 0xf0) | + (btv->gbuf[btv->gq_grab].fmt & 0x0f); + bswap = btv->fb_color_ctl & 0x0a; + } else { + /* capture only */ + owidth = btv->gbuf[btv->gq_grab].width; + oheight = btv->gbuf[btv->gq_grab].height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = btv->gbuf[btv->gq_grab].fmt; + bswap = 0; + inter = (btv->win.height>tvn->sheight/2) ? 0 : 1; + } - hdelay=tvn->hdelayx1+btv->win.cropx; - hdelay=(hdelay*hactive)/btv->win.cropwidth; - hdelay&=0x3fe; + inter = (oheight>tvn->sheight/2) ? 0 : 1; - sr=((btv->win.cropheight>>inter)*512)/height-512; + /* odd field */ + hactive=owidth; + xsf = (hactive*tvn->scaledtwidth)/tvn->swidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + hdelay = tvn->hdelayx1; + hdelay = (hdelay*hactive)/tvn->swidth; + hdelay &= 0x3fe; + sr=((tvn->sheight>>inter)*512)/oheight-512; vscale=(0x10000UL-sr)&0x1fff; - vactive=btv->win.cropheight; crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| - ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); - vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); + vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, tvn->sheight, + hdelay, tvn->vdelay, crop); + + /* even field */ + hactive=ewidth; + xsf = (hactive*tvn->scaledtwidth)/tvn->swidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + hdelay = tvn->hdelayx1; + hdelay = (hdelay*hactive)/tvn->swidth; + hdelay &= 0x3fe; + sr=((tvn->sheight>>inter)*512)/eheight-512; + vscale=(0x10000UL-sr)&0x1fff; + crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| + ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); + vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, tvn->sheight, + hdelay, tvn->vdelay, crop); - bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive, - hdelay, vdelay, crop); - bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive, - hdelay, vdelay, crop); + btwrite(format, BT848_COLOR_FMT); + btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); restore_flags(flags); } -int bpp2fmt[4] = { +static int bpp2fmt[4] = { BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 }; @@ -1569,14 +1814,31 @@ static void bt848_set_winsize(struct bttv *btv) { unsigned short format; - if (btv->win.use_yuv) { - /* yuv-to-offscreen */ - format = BT848_COLOR_FMT_YUY2; + if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { + /* format set by VIDIOCSPICT */ + format = palette2fmt[btv->picture.palette]; } else { + /* use default for the given color depth */ format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : bpp2fmt[(btv->win.bpp-1)&3]; } btv->win.color_fmt = format; + if (bigendian && + format == BT848_COLOR_FMT_RGB32) { + btv->fb_color_ctl = + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else if (bigendian && + (format == BT848_COLOR_FMT_RGB16 || + format == BT848_COLOR_FMT_RGB15)) { + btv->fb_color_ctl = + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else { + btv->fb_color_ctl = 0; + } /* RGB8 seems to be a 9x5x5 GRB color cube starting at * color 16. Why the h... can't they even mention this in the @@ -1590,38 +1852,8 @@ static void bt848_set_winsize(struct bttv *btv) else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - bt848_set_geo(btv, btv->win.width, btv->win.height, format,1); -} - -/* - * Set TSA5522 synthesizer frequency in 1/16 Mhz steps - */ - -#if 0 -static void set_freq(struct bttv *btv, unsigned short freq) -{ - int naudio; - int fixme = freq; /* XXX */ - /* int oldAudio = btv->audio; */ - - /* mute */ - AUDIO(AUDC_SWITCH_MUTE,0); - - /* tune */ - if (btv->radio) { - TUNER(TUNER_SET_RADIOFREQ,&fixme); - } else { - TUNER(TUNER_SET_TVFREQ,&fixme); - } - - if (btv->radio) { - AUDIO(AUDC_SET_RADIO,0); - } else { - AUDIO(AUDC_SET_TVNORM,&(btv->win.norm)); - AUDIO(AUDC_NEWCHANNEL,0); - } + bt848_set_geo(btv,1); } -#endif /* @@ -1639,30 +1871,19 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) if(fbuffer_alloc(btv)) return -ENOBUFS; } - if(btv->grabbing >= MAX_GBUFFERS) - return -ENOBUFS; - - /* - * No grabbing past the end of the buffer! - */ - - if(mp->frame>(MAX_GBUFFERS-1) || mp->frame <0) + + if(mp->frame >= gbuffers || mp->frame < 0) return -EINVAL; + if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) + return -EBUSY; if(mp->height <0 || mp->width <0) return -EINVAL; - -/* This doesn´t work like this for NTSC anyway. - So, better check the total image size ... -*/ -/* - if(mp->height>576 || mp->width>768+BURSTOFFSET) - return -EINVAL; -*/ if (mp->format >= PALETTEFMT_MAX) return -EINVAL; + if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 - > BTTV_MAX_FBUF) + > gbufsize) return -EINVAL; if(-1 == palette2fmt[mp->format]) return -EINVAL; @@ -1677,41 +1898,40 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) * Ok load up the BT848 */ - vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame); -/* if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) - return -EAGAIN;*/ - ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0); + vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); + ro=btv->gbuf[mp->frame].risc; re=ro+2048; make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); - /* bt848_set_risc_jmps(btv); */ + + if (debug) + printk("bttv%d: cap vgrab: queue %d\n",btv->nr,mp->frame); cli(); - btv->frame_stat[mp->frame] = GBUFFER_GRABBING; - if (btv->grabbing) { - btv->gfmt_next=palette2fmt[mp->format]; - btv->gwidth_next=mp->width; - btv->gheight_next=mp->height; - btv->gro_next=virt_to_bus(ro); - btv->gre_next=virt_to_bus(re); - btv->grf_next=mp->frame; - } else { - btv->gfmt=palette2fmt[mp->format]; - btv->gwidth=mp->width; - btv->gheight=mp->height; - btv->gro=virt_to_bus(ro); - btv->gre=virt_to_bus(re); - btv->grf=mp->frame; - } - if (!(btv->grabbing++)) { + btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; + btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; + btv->gbuf[mp->frame].width = mp->width; + btv->gbuf[mp->frame].height = mp->height; + btv->gbuf[mp->frame].ro = virt_to_bus(ro); + btv->gbuf[mp->frame].re = virt_to_bus(re); + +#if 1 + if (mp->height <= tvnorms[btv->win.norm].sheight/2 && + mp->format != VIDEO_PALETTE_RAW) + btv->gbuf[mp->frame].ro = 0; +#endif + + if (btv->gq_in == btv->gq_out) { if(mp->format>=VIDEO_PALETTE_COMPONENT) { btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI); } btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } + btv->gqueue[btv->gq_in++] = mp->frame; + btv->gq_in = btv->gq_in % MAX_GBUFFERS; + sti(); btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); - /* interruptible_sleep_on(&btv->capq); */ return 0; } @@ -1787,16 +2007,16 @@ static int bttv_open(struct video_device *dev, int flags) if (btv->user) goto out_unlock; - btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); ret = -ENOMEM; if (!btv->fbuffer) goto out_unlock; - btv->grabbing = 0; - btv->grab = 0; - btv->lastgrab = 0; - for (i = 0; i < MAX_GBUFFERS; i++) - btv->frame_stat[i] = GBUFFER_UNUSED; + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; + for (i = 0; i < gbuffers; i++) + btv->gbuf[i].stat = GBUFFER_UNUSED; burst(0); btv->user++; @@ -1815,8 +2035,10 @@ static void bttv_close(struct video_device *dev) down(&btv->lock); btv->user--; - btv->cap&=~3; - bt848_set_risc_jmps(btv); + btv->scr_on = 0; + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); /* * A word of warning. At this point the chip @@ -1841,7 +2063,7 @@ static void bttv_close(struct video_device *dev) */ if(btv->fbuffer) - rvfree((void *) btv->fbuffer, MAX_GBUFFERS*BTTV_MAX_FBUF); + rvfree((void *) btv->fbuffer, gbuffers*gbufsize); btv->fbuffer=0; up(&btv->lock); MOD_DEC_USE_COUNT; @@ -1901,7 +2123,9 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data) static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct bttv *btv=(struct bttv *)dev; - int i; + int i,ret; + + if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); switch (cmd) { case VIDIOCGCAP: @@ -2021,17 +2245,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case VIDIOCGPICT: { struct video_picture p=btv->picture; - if(btv->win.depth==8) - p.palette=VIDEO_PALETTE_HI240; - if(btv->win.depth==15) - p.palette=VIDEO_PALETTE_RGB555; - if(btv->win.depth==16) - p.palette=VIDEO_PALETTE_RGB565; - if(btv->win.depth==24) - p.palette=VIDEO_PALETTE_RGB24; - if(btv->win.depth==32) - p.palette=VIDEO_PALETTE_RGB32; - if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; @@ -2041,6 +2254,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) struct video_picture p; if(copy_from_user(&p, arg,sizeof(p))) return -EFAULT; + if (p.palette > PALETTEFMT_MAX) + return -EINVAL; down(&btv->lock); /* We want -128 to 127 we get 0-65535 */ bt848_bright(btv, (p.brightness>>8)-128); @@ -2059,7 +2274,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct video_window vw; struct video_clip *vcp = NULL; - int on; if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; @@ -2067,25 +2281,24 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if(vw.flags || vw.width < 16 || vw.height < 16) { down(&btv->lock); - bt848_cap(btv,0); + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return -EINVAL; - } + } if (btv->win.bpp < 4) { /* adjust and align writes */ vw.x = (vw.x + 3) & ~3; vw.width &= ~3; } down(&btv->lock); - btv->win.use_yuv=0; btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; btv->win.height=vw.height; - on=(btv->cap&3); - - bt848_cap(btv,0); + bt848_set_risc_jmps(btv,0); + bt848_set_winsize(btv); up(&btv->lock); @@ -2115,39 +2328,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) make_clip_tab(btv, vcp, vw.clipcount); if (vw.clipcount != 0) vfree(vcp); - if(on && btv->win.vidadr!=0) - bt848_cap(btv,1); - up(&btv->lock); - return 0; - } - case VIDIOCSWIN2: - { - /* experimental -- right now it handles unclipped yuv data only */ - struct video_window2 vo; - __u32 fbsize; - int on; - - if(copy_from_user(&vo,arg,sizeof(vo))) - return -EFAULT; - - fbsize = btv->win.sheight * btv->win.bpl; - if (vo.start + vo.pitch*vo.height > fbsize) - return -EINVAL; - if (vo.palette != VIDEO_PALETTE_YUV422) - return -EINVAL; - - down(&btv->lock); - btv->win.use_yuv=1; - memcpy(&btv->win.win2,&vo,sizeof(vo)); - btv->win.width=vo.width; - btv->win.height=vo.height; - - on=(btv->cap&3); - bt848_cap(btv,0); - bt848_set_winsize(btv); - make_clip_tab(btv, NULL, 0); - if(on && btv->win.vidadr!=0) - bt848_cap(btv,1); + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return 0; } @@ -2174,13 +2355,14 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) return -EFAULT; if(btv->win.vidadr == 0) return -EINVAL; - if (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0)) + if (btv->win.width==0 || btv->win.height==0) return -EINVAL; down(&btv->lock); - if(v==0) - bt848_cap(btv,0); - else - bt848_cap(btv,1); + if (v == 1 && btv->win.vidadr != 0) + btv->scr_on = 1; + if (v == 0) + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return 0; } @@ -2217,9 +2399,19 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) btv->win.bpp=((v.depth+7)&0x38)/8; btv->win.depth=v.depth; btv->win.bpl=v.bytesperline; - - DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", - v.base, v.width,v.height, btv->win.bpp, btv->win.bpl)); + + /* set sefault color format */ + switch (btv->win.bpp) { + case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break; + case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break; + case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break; + case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break; + case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break; + } + + if (debug) + printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", + v.base, v.width,v.height, btv->win.bpp, btv->win.bpl); bt848_set_winsize(btv); up(&btv->lock); return 0; @@ -2273,19 +2465,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) v.step = 4096; } -#if 0 -#warning this should be handled by tda9855.c - else if (btv->audio_chip == TDA9850) { - unsigned char ALR1; - v.flags|=VIDEO_AUDIO_VOLUME; - ALR1 = I2CRead(btv, I2C_TDA9850|1); - v.mode = VIDEO_SOUND_MONO; - v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; - v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0; - v.volume = 32768; /* fixme */ - v.step = 4096; - } -#endif if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; @@ -2354,23 +2533,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) udelay(10); data &= ~WINVIEW_PT2254_STROBE; btwrite(data, BT848_GPIO_DATA); - -#if 0 -#warning this should be handled by tda9855.c - } else if (btv->audio_chip == TDA9850) { - unsigned char con3 = 0; - if (v.mode & VIDEO_SOUND_LANG1) - con3 = 0x80; /* sap */ - if (v.mode & VIDEO_SOUND_STEREO) - con3 = 0x40; /* stereo */ - I2CWrite(btv, I2C_TDA9850, - TDA9850_CON3, con3, 1); - if (v.flags & VIDEO_AUDIO_VOLUME) - I2CWrite(btv, I2C_TDA9850, - TDA9850_CON4, - (v.volume>>12) & 15, 1); -#endif } + btv->audio_dev=v; up(&btv->lock); return 0; @@ -2379,19 +2543,27 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case VIDIOCSYNC: if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; - switch (btv->frame_stat[i]) { + if (i < 0 || i >= gbuffers) + return -EINVAL; + switch (btv->gbuf[i].stat) { case GBUFFER_UNUSED: return -EINVAL; case GBUFFER_GRABBING: - while(btv->frame_stat[i]==GBUFFER_GRABBING) { + while(btv->gbuf[i].stat==GBUFFER_GRABBING) { + if (debug) + printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); interruptible_sleep_on(&btv->capq); if(signal_pending(current)) return -EINTR; } - /* fall */ + /* fall throuth */ case GBUFFER_DONE: - btv->frame_stat[i] = GBUFFER_UNUSED; - break; + case GBUFFER_ERROR: + ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0; + if (debug) + printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); + btv->gbuf[i].stat = GBUFFER_UNUSED; + return ret; } return 0; @@ -2422,8 +2594,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) int ret; if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) return -EFAULT; - if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) - return -EBUSY; down(&btv->lock); ret = vgrab(btv, &vm); up(&btv->lock); @@ -2434,10 +2604,10 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct video_mbuf vm; memset(&vm, 0 , sizeof(vm)); - vm.size=BTTV_MAX_FBUF*MAX_GBUFFERS; - vm.frames=MAX_GBUFFERS; - vm.offsets[0]=0; - vm.offsets[1]=BTTV_MAX_FBUF; + vm.size=gbufsize*gbuffers; + vm.frames=gbuffers; + for (i = 0; i < gbuffers; i++) + vm.offsets[i]=i*gbufsize; if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; return 0; @@ -2510,7 +2680,7 @@ static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size) unsigned long start=(unsigned long) adr; unsigned long page,pos; - if (size>2*BTTV_MAX_FBUF) + if (size>gbuffers*gbufsize) return -EINVAL; if (!btv->fbuffer) { if(fbuffer_alloc(btv)) @@ -2623,8 +2793,8 @@ static int vbi_open(struct video_device *dev, int flags) down(&btv->lock); btv->vbip=VBIBUF_SIZE; - btv->cap|=0x0c; - bt848_set_risc_jmps(btv); + btv->vbi_on = 1; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); MOD_INC_USE_COUNT; @@ -2636,8 +2806,8 @@ static void vbi_close(struct video_device *dev) struct bttv *btv=(struct bttv *)(dev-2); down(&btv->lock); - btv->cap&=~0x0c; - bt848_set_risc_jmps(btv); + btv->vbi_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); MOD_DEC_USE_COUNT; @@ -2875,26 +3045,12 @@ static void init_tda9840(struct bttv *btv) 7a - external */ } - -#if 0 -#warning this should be handled by tda9855.c -static void init_tda9850(struct bttv *btv) -{ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI3, 0x03, 1); -} -#endif - /* Figure out card and tuner type */ static void idcard(int i) { struct bttv *btv = &bttvs[i]; + int type,eeprom = 0; btwrite(0, BT848_GPIO_OUT_EN); DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA))); @@ -2903,40 +3059,36 @@ static void idcard(int i) if (card[i] >= 0 && card[i] < TVCARDS) btv->type=card[i]; - /* If we were asked to auto-detect, then do so! - Right now this will only recognize Miro, Hauppauge or STB - */ - if (btv->type == BTTV_UNKNOWN) - { - if (I2CRead(btv, I2C_HAUPEE, "eeprom")>=0) - { - if(btv->id>849) - btv->type=BTTV_HAUPPAUGE878; - else + /* If we were asked to auto-detect, then do so! */ + if (btv->type == BTTV_UNKNOWN) { + + /* many bt878 cards have a eeprom @ 0xa0 => read ID + and try to identify it */ + if (I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) { + eeprom = 0xa0; + readee(btv,eeprom_data,0xa0); + dump_eeprom(btv,0xa0); /* DEBUG */ + type = idcard_eeprom(btv); + if (-1 != type) { + btv->type = type; + } else if (btv->id <= 849) { + /* for unknown bt848, assume old Hauppauge */ btv->type=BTTV_HAUPPAUGE; + } + /* STB cards have a eeprom @ 0xae */ } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) { btv->type=BTTV_STB; + } -#if 0 /* bad idea: 0xc0 is used for the tuner on _many_ boards */ - } else if (I2CRead(btv, I2C_VHX)>=0) { - btv->type=BTTV_VHX; -#endif - - } else { - if (I2CRead(btv, 0x80, "msp3400")>=0) /* check for msp34xx */ +#if 0 + /* check for msp34xx */ + if (I2CRead(btv, 0x80, "msp3400")>=0) btv->type = BTTV_MIROPRO; else - btv->type = BTTV_MIRO; - } - } - -#if 1 - /* DEBUG: dump eeprom content if available */ - if (I2CRead(btv, 0xa0, "eeprom")>=0) { - dump_eeprom(btv,0xa0); - } + btv->type = BTTV_MIRO; #endif + } /* print which board we have found */ printk(KERN_INFO "bttv%d: model: ",btv->nr); @@ -2955,8 +3107,12 @@ static void idcard(int i) btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; } if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { - hauppauge_msp_reset(btv); + if (0xa0 != eeprom) { + eeprom = 0xa0; + readee(btv,eeprom_data,0xa0); + } hauppauge_eeprom(btv); + hauppauge_boot_msp34xx(btv); } if (btv->type == BTTV_MAXI) { /* PHILIPS FI1216MK2 tuner (PAL/SECAM) */ @@ -2973,7 +3129,11 @@ static void idcard(int i) btv->type == BTTV_CONFERENCETV || btv->type == BTTV_PIXVIEWPLAYTV || btv->type == BTTV_AVERMEDIA98 || - btv->type == BTTV_MAGICTVIEW061) { + btv->type == BTTV_MAGICTVIEW061 || + btv->type == BTTV_CHRONOS_VS2 || + btv->type == BTTV_TYPHOON_TVIEW || + btv->type == BTTV_PXELVWPLTVPRO || + btv->type == BTTV_WINFAST2000) { btv->pll.pll_ifreq=28636363; btv->pll.pll_crystal=BT848_IFORM_XT0; } @@ -3005,7 +3165,7 @@ static void idcard(int i) if (tvcards[btv->type].tda985x && I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { if (autoload) - request_module("tda9855"); + request_module("tda985x"); } if (tvcards[btv->type].tea63xx /* && @@ -3023,9 +3183,19 @@ static void idcard(int i) } -static void bt848_set_risc_jmps(struct bttv *btv) +static void bt848_set_risc_jmps(struct bttv *btv, int flags) { - int flags=btv->cap; + if (-1 == flags) { + /* defaults */ + flags = 0; + if (btv->scr_on) + flags |= 0x03; + if (btv->vbi_on) + flags |= 0x0c; + } + + if (debug) printk("bttv%d: set_risc_jmp %08lx:", + btv->nr,virt_to_bus(btv->risc_jmp)); /* Sync to start of odd field */ btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC @@ -3034,17 +3204,27 @@ static void bt848_set_risc_jmps(struct bttv *btv) /* Jump to odd vbi sub */ btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); - if (flags&8) + if (flags&8) { + if (debug) printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); - else + } else { + if (debug) printk(" -----------"); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); + } /* Jump to odd sub */ btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); - if (flags&2) - btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd)); - else + if (0 != btv->risc_cap_odd) { + if (debug) printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); + flags |= 3; + btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); + } else if (flags&2) { + if (debug) printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); + } else { + if (debug) printk(" -----------"); btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); + } /* Sync to start of even field */ @@ -3054,22 +3234,34 @@ static void bt848_set_risc_jmps(struct bttv *btv) /* Jump to even vbi sub */ btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); - if (flags&4) + if (flags&4) { + if (debug) printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); - else + } else { + if (debug) printk(" -----------"); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + } /* Jump to even sub */ btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); - if (flags&1) - btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even)); - else + if (0 != btv->risc_cap_even) { + if (debug) printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); + flags |= 3; + btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); + } else if (flags&1) { + if (debug) printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); + } else { + if (debug) printk(" -----------"); btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); + } btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); /* enable cpaturing and DMA */ + if (debug) printk(" flags=0x%x dma=%s\n", + flags,(flags&0x0f) ? "on" : "off"); btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); @@ -3110,24 +3302,29 @@ init_video_dev(struct bttv *btv) static int init_bt848(int i) { struct bttv *btv = &bttvs[i]; + int j; btv->user=0; init_MUTEX(&btv->lock); -#if 0 /* dump current state of the gpio registers before changing them, * might help to make a new card work */ - printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", - i, - btread(BT848_GPIO_OUT_EN), - btread(BT848_GPIO_DATA), - btread(BT848_GPIO_REG_INP)); -#endif + if (verbose >= 2) + printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", + i, + btread(BT848_GPIO_OUT_EN), + btread(BT848_GPIO_DATA), + btread(BT848_GPIO_REG_INP)); /* reset the bt848 */ btwrite(0, BT848_SRESET); DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem)); + /* not registered yet */ + btv->video_dev.minor = -1; + btv->radio_dev.minor = -1; + btv->vbi_dev.minor = -1; + /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ btv->win.interlace=1; @@ -3135,10 +3332,6 @@ static int init_bt848(int i) btv->win.y=0; btv->win.width=768; /* 640 */ btv->win.height=576; /* 480 */ - btv->win.cropwidth=768; /* 640 */ - btv->win.cropheight=576; /* 480 */ - btv->win.cropx=0; - btv->win.cropy=0; btv->win.bpp=2; btv->win.depth=16; btv->win.color_fmt=BT848_COLOR_FMT_RGB16; @@ -3146,27 +3339,24 @@ static int init_bt848(int i) btv->win.swidth=1024; btv->win.sheight=768; btv->win.vidadr=0; - btv->cap=0; + btv->vbi_on=0; + btv->scr_on=0; - btv->gmode=0; - btv->risc_odd=0; - btv->risc_even=0; + btv->risc_scr_odd=0; + btv->risc_scr_even=0; + btv->risc_cap_odd=0; + btv->risc_cap_even=0; btv->risc_jmp=0; btv->vbibuf=0; - btv->grisc=0; - btv->grabbing=0; - btv->grabcount=0; - btv->grab=0; - btv->lastgrab=0; btv->field=btv->last_field=0; /* i2c */ btv->tuner_type=-1; init_bttv_i2c(btv); - if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; - if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) return -1; @@ -3180,9 +3370,13 @@ static int init_bt848(int i) btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE); if (!btv->vbibuf) return -1; - if (!(btv->grisc=(unsigned int *) kmalloc(32768, GFP_KERNEL))) + if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) return -1; - + for (j = 0; j < gbuffers; j++) { + if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL))) + return -1; + } + memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random memory to the user */ @@ -3194,7 +3388,14 @@ static int init_bt848(int i) /* btwrite(0, BT848_TDEC); */ btwrite(0x10, BT848_COLOR_CTL); btwrite(0x00, BT848_CAP_CTL); - btwrite(0xac, BT848_GPIO_DMA_CTL); + /* set planar and packed mode trigger points and */ + /* set rising edge of inverted GPINTR pin as irq trigger */ + btwrite(BT848_GPIO_DMA_CTL_PKTP_32| + BT848_GPIO_DMA_CTL_PLTP1_16| + BT848_GPIO_DMA_CTL_PLTP23_16| + BT848_GPIO_DMA_CTL_GPINTC| + BT848_GPIO_DMA_CTL_GPINTI, + BT848_GPIO_DMA_CTL); /* select direct input */ btwrite(0x00, BT848_GPIO_REG_INP); @@ -3229,13 +3430,14 @@ static int init_bt848(int i) /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ (fieldnr ? BT848_INT_VSYNC : 0)| + BT848_INT_GPINT| BT848_INT_SCERR| BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| BT848_INT_FMTCHG|BT848_INT_HLOCK, BT848_INT_MASK); make_vbitab(btv); - bt848_set_risc_jmps(btv); + bt848_set_risc_jmps(btv,-1); /* * Now add the template and register the device unit. @@ -3262,12 +3464,17 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) if (!astat) return; btwrite(astat,BT848_INT_STAT); - IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat)); - IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat)); + IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat)); + IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); /* get device status bits */ dstat=btread(BT848_DSTATUS); + if (astat&BT848_INT_GPINT) { + IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr)); + wake_up_interruptible(&btv->gpioq); + } + if (astat&BT848_INT_FMTCHG) { IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr)); @@ -3283,13 +3490,21 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr)); btv->field++; } - if (astat&BT848_INT_SCERR) { - IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr)); - bt848_dma(btv, 0); - bt848_dma(btv, 1); + if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) { + printk("bttv%d: irq:%s%s risc_count=%08x\n",btv->nr, + (astat&BT848_INT_SCERR) ? " SCERR" : "", + (astat&BT848_INT_OCERR) ? " OCERR" : "", + btread(BT848_RISC_COUNT)); + bt848_set_risc_jmps(btv,0); + btwrite(0, BT848_SRESET); + btwrite(virt_to_bus(btv->risc_jmp), + BT848_RISC_STRT_ADD); + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); +#if 0 wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); - +#endif } if (astat&BT848_INT_RISCI) { @@ -3307,41 +3522,48 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) /* captured full frame */ if (stat&(2<<28)) { - /*wake_up_interruptible(&btv->capq);*/ btv->last_field=btv->field; - btv->grab++; - btv->frame_stat[btv->grf] = GBUFFER_DONE; - if ((--btv->grabbing)) + if (debug) + printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); + btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; + btv->gq_grab = -1; + if (btv->gq_in != btv->gq_out) { - btv->gfmt = btv->gfmt_next; - btv->gwidth = btv->gwidth_next; - btv->gheight = btv->gheight_next; - btv->gro = btv->gro_next; - btv->gre = btv->gre_next; - btv->grf = btv->grf_next; - btv->risc_jmp[5]=cpu_to_le32(btv->gro); - btv->risc_jmp[11]=cpu_to_le32(btv->gre); - bt848_set_geo(btv, btv->gwidth, - btv->gheight, - btv->gfmt,0); + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (debug) + printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } else { - bt848_set_risc_jmps(btv); + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI); - bt848_set_geo(btv, btv->win.width, - btv->win.height, - btv->win.color_fmt,0); + bt848_set_geo(btv,0); + btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } wake_up_interruptible(&btv->capq); break; } if (stat&(8<<28)) { - btv->risc_jmp[5]=cpu_to_le32(btv->gro); - btv->risc_jmp[11]=cpu_to_le32(btv->gre); - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); - bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt,0); + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (debug) + printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } } if (astat&BT848_INT_OCERR) @@ -3427,6 +3649,9 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) init_waitqueue_head(&btv->capqe); btv->vbip=VBIBUF_SIZE; + init_waitqueue_head(&btv->gpioq); + btv->shutdown=0; + btv->id=dev->device; btv->irq=dev->irq; btv->bt848_adr=dev->resource[0].start; @@ -3544,15 +3769,17 @@ static int find_bt848(void) static void release_bttv(void) { u8 command; - int i; + int i,j; struct bttv *btv; for (i=0;ii2c_adap); + /* turn off all capturing, DMA and IRQs */ btand(~15, BT848_GPIO_DMA_CTL); /* first disable interrupts before unmapping the memory! */ @@ -3560,9 +3787,6 @@ static void release_bttv(void) btwrite(0xffffffffUL,BT848_INT_STAT); btwrite(0x0, BT848_GPIO_OUT_EN); - /* unregister i2c_bus */ - i2c_bit_del_bus(&btv->i2c_adap); - /* disable PCI bus-mastering */ pci_read_config_byte(btv->dev, PCI_COMMAND, &command); /* Should this be &=~ ?? */ @@ -3570,14 +3794,17 @@ static void release_bttv(void) pci_write_config_byte(btv->dev, PCI_COMMAND, command); /* unmap and free memory */ - if (btv->grisc) - kfree((void *) btv->grisc); - - if (btv->risc_odd) - kfree((void *) btv->risc_odd); + for (j = 0; j < gbuffers; j++) + if (btv->gbuf[j].risc) + kfree(btv->gbuf[j].risc); + if (btv->gbuf) + kfree((void *) btv->gbuf); + + if (btv->risc_scr_odd) + kfree((void *) btv->risc_scr_odd); - if (btv->risc_even) - kfree((void *) btv->risc_even); + if (btv->risc_scr_even) + kfree((void *) btv->risc_scr_even); DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); if (btv->risc_jmp) @@ -3599,6 +3826,13 @@ static void release_bttv(void) video_unregister_device(&btv->vbi_dev); if (radio[btv->nr] && btv->radio_dev.minor != -1) video_unregister_device(&btv->radio_dev); + + /* wake up any waiting processes + because shutdown flag is set, no new processes (in this queue) + are expected + */ + btv->shutdown=1; + wake_up(&btv->gpioq); } } @@ -3614,6 +3848,14 @@ int init_bttv_cards(struct video_init *unused) (BTTV_VERSION_CODE >> 16) & 0xff, (BTTV_VERSION_CODE >> 8) & 0xff, BTTV_VERSION_CODE & 0xff); + if (gbuffers < 2 || gbuffers > MAX_GBUFFERS) + gbuffers = 2; + if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) + gbufsize = BTTV_MAX_FBUF; + if (verbose) + printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n", + gbuffers,gbufsize/1024,gbuffers*gbufsize/1024); + handle_chipset(); if (find_bt848()<=0) return -EIO; diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h index 309e93e95b7d..ab3d88ab51ab 100644 --- a/drivers/char/bttv.h +++ b/drivers/char/bttv.h @@ -21,45 +21,67 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE 0x00070d +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,21) #include #include +#include +#include +#include #include "audiochip.h" #include "bt848.h" +#define WAIT_QUEUE wait_queue_head_t -/* experimental, interface might change */ -#ifndef VIDIOCSWIN2 -#define VIDIOCSWIN2 _IOW('v',28,struct video_window2) -struct video_window2 -{ - __u16 palette; /* Palette (aka video format) in use */ - __u32 start; /* start address, relative to video_buffer.base */ - __u32 pitch; - __u32 width; - __u32 height; - __u32 flags; - - struct video_clip *clips; - int clipcount; -}; -#endif +/* returns card type, + for possible values see lines below beginning with #define BTTV_UNKNOWN + returns negative value if error ocurred +*/ +extern int bttv_get_id(unsigned int card); +/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: + data | (current_GPOE_value & ~mask) + returns negative value if error ocurred +*/ +extern int bttv_gpio_enable(unsigned int card, + unsigned long mask, unsigned long data); + +/* fills data with GPDATA register contents + returns negative value if error ocurred +*/ +extern int bttv_read_gpio(unsigned int card, unsigned long *data); + +/* sets GPDATA register to new value: + (data & mask) | (current_GPDATA_value & ~mask) + returns negative value if error ocurred +*/ +extern int bttv_write_gpio(unsigned int card, + unsigned long mask, unsigned long data); + +/* returns pointer to task queue which can be used as parameter to + interruptible_sleep_on + in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated + (wake_up_interruptible) and following call to the function bttv_read_gpio + should return new value of GPDATA, + returns NULL value if error ocurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card); -#define WAIT_QUEUE wait_queue_head_t #ifndef O_NONCAP #define O_NONCAP O_TRUNC #endif -#define MAX_GBUFFERS 2 +#define MAX_GBUFFERS 64 #define RISCMEM_LEN (32744*2) #define VBI_MAXLINES 16 #define VBIBUF_SIZE (2048*VBI_MAXLINES*2) #define BTTV_MAX_FBUF 0x208000 +#define I2C_CLIENTS_MAX 8 #ifdef __KERNEL__ @@ -69,17 +91,12 @@ struct bttv_window ushort width, height; ushort bpp, bpl; ushort swidth, sheight; - short cropx, cropy; - ushort cropwidth, cropheight; unsigned long vidadr; ushort freq; int norm; int interlace; int color_fmt; ushort depth; - - int use_yuv; - struct video_window2 win2; }; struct bttv_pll_info { @@ -89,7 +106,21 @@ struct bttv_pll_info { unsigned int pll_current; /* Currently programmed ofreq */ }; -#define I2C_CLIENTS_MAX 8 +struct bttv_gbuf { + int stat; +#define GBUFFER_UNUSED 0 +#define GBUFFER_GRABBING 1 +#define GBUFFER_DONE 2 +#define GBUFFER_ERROR 3 + + u16 width; + u16 height; + u16 fmt; + + u32 *risc; + unsigned long ro; + unsigned long re; +}; struct bttv { @@ -125,6 +156,7 @@ struct bttv unsigned char *vbibuf; struct bttv_window win; + int fb_color_ctl; int type; /* card type */ int audio; /* audio mode */ int audio_chip; /* set to one of the chips supported by bttv.c */ @@ -141,34 +173,18 @@ struct bttv WAIT_QUEUE capqe; int vbip; - u32 *risc_odd; - u32 *risc_even; - int cap; + u32 *risc_scr_odd; + u32 *risc_scr_even; + u32 risc_cap_odd; + u32 risc_cap_even; + int scr_on; + int vbi_on; struct video_clip *cliprecs; - struct gbuffer *ogbuffers; - struct gbuffer *egbuffers; - u16 gwidth, gheight, gfmt; - u16 gwidth_next, gheight_next, gfmt_next; - u32 *grisc; - - unsigned long gro; - unsigned long gre; - unsigned long gro_next; - unsigned long gre_next; - - int grf,grf_next; /* frame numbers in grab queue */ - int frame_stat[MAX_GBUFFERS]; -#define GBUFFER_UNUSED 0 -#define GBUFFER_GRABBING 1 -#define GBUFFER_DONE 2 - + struct bttv_gbuf *gbuf; + int gqueue[MAX_GBUFFERS]; + int gq_in,gq_out,gq_grab; char *fbuffer; - int gmode; - int grabbing; - int lastgrab; - int grab; - int grabcount; struct bttv_pll_info pll; unsigned int Fsc; @@ -176,12 +192,12 @@ struct bttv unsigned int last_field; /* number of last grabbed field */ int i2c_command; int triton1; + + WAIT_QUEUE gpioq; + int shutdown; }; #endif -/*The following should be done in more portable way. It depends on define - of _ALPHA_BTTV in the Makefile.*/ - #if defined(__powerpc__) /* big-endian */ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) { @@ -193,14 +209,9 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat)) #define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(adr))) #else -#ifdef _ALPHA_BTTV -#define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr))) -#define btread(adr) readl(btv->bt848_adr+(adr)) -#else #define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr))) #define btread(adr) readl(btv->bt848_mem+(adr)) #endif -#endif #define btand(dat,adr) btwrite((dat) & btread(adr), adr) #define btor(dat,adr) btwrite((dat) | btread(adr), adr) @@ -243,10 +254,19 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define BTTV_PHOEBE_TVMAS 0x16 #define BTTV_MODTEC_205 0x17 #define BTTV_MAGICTVIEW061 0x18 - +#define BTTV_VOBIS_BOOSTAR 0x19 +#define BTTV_HAUPPAUG_WCAM 0x1a #define BTTV_MAXI 0x1b #define BTTV_TERRATV 0x1c #define BTTV_PXC200 0x1d +#define BTTV_FLYVIDEO_98 0x1e +#define BTTV_IPROTV 0x1f +#define BTTV_INTEL_C_S_PCI 0x20 +#define BTTV_TERRATVALUE 0x21 +#define BTTV_WINFAST2000 0x22 +#define BTTV_CHRONOS_VS2 0x23 +#define BTTV_TYPHOON_TVIEW 0x24 +#define BTTV_PXELVWPLTVPRO 0x25 #define AUDIO_TUNER 0x00 @@ -279,27 +299,6 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define TDA9840_STADJ 0x03 #define TDA9840_TEST 0x04 -#define TDA9850_CON1 0x04 -#define TDA9850_CON2 0x05 -#define TDA9850_CON3 0x06 -#define TDA9850_CON4 0x07 -#define TDA9850_ALI1 0x08 -#define TDA9850_ALI2 0x09 -#define TDA9850_ALI3 0x0a - -#define TDA8425_VL 0x00 -#define TDA8425_VR 0x01 -#define TDA8425_BA 0x02 -#define TDA8425_TR 0x03 -#define TDA8425_S1 0x08 - -#define TEA6300_VL 0x00 /* volume control left */ -#define TEA6300_VR 0x01 /* volume control right */ -#define TEA6300_BA 0x02 /* bass control */ -#define TEA6300_TR 0x03 /* treble control */ -#define TEA6300_FA 0x04 /* fader control */ -#define TEA6300_SW 0x05 /* mute and source switch */ - #define PT2254_L_CHANEL 0x10 #define PT2254_R_CHANEL 0x08 #define PT2254_DBS_IN_2 0x400 @@ -309,3 +308,9 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define WINVIEW_PT2254_STROBE 0x80 #endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/console.c b/drivers/char/console.c index a1c9f3cf39ff..9d8bf6cb03ac 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -2564,7 +2564,7 @@ void __init con_init_devfs (void) int i; for (i = 0; i < console_driver.num; i++) - tty_register_devfs (&console_driver, 0, + tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY, console_driver.minor_start + i); } diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index 2be8b27984d4..8de178bb6a72 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -480,7 +480,7 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode) break; case VIDEO_SOUND_MONO: if (msp->mode == MSP_MODE_AM_NICAM) { - printk("msp3400: switching to AM mono\n"); + dprintk("msp3400: switching to AM mono\n"); /* AM mono decoding is handled by tuner, not MSP chip */ /* so let's redirect sound from tuner via SCART */ /* volume prescale for SCART */ @@ -723,7 +723,7 @@ static int msp3400c_thread(void *data) /* some time for the tuner to sync */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/5); if (signal_pending(current)) goto done; @@ -750,13 +750,15 @@ static int msp3400c_thread(void *data) msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/25); + schedule_timeout(HZ/10); if (signal_pending(current)) goto done; if (msp->restart) msp->restart = 0; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + if (val > 32768) + val -= 65536; if (val1 < val) val1 = val, max1 = this; dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); @@ -785,13 +787,15 @@ static int msp3400c_thread(void *data) msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/25); + schedule_timeout(HZ/10); if (signal_pending(current)) goto done; if (msp->restart) goto restart; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + if (val > 32768) + val -= 65536; if (val2 < val) val2 = val, max2 = this; dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); @@ -974,7 +978,7 @@ static int msp3410d_thread(void *data) /* some time for the tuner to sync */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/5); if (signal_pending(current)) goto done; @@ -1041,10 +1045,9 @@ static int msp3410d_thread(void *data) for (i = 0; modelist[i].name != NULL; i++) if (modelist[i].retval == val) break; - if (debug) - printk("msp3410: current mode: %s (0x%04x)\n", - modelist[i].name ? modelist[i].name : "unknown", - val); + dprintk("msp3410: current mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown", + val); msp->main = modelist[i].main; msp->second = modelist[i].second; @@ -1242,6 +1245,7 @@ static int msp3400c_mixer_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + struct i2c_client *client; struct msp3400c *msp; int i; @@ -1249,12 +1253,17 @@ msp3400c_mixer_open(struct inode *inode, struct file *file) for (i = 0; i < MSP3400_MAX; i++) { msp = msps[i]->data; if (msp->mixer_num == minor) { - file->private_data = msps[i]; + client = msps[i]; + file->private_data = client; break; } } if (MSP3400_MAX == i) return -ENODEV; + + /* lock bttv in memory while the mixer is in use */ + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); MOD_INC_USE_COUNT; return 0; @@ -1263,6 +1272,10 @@ msp3400c_mixer_open(struct inode *inode, struct file *file) static int msp3400c_mixer_release(struct inode *inode, struct file *file) { + struct i2c_client *client = file->private_data; + + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); MOD_DEC_USE_COUNT; return 0; } @@ -1274,10 +1287,10 @@ msp3400c_mixer_llseek(struct file *file, loff_t offset, int origin) } static struct file_operations msp3400c_mixer_fops = { - llseek: msp3400c_mixer_llseek, - ioctl: msp3400c_mixer_ioctl, - open: msp3400c_mixer_open, - release: msp3400c_mixer_release, + llseek: msp3400c_mixer_llseek, + ioctl: msp3400c_mixer_ioctl, + open: msp3400c_mixer_open, + release: msp3400c_mixer_release, }; #endif diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index d73c09695203..59853da1f16f 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -83,7 +83,7 @@ struct pp_struct { /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) -static inline void enable_irq (struct pp_struct *pp) +static inline void pp_enable_irq (struct pp_struct *pp) { struct parport *port = pp->pdev->port; port->ops->enable_irq (port); @@ -144,7 +144,7 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count, } kfree (kbuffer); - enable_irq (pp); + pp_enable_irq (pp); return bytes_read; } @@ -197,7 +197,7 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count, } kfree (kbuffer); - enable_irq (pp); + pp_enable_irq (pp); return bytes_written; } @@ -292,7 +292,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, /* For interrupt-reporting to work, we need to be * informed of each interrupt. */ - enable_irq (pp); + pp_enable_irq (pp); /* We may need to fix up the state machine. */ info = &pp->pdev->port->ieee1284; @@ -441,7 +441,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, ret = -ENXIO; break; } - enable_irq (pp); + pp_enable_irq (pp); return ret; case PPWCTLONIRQ: diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 77cdb7a51993..8f25926e98df 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -329,9 +329,10 @@ static int pty_open(struct tty_struct *tty, struct file * filp) clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&pty->open_wait); set_bit(TTY_THROTTLED, &tty->flags); - /* register a slave for the master */ + /* Register a slave for the master */ if (tty->driver.major == PTY_MASTER_MAJOR) - tty_register_devfs(&tty->link->driver, DEVFS_FL_WAIT, + tty_register_devfs(&tty->link->driver, + DEVFS_FL_AUTO_OWNER | DEVFS_FL_WAIT, tty->link->driver.minor_start + MINOR(tty->device)-tty->driver.minor_start); retval = 0; diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h index 893d1a1e0d14..9239e41d7967 100644 --- a/drivers/char/sh-sci.h +++ b/drivers/char/sh-sci.h @@ -7,6 +7,7 @@ * Copyright (C) 2000 Greg Banks * */ +#include #if defined(CONFIG_SH_SCI_SERIAL) #if defined(__sh3__) diff --git a/drivers/char/tda9855.c b/drivers/char/tda9855.c deleted file mode 100644 index dfdee66dcc1c..000000000000 --- a/drivers/char/tda9855.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * For the TDA9855 chip (afaik, only the Diamond DTV2000 has this) - * This driver will not complain if used with a TDA9850 or any - * other i2c device with the same address. - * - * Copyright (c) 1999 Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * This code is placed under the terms of the GNU General Public License - * Based on tda8425.c by Greg Alexander (c) 1998 - * - * TODO: - * Fix channel change bug - sound goes out when changeing channels, mute - * and unmote to fix. - * Fine tune sound - * Get rest of capabilities into video_audio struct... - * - * Revision: 0.1 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "audiochip.h" - - -MODULE_PARM(debug,"i"); -static int debug = 0; /* insmod parameter */ - -/* Addresses to scan */ -#define I2C_TDA9855_L 0xb4 -#define I2C_TDA9855_H 0xb6 -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = { - I2C_TDA9855_L >> 1, - I2C_TDA9855_H >> 1, - I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -struct tda9855 { - int addr; - int rvol, lvol; - int bass, treble, sub; - int c1, c2, c3; - int a1, a2, a3; -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - - -#define dprintk if (debug) printk - - /* subaddresses */ -#define TDA9855_VR 0x00 /* Volume, right */ -#define TDA9855_VL 0x01 /* Volume, left */ -#define TDA9855_BA 0x02 /* Bass */ -#define TDA9855_TR 0x03 /* Treble */ -#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ -#define TDA9855_C1 0x05 /* Control 1 */ -#define TDA9855_C2 0x06 /* Control 2 */ -#define TDA9855_C3 0x07 /* Control 3 */ -#define TDA9855_A1 0x08 /* Alignmnet 1*/ -#define TDA9855_A2 0x09 /* Alignmnet 2*/ -#define TDA9855_A3 0x0a /* Alignmnet 3*/ - /* Masks for bits in subaddresses */ -/* VR */ /* VL */ -/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) - * in 1dB steps - mute is 0x27 */ - -/* BA */ -/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) - * in .5dB steps - 0 is 0x0E */ - -/* TR */ -/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) - * in 3dB steps - 0 is 0x7 */ - -/* SW */ -/* 4 bits << 2 control subwoofer/surraound gain from -14db (0x1) to 14db (0xf) - * in 3dB steps - mute is 0x0 */ - -/* C1 */ -#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ -#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ -#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ -#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ - /* Bits 0 to 3 select various combinations - * of line in and line out, only the - * interesting ones are defined */ -#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ -#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ - -/* C2 */ -#define TDA9855_SAP 3<<6 /* Selects SAP output, mute if not received */ -#define TDA9855_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ -#define TDA9855_MONO 0 /* Forces Mono output */ -#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ -#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ -#define TDA9855_LMU 1<<3 /* Mute at LOR and LOL */ -#define TDA9855_LINEAR 0 /* Linear Stereo */ -#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ -#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ -#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ -#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ - -/* C3 */ -/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) - * in .5dB steps - 0 is 0x7 */ - -/* A1 and A2 (read/write) */ -/* lower 5 bites are wideband and spectral expander alignment - * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ -#define TDA9855_STP 1<<5 /* Stereo Pilot/detect (read-only) */ -#define TDA9855_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ -#define TDA9855_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ - -/* A3 */ -/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), - * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ -/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), - * 1200ohm (0x1), 2100ohm (0x3) */ -#define TDA9855_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral) */ - - -/* Begin code */ - -static int tda9855_write(struct i2c_client *client, int subaddr, int val) -{ - unsigned char buffer[2]; - - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tda9855: I/O error, trying (write %d 0x%x)\n", - subaddr, val); - return -1; - } - return 0; -} - -static int tda9855_read(struct i2c_client *client) -{ - unsigned char buffer; - - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda9855: I/O error, trying (read)\n"); - return -1; - } - return buffer; -} - -static int tda9855_set(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - unsigned char buf[16]; - - dprintk(KERN_INFO "tda9855_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",t->rvol,t->lvol,t->bass,t->treble,t->sub, - t->c1,t->c2,t->c3,t->a1,t->a2,t->a3); - buf[0] = TDA9855_VR; - buf[1] = t->rvol; - buf[2] = t->lvol; - buf[3] = t->bass; - buf[4] = t->treble; - buf[5] = t->sub; - buf[6] = t->c1; - buf[7] = t->c2; - buf[8] = t->c3; - buf[9] = t->a1; - buf[10] = t->a2; - buf[11] = t->a3; - if (12 != i2c_master_send(client,buf,12)) { - printk(KERN_WARNING "tda9855: I/O error, trying tda9855_set\n"); - return -1; - } - return 0; -} - -static void do_tda9855_init(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - - t->rvol=0x6f; /* 0dB */ - t->lvol=0x6f; /* 0dB */ - t->bass=0x0e; /* 0dB */ - t->treble=(0x07 << 1); /* 0dB */ - t->sub=0x8 << 2; /* 0dB */ - t->c1=TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT; - /* Set Mute, AVL, Loudness off, Internal sound */ - t->c2=TDA9855_STEREO | TDA9855_LINEAR; /* Set Stereo liner mode */ - t->c3=0x07; /* 0dB input gain */ - t->a1=0x10; /* Select nominal wideband expander */ - t->a2=0x10; /* Select nominal spectral expander and 30mV trigger */ - t->a3=0x3; /* Set: nominal timinig current, 420ohm AVL attack */ - tda9855_write(client, TDA9855_C1, TDA9855_MUTE); /* mute */ - tda9855_set(client); -} - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda9855_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tda9855 *t; - struct i2c_client *client; - - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = t = kmalloc(sizeof *t,GFP_KERNEL); - if (!t) - return -ENOMEM; - memset(t,0,sizeof *t); - do_tda9855_init(client); - MOD_INC_USE_COUNT; - strcpy(client->name,"TDA9855"); - printk(KERN_INFO "tda9855: init\n"); - - i2c_attach_client(client); - return 0; -} - -static int tda9855_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tda9855_attach); - return 0; -} - -static int tda9855_detach(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - - do_tda9855_init(client); - i2c_detach_client(client); - - kfree(t); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int tda9855_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct tda9855 *t = client->data; -#if 0 - __u16 *sarg = arg; -#endif - - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - int left,right; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - - /* min is 0x27 max is 0x7f, vstep is 2e8 */ - left = (t->lvol-0x27)*0x2e8; - right = (t->rvol-0x27)*0x2e8; - va->volume=MAX(left,right); - va->balance=(32768*MIN(left,right))/ - (va->volume ? va->volume : 1); - va->balance=(leftbalance) : va->balance; - va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ - va->treble = ((t->treble>>1)-0x3)*0x1c71; - - va->mode = ((TDA9855_STP | TDA9855_SAPP) & - tda9855_read(client)) >> 4; - va->mode |= VIDEO_SOUND_MONO; - break; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - int left,right; - - left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - right = (MIN(va->balance,32768) * - va->volume) / 32768; - t->lvol = left/0x2e8+0x27; - t->rvol = right/0x2e8+0x27; - t->bass = va->bass/0xccc+0x6; - t->treble = (va->treble/0x1c71+0x3)<<1; - tda9855_write(client,TDA9855_VL,t->lvol); - tda9855_write(client,TDA9855_VR,t->rvol); - tda9855_write(client,TDA9855_BA, t->bass); - tda9855_write(client,TDA9855_TR,t->treble); - - switch (va->mode) { - case VIDEO_SOUND_MONO: - t->c2= TDA9855_MONO | (t->c2 & 0x3f); - break; - case VIDEO_SOUND_STEREO: - t->c2= TDA9855_STEREO | (t->c2 & 0x3f); - break; - case VIDEO_SOUND_LANG1: - t->c2= TDA9855_SAP | (t->c2 & 0x3f); - break; - } - tda9855_write(client,TDA9855_C2,t->c2); - break; - } - -#if 0 - /* --- old, obsolete interface --- */ - case AUDC_GET_VOLUME_LEFT: - *sarg = (t->lvol-0x27)*0x2e8; /* min is 0x27 max is 0x7f, vstep is 2e8 */ - break; - case AUDC_GET_VOLUME_RIGHT: - *sarg = (t->rvol-0x27)*0x2e8; - break; - case AUDC_SET_VOLUME_LEFT: - t->lvol = *sarg/0x2e8+0x27; - break; - case AUDC_SET_VOLUME_RIGHT: - t->rvol = *sarg/0x2e8+0x27; - break; - case AUDC_GET_BASS: - *sarg = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ - break; - case AUDC_SET_BASS: - t->bass = *sarg/0xccc+0x6; - tda9855_write(client,TDA9855_BA, t->bass); - break; - case AUDC_GET_TREBLE: - *sarg = ((t->treble>>1)-0x3)*0x1c71; - break; - case AUDC_SET_TREBLE: - t->treble = (*sarg/0x1c71+0x3)<<1; - tda9855_write(client,TDA9855_TR,t->treble); - break; - case AUDC_GET_STEREO: - *sarg = ((TDA9855_STP | TDA9855_SAPP) & - tda9855_read(client)) >> 4; - if(*sarg==0) *sarg=VIDEO_SOUND_MONO; - break; - case AUDC_SET_STEREO: - if(*sarg==VIDEO_SOUND_MONO) - t->c2= TDA9855_MONO | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set mono */ - else if(*sarg==VIDEO_SOUND_STEREO) - t->c2= TDA9855_STEREO | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set stereo */ - else if(*sarg==VIDEO_SOUND_LANG2) - t->c2= TDA9855_SAP | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set sap */ - tda9855_write(client,TDA9855_C2,t->c2); - break; - case AUDC_SET_INPUT: - dprintk(KERN_INFO "tda9855: SET_INPUT with 0x%04x\n",*sarg); - if((*sarg & (AUDIO_MUTE | AUDIO_OFF))!=0) - t->c1|=TDA9855_MUTE; - else - t->c1= t->c1 & 0x7f; /* won't work --> (~TDA9855_MUTE); */ - if((*sarg & AUDIO_INTERN) == AUDIO_INTERN) - t->c1=(t->c1 & ~0x7) | TDA9855_INT; /* 0x7 is a mask for the int/ext */ - if((*sarg & AUDIO_EXTERN) == AUDIO_EXTERN) - t->c1=(t->c1 & ~0x7) | TDA9855_EXT; /* 0x7 is a mask for the int/ext */ - tda9855_write(client,TDA9855_C1,t->c1); - break; - case AUDC_SWITCH_MUTE: - if((t->c1 & ~TDA9855_MUTE) == 0) - t->c1|=TDA9855_MUTE; - else - t->c1&=~TDA9855_MUTE; - tda9855_write(client,TDA9855_C1,t->c1); - break; - -/* TDA9855 unsupported: */ -/* case AUDC_NEWCHANNEL: - case AUDC_SET_RADIO: - case AUDC_GET_DC: -*/ -#endif - default: - /* nothing */ - } - return 0; -} - - -static struct i2c_driver driver = { - "i2c tda9855 driver", - I2C_DRIVERID_TDA9855, - I2C_DF_NOTIFY, - tda9855_probe, - tda9855_detach, - tda9855_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tda9855_init(void) -#endif -{ - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/char/tda985x.c b/drivers/char/tda985x.c new file mode 100644 index 000000000000..62bcf15ba2cd --- /dev/null +++ b/drivers/char/tda985x.c @@ -0,0 +1,532 @@ +/* + * For the TDA9850 and TDA9855 chips + * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used + * on STB cards. Other cards probably use these chips as well.) + * This driver will not complain if used with any + * other i2c device with the same address. + * + * Copyright (c) 1999 Gerd Knorr + * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com) + * This code is placed under the terms of the GNU General Public License + * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * Which was based on tda8425.c by Greg Alexander (c) 1998 + * + * OPTIONS: + * debug - set to 1 if you'd like to see debug messages + * chip - set to 9850 or 9855 to select your chip (default 9855) + * + * TODO: + * Fix channel change bug - sound goes out when changeing channels, mute + * and unmote to fix. - Is this still here? + * Fine tune sound + * Get rest of capabilities into video_audio struct... + * + * Revision: 0.4 - check for correct chip= insmod value + * also cleaned up comments a bit + * Revision: 0.3 - took out extraneous tda985x_write in tda985x_command + * Revision: 0.2 - added insmod option chip= + * Revision: 0.1 - original version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +MODULE_PARM(debug,"i"); +MODULE_PARM(chip,"i"); +MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855"); + +static int debug = 0; /* insmod parameter */ +static int chip = 9855; /* insmod parameter */ + +/* Addresses to scan */ +#define I2C_TDA985x_L 0xb4 +#define I2C_TDA985x_H 0xb6 +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = { + I2C_TDA985x_L >> 1, + I2C_TDA985x_H >> 1, + I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* This is a superset of the TDA9850 and TDA9855 members */ + +struct tda985x { + int addr; + int rvol, lvol; + int bass, treble, sub; + int c4, c5, c6, c7; + int a1, a2, a3; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define dprintk if (debug) printk + +/* The TDA9850 and TDA9855 are both made by Philips Semiconductor + * http://www.semiconductors.philips.com + * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder + * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor + * + * The TDA9850 has more or less a subset of the functions that the TDA9855 + * has. As a result, we can re-use many of these defines. Anything with + * TDA9855 is specific to that chip, anything with TDA9850 is specific + * to that chip, and anything with TDA985x is valid for either. + * + * To complicate things further, the TDA9850 uses labels C1 through C4 + * for subaddresses 0x04 through 0x07, while the TDA9855 uses + * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing. + * To help keep things straight, I have renamed the various C[1,4] labels + * to C[4,7] so that the numerical label matches the hex value of the + * subaddress for both chips. At least the A[1,3] labels line up. :) + */ + + /* subaddresses for TDA9855 */ +#define TDA9855_VR 0x00 /* Volume, right */ +#define TDA9855_VL 0x01 /* Volume, left */ +#define TDA9855_BA 0x02 /* Bass */ +#define TDA9855_TR 0x03 /* Treble */ +#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ + + /* subaddresses for TDA9850 */ +#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */ + + /* subaddesses for both chips */ +#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */ +#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */ +#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */ +#define TDA985x_A1 0x08 /* Alignment 1 for both chips */ +#define TDA985x_A2 0x09 /* Alignment 2 for both chips */ +#define TDA985x_A3 0x0a /* Alignment 3 for both chips */ + + /* Masks for bits in TDA9855 subaddresses */ +/* 0x00 - VR in TDA9855 */ +/* 0x01 - VL in TDA9855 */ +/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) + * in 1dB steps - mute is 0x27 */ + + +/* 0x02 - BA in TDA9855 */ +/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) + * in .5dB steps - 0 is 0x0E */ + + +/* 0x03 - TR in TDA9855 */ +/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) + * in 3dB steps - 0 is 0x7 */ + + /* Masks for bits in both chips' subaddresses */ +/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */ +/* Unique to TDA9855: */ +/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf) + * in 3dB steps - mute is 0x0 */ + +/* Unique to TDA9850: */ +/* lower 4 bits control stereo noise threshold, over which stereo turns off + * set to values of 0x00 through 0x0f for Ster1 through Ster16 */ + + +/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/ +/* Unique to TDA9855: */ +#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ +#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ +#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ +#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ + /* Bits 0 to 3 select various combinations + * of line in and line out, only the + * interesting ones are defined */ +#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ +#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ + +/* Unique to TDA9850: */ +/* lower 4 bits contol SAP noise threshold, over which SAP turns off + * set to values of 0x00 through 0x0f for SAP1 through SAP16 */ + + +/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */ +/* Common to TDA9855 and TDA9850: */ +#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */ +#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ +#define TDA985x_MONO 0 /* Forces Mono output */ +#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */ + +/* Unique to TDA9855: */ +#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ +#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ +#define TDA9855_LINEAR 0 /* Linear Stereo */ +#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ +#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ +#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ +#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ + + +/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) + * in .5dB steps - 0dB is 0x7 */ + + +/* 0x08, 0x09 - A1 and A2 (read/write) */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 5 bites are wideband and spectral expander alignment + * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ +#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */ +#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ +#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ + + +/* 0x0a - A3 */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), + * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ +#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */ + +/* Unique to TDA9855: */ +/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), + * 1200ohm (0x1), 2100ohm (0x3) */ + + +/* Begin code */ + +static int tda985x_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + dprintk("In tda985x_write\n"); + dprintk("Writing %d 0x%x\n", subaddr, val); + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +static int tda985x_read(struct i2c_client *client) +{ + unsigned char buffer; + dprintk("In tda985x_read\n"); + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda985x: I/O error, trying (read)\n"); + return -1; + } + dprintk("Read 0x%02x\n", buffer); + return buffer; +} + +static int tda985x_set(struct i2c_client *client) +{ + struct tda985x *t = client->data; + unsigned char buf[16]; + dprintk("In tda985x_set\n"); + + if (chip == 9855) + { + dprintk(KERN_INFO + "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->rvol,t->lvol,t->bass,t->treble,t->sub, + t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); + buf[0] = TDA9855_VR; + buf[1] = t->rvol; + buf[2] = t->lvol; + buf[3] = t->bass; + buf[4] = t->treble; + buf[5] = t->sub; + buf[6] = t->c5; + buf[7] = t->c6; + buf[8] = t->c7; + buf[9] = t->a1; + buf[10] = t->a2; + buf[11] = t->a3; + if (12 != i2c_master_send(client,buf,12)) { + printk(KERN_WARNING "tda9855: I/O error, trying tda985x_set\n"); + return -1; + } + } + + else if (chip == 9850) + { + dprintk(KERN_INFO + "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); + buf[0] = TDA9850_C4; + buf[1] = t->c4; + buf[2] = t->c5; + buf[3] = t->c6; + buf[4] = t->c7; + buf[5] = t->a1; + buf[6] = t->a2; + buf[7] = t->a3; + if (8 != i2c_master_send(client,buf,8)) { + printk(KERN_WARNING "tda9850: I/O error, trying tda985x_set\n"); + return -1; + } + } + + return 0; +} + +static void do_tda985x_init(struct i2c_client *client) +{ + struct tda985x *t = client->data; + dprintk("In tda985x_init\n"); + + if (chip == 9855) + { + printk("Using tda9855 options\n"); + t->rvol = 0x6f; /* 0dB */ + t->lvol = 0x6f; /* 0dB */ + t->bass = 0x0e; /* 0dB */ + t->treble = (0x07 << 1); /* 0dB */ + t->sub = 0x8 << 2; /* 0dB */ + t->c5 = TDA9855_MUTE | TDA9855_AVL | + TDA9855_LOUD | TDA9855_INT; + /* Set Mute, AVL, Loudness off, Internal sound */ + t->c6 = TDA985x_STEREO | TDA9855_LINEAR | + TDA9855_TZCM | TDA9855_VZCM; + /* Stereo linear mode, also wait til zero crossings */ + t->c7 = 0x07; /* 0dB input gain */ + } + + else if (chip == 9850) + { + printk("Using tda9850 options\n"); + t->c4 = 0x08; /* Set stereo noise thresh to nominal */ + t->c5 = 0x08; /* Set SAP noise threshold to nominal */ + t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */ + t->c7 = 0x07; /* 0dB input gain */ + } + + /* The following is valid for both chip types */ + t->a1 = 0x10; /* Select nominal wideband expander */ + t->a2 = 0x10; /* Select nominal spectral expander and 30mV trigger */ + t->a3 = 0x3; /* Set: nominal timing current, 420ohm AVL attack */ + + tda985x_set(client); +} + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda985x_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda985x *t; + struct i2c_client *client; + dprintk("In tda985x_attach\n"); + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda985x_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA985x"); + printk(KERN_INFO "tda985x: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda985x_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda985x_attach); + return 0; +} + +static int tda985x_detach(struct i2c_client *client) +{ + struct tda985x *t = client->data; + + do_tda985x_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda985x_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda985x *t = client->data; + dprintk("In tda985x_command...\n"); +#if 0 + __u16 *sarg = arg; +#endif + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + dprintk("VIDIOCGAUDIO\n"); + if (chip == 9855) + { + int left,right; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* min is 0x27 max is 0x7f, vstep is 2e8 */ + left = (t->lvol-0x27)*0x2e8; + right = (t->rvol-0x27)*0x2e8; + va->volume=MAX(left,right); + va->balance=(32768*MIN(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(leftbalance) : va->balance; + va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */ + va->treble = ((t->treble>>1)-0x3)*0x1c71; + } + + /* Valid for both chips: */ + { + va->mode = ((TDA985x_STP | TDA985x_SAPP) & + tda985x_read(client)) >> 4; + /* Add mono mode regardless of SAP and stereo */ + /* Allows forced mono */ + va->mode |= VIDEO_SOUND_MONO; + } + + break; /* VIDIOCGAUDIO case */ + } + + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + dprintk("VIDEOCSAUDIO...\n"); + if (chip == 9855) + { + int left,right; + + left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + right = (MIN(va->balance,32768) * + va->volume) / 32768; + t->lvol = left/0x2e8+0x27; + t->rvol = right/0x2e8+0x27; + t->bass = va->bass/0xccc+0x6; + t->treble = (va->treble/0x1c71+0x3)<<1; + tda985x_write(client,TDA9855_VL,t->lvol); + tda985x_write(client,TDA9855_VR,t->rvol); + tda985x_write(client,TDA9855_BA, t->bass); + tda985x_write(client,TDA9855_TR,t->treble); + } + + /* The following is valid for both chips */ + + switch (va->mode) { + case VIDEO_SOUND_MONO: + dprintk("VIDEO_SOUND_MONO\n"); + t->c6= TDA985x_MONO | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + case VIDEO_SOUND_STEREO: + dprintk("VIDEO_SOUND_STEREO\n"); + t->c6= TDA985x_STEREO | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + case VIDEO_SOUND_LANG1: + dprintk("VIDEO_SOUND_LANG1\n"); + t->c6= TDA985x_SAP | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + } /* End of (va->mode) switch */ + + break; + + } /* end of VIDEOCSAUDIO case */ + + default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ + + /* nothing */ + dprintk("Default\n"); + + } /* end of (cmd) switch */ + + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda985x driver", + I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */ + I2C_DF_NOTIFY, + tda985x_probe, + tda985x_detach, + tda985x_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda985x_init(void) +#endif +{ + if ( (chip != 9850) && (chip != 9855) ) + { + printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n"); + return -EINVAL; + } + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 705d876b32e9..ed504dcfec97 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1321,7 +1321,7 @@ retry_open: set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ minor -= driver->minor_start; devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start)); - tty_register_devfs(&pts_driver[major], 0, + tty_register_devfs(&pts_driver[major], DEVFS_FL_NO_PERSISTENCE, pts_driver[major].minor_start + minor); noctty = 1; goto init_dev_done; @@ -2003,7 +2003,6 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags, struct tty_struct tty; char buf[32]; - flags |= DEVFS_FL_DEFAULT; tty.driver = *driver; tty.device = MKDEV (driver->major, minor); switch (tty.device) { @@ -2012,28 +2011,22 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags, mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; break; default: - flags |= DEVFS_FL_AUTO_OWNER; break; } - if ((minor < driver->minor_start) || - (minor >= driver->minor_start + driver->num)) { + if ( (minor < driver->minor_start) || + (minor >= driver->minor_start + driver->num) ) { printk(KERN_ERR "Attempt to register invalid minor number " "with devfs (%d:%d).\n", (int)driver->major,(int)minor); return; } - if (driver->type == TTY_DRIVER_TYPE_CONSOLE) { - flags |= DEVFS_FL_AOPEN_NOTIFY; - flags &= ~DEVFS_FL_AUTO_OWNER; - } # ifdef CONFIG_UNIX98_PTYS if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) && (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) { - flags &= ~DEVFS_FL_AUTO_OWNER; uid = current->uid; gid = current->gid; } # endif - devfs_register (NULL, tty_name (&tty, buf), 0, flags, + devfs_register (NULL, tty_name (&tty, buf), 0,flags | DEVFS_FL_DEFAULT, driver->major, minor, mode, uid, gid, &tty_fops, NULL); #endif /* CONFIG_DEVFS_FS */ diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c index 99dc750ee629..dfea37d63865 100644 --- a/drivers/char/tuner.c +++ b/drivers/char/tuner.c @@ -12,6 +12,7 @@ #include #include "tuner.h" +#include "audiochip.h" /* Addresses to scan */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; @@ -334,6 +335,9 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) t->type,tuners[t->type].name); strncpy(client->name, tuners[t->type].name, sizeof(client->name)); break; + case AUDC_SET_RADIO: + t->radio = 1; + break; /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a @@ -342,6 +346,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct video_channel *vc = arg; + t->radio = 0; if (t->type == TUNER_PHILIPS_SECAM) { t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0; set_tv_freq(client,t->freq); diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3231ad4b96f2..fc4bf1922651 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -172,8 +172,10 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o # obj-$(CONFIG_AIRONET4500) += aironet4500_core.o +obj-$(CONFIG_AIRONET4500_CS) += aironet4500_core.o obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o obj-$(CONFIG_AIRONET4500_PROC) += aironet4500_proc.o +obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o diff --git a/drivers/net/aironet4500_core.c b/drivers/net/aironet4500_core.c index 205a43d97a28..36554e46f41b 100644 --- a/drivers/net/aironet4500_core.c +++ b/drivers/net/aironet4500_core.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -2521,7 +2522,7 @@ static const char *aironet4500_core_version = struct net_device * aironet4500_devices[MAX_AWCS] = {NULL,NULL,NULL,NULL}; -static int awc_debug = 0; // 0xffffff; +int awc_debug = 0; // 0xffffff; static int p802_11_send = 0; // 1 static int awc_process_tx_results = 0; @@ -3197,9 +3198,7 @@ int awc_unregister_proc(void){ return 0; }; -#ifdef MODULE - -int init_module(void) +static int aironet_core_init(void) { // unsigned long flags; @@ -3210,11 +3209,12 @@ int init_module(void) } -void cleanup_module(void) +static void aironet_core_exit(void) { printk(KERN_INFO "aironet4500 unloading core module \n"); } - -#endif +module_init(aironet_core_init); +module_exit(aironet_core_exit); + diff --git a/drivers/net/aironet4500_proc.c b/drivers/net/aironet4500_proc.c index b9da62ab78a9..cefa41b88467 100644 --- a/drivers/net/aironet4500_proc.c +++ b/drivers/net/aironet4500_proc.c @@ -10,6 +10,7 @@ * */ #include +#include #include #include @@ -520,7 +521,7 @@ int awc_proc_unset_device(int device_number){ return 0; }; -int init_module(void) { +static int aironet_proc_init(void) { int i=0; AWC_ENTRY_EXIT_DEBUG("init_module"); @@ -539,7 +540,7 @@ int init_module(void) { }; -void cleanup_module(void){ +static void aironet_proc_exit(void){ int i=0; AWC_ENTRY_EXIT_DEBUG("cleanup_module"); @@ -552,4 +553,7 @@ void cleanup_module(void){ AWC_ENTRY_EXIT_DEBUG("exit"); }; -#endif // whole proc system styff \ No newline at end of file +module_init(aironet_proc_init); +module_exit(aironet_proc_exit); + +#endif // whole proc system styff diff --git a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c index 5d72f7778fd2..3ef45a297d45 100644 --- a/drivers/net/pcmcia/aironet4500_cs.c +++ b/drivers/net/pcmcia/aironet4500_cs.c @@ -15,8 +15,7 @@ static const char *awc_version = #include -//#include - +#include #include #include #include @@ -604,7 +603,7 @@ static int awc_event(event_t event, int priority, -int init_module(void) +static int aironet_cs_init(void) { servinfo_t serv; @@ -621,7 +620,7 @@ int init_module(void) return 0; } -void cleanup_module(void) +static void aironet_cs_exit(void) { DEBUG(0, "awc_cs: unloading %c ",'\n'); unregister_pcmcia_driver(&dev_info); @@ -636,4 +635,6 @@ void cleanup_module(void) // awc_detach(dev_list); } - +module_init(aironet_cs_init); +module_exit(aironet_cs_init); + diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index 7f14fc61b4bc..d111eba9d29b 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -49,16 +49,11 @@ #include "scsi.h" #include "hosts.h" #include +#include #include "pci2000.h" #include "psi_roy.h" -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) -#include -#endif -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) -#include -#endif //#define DEBUG 1 diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index b84ff1723bd1..57ade7eec92d 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -55,12 +56,6 @@ #include "pci2220i.h" #include "psi_dale.h" -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) -#include -#endif -#if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) -#include -#endif #define PCI2220I_VERSION "2.00" #define READ_CMD IDE_CMD_READ_MULTIPLE diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2ccf9ac095b1..daca9f800d3f 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -7,7 +7,7 @@ * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: - * Copyright (C) 1998, 1999 Douglas Gilbert + * Copyright (C) 1998 - 2000 Douglas Gilbert * * Modified 19-JAN-1998 Richard Gooch Devfs support * @@ -17,8 +17,8 @@ * any later version. * */ - static char * sg_version_str = "Version: 3.1.10 (20000123)"; - static int sg_version_num = 30110; /* 2 digits for each component */ + static char * sg_version_str = "Version: 3.1.12 (20000222)"; + static int sg_version_num = 30112; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -100,6 +100,8 @@ static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS; #define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */ #define SG_USER_MEM 4 /* memory belongs to user space */ +#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */ + static int sg_init(void); static int sg_attach(Scsi_Device *); @@ -109,8 +111,7 @@ static void sg_detach(Scsi_Device *); static Scsi_Cmnd * dummy_cmdp = 0; /* only used for sizeof */ - -static spinlock_t sg_request_lock = SPIN_LOCK_UNLOCKED; +static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; struct Scsi_Device_Template sg_template = { @@ -124,7 +125,6 @@ struct Scsi_Device_Template sg_template = detach:sg_detach }; -/* Need to add 'rwlock_t sg_rw_lock = RW_LOCK_UNLOCKED;' for list protection */ typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */ { @@ -137,7 +137,7 @@ typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */ char mapped; /* indicates kiobp has locked pages */ char buffer_mem_src; /* heap whereabouts of 'buffer' */ unsigned char cmd_opcode; /* first byte of command */ -} Sg_scatter_hold; /* 20 bytes long on i386 */ +} Sg_scatter_hold; /* 24 bytes long on i386 */ struct sg_device; /* forward declarations */ struct sg_fd; @@ -174,7 +174,7 @@ typedef struct sg_fd /* holds the state of a file descriptor */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ -} Sg_fd; /* 1212 bytes long on i386 */ +} Sg_fd; /* 2760 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ { @@ -186,7 +186,8 @@ typedef struct sg_device /* holds the state of each scsi generic device */ kdev_t i_rdev; /* holds device major+minor number */ char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ -} Sg_device; /* 24 bytes long on i386 */ + char detached; /* 0->attached, 1->detached pending removal */ +} Sg_device; /* 40 bytes long on i386 */ static int sg_fasync(int fd, struct file * filp, int mode); @@ -232,8 +233,10 @@ static int sg_allow_access(unsigned char opcode, char dev_type); static int sg_last_dev(void); static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static void sg_unmap_and(Sg_scatter_hold * schp, int free_also); +static Sg_device * sg_get_dev(int dev); + +static Sg_device ** sg_dev_arr = NULL; -static Sg_device * sg_dev_arr = NULL; static const int size_sg_header = sizeof(struct sg_header); static const int size_sg_io_hdr = sizeof(sg_io_hdr_t); static const int size_sg_iovec = sizeof(sg_iovec_t); @@ -248,10 +251,8 @@ static int sg_open(struct inode * inode, struct file * filp) Sg_fd * sfp; int res; - if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) - return -ENXIO; - sdp = &sg_dev_arr[dev]; - if ((! sdp->device) || (! sdp->device->host)) + sdp = sg_get_dev(dev); + if ((! sdp) || (! sdp->device) || (! sdp->device->host)) return -ENXIO; if (sdp->i_rdev != inode->i_rdev) printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n", @@ -664,6 +665,15 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, SCpnt->bufflen = srp->data.bufflen; SCpnt->underflow = 0; SCpnt->buffer = srp->data.buffer; + switch (hp->dxfer_direction) { + case SG_DXFER_TO_FROM_DEV: + case SG_DXFER_FROM_DEV: + SCpnt->sc_data_direction = SCSI_DATA_READ; break; + case SG_DXFER_TO_DEV: + SCpnt->sc_data_direction = SCSI_DATA_WRITE; break; + default: + SCpnt->sc_data_direction = SCSI_DATA_NONE; break; + } srp->data.k_use_sg = 0; srp->data.sglist_len = 0; srp->data.bufflen = 0; @@ -946,8 +956,7 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) Sg_fd * sfp; Sg_request * srp = NULL; - if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max) - || (NULL == (sdp = &sg_dev_arr[dev]))) { + if (NULL == (sdp = sg_get_dev(dev))) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; @@ -1060,11 +1069,11 @@ static int sg_detect(Scsi_Device * scsidp) case TYPE_WORM: case TYPE_TAPE: break; default: - printk("Detected scsi generic sg%c at scsi%d," - " channel %d, id %d, lun %d\n", - 'a'+sg_template.dev_noticed, + printk("Detected scsi generic sg%d at scsi%d," + " channel %d, id %d, lun %d, type %d\n", + sg_template.dev_noticed, scsidp->host->host_no, scsidp->channel, - scsidp->id, scsidp->lun); + scsidp->id, scsidp->lun, scsidp->type); } sg_template.dev_noticed++; return 1; @@ -1074,36 +1083,37 @@ static int sg_detect(Scsi_Device * scsidp) static int sg_init() { static int sg_registered = 0; - int size; + unsigned long flags = 0; - if (sg_template.dev_noticed == 0) return 0; + if ((sg_template.dev_noticed == 0) || sg_dev_arr) + return 0; + write_lock_irqsave(&sg_dev_arr_lock, flags); if(!sg_registered) { - if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) + if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) { printk("Unable to get major %d for generic SCSI device\n", SCSI_GENERIC_MAJOR); + write_unlock_irqrestore(&sg_dev_arr_lock, flags); return 1; } sg_registered++; } - /* If we have already been through here, return */ - if(sg_dev_arr) return 0; - SCSI_LOG_TIMEOUT(3, printk("sg_init\n")); - size = sizeof(Sg_device) * - (sg_template.dev_noticed + SG_EXTRA_DEVS); - sg_dev_arr = (Sg_device *)kmalloc(size, GFP_ATOMIC); - memset(sg_dev_arr, 0, size); + sg_template.dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP; + sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * + sizeof(Sg_device *), GFP_ATOMIC); if (NULL == sg_dev_arr) { printk("sg_init: no space for sg_dev_arr\n"); + write_unlock_irqrestore(&sg_dev_arr_lock, flags); return 1; } + memset(sg_dev_arr, 0, sg_template.dev_max * sizeof(Sg_device *)); + write_unlock_irqrestore(&sg_dev_arr_lock, flags); #ifdef CONFIG_PROC_FS sg_proc_init(); #endif /* CONFIG_PROC_FS */ - sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS; return 0; } @@ -1130,21 +1140,41 @@ __setup("sg_def_reserved_size=", sg_def_reserved_size_setup); static int sg_attach(Scsi_Device * scsidp) { - Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; + unsigned long flags = 0; int k; - if ((sg_template.nr_dev >= sg_template.dev_max) || (! sdp)) - { - scsidp->attached--; - printk("sg_attach: rejected since exceeds dev_max=%d\n", - sg_template.dev_max); - return 1; + write_lock_irqsave(&sg_dev_arr_lock, flags); + if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */ + Sg_device ** tmp_da; + int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP; + + tmp_da = (Sg_device **)kmalloc(tmp_dev_max * + sizeof(Sg_device *), GFP_ATOMIC); + if (NULL == tmp_da) { + scsidp->attached--; + write_unlock_irqrestore(&sg_dev_arr_lock, flags); + printk("sg_attach: device array cannot be resized\n"); + return 1; + } + memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *)); + memcpy(tmp_da, sg_dev_arr, sg_template.dev_max * sizeof(Sg_device *)); + kfree((char *)sg_dev_arr); + sg_dev_arr = tmp_da; + sg_template.dev_max = tmp_dev_max; } - for(k = 0; k < sg_template.dev_max; k++, sdp++) - if(! sdp->device) break; + for(k = 0; k < sg_template.dev_max; k++) + if(! sg_dev_arr[k]) break; + if(k >= sg_template.dev_max) panic ("sg_dev_arr corrupt"); - if(k >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)"); + sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC); + if (NULL == sdp) { + scsidp->attached--; + write_unlock_irqrestore(&sg_dev_arr_lock, flags); + printk("sg_attach: Sg_device cannot be allocated\n"); + return 1; + } SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); sdp->device = scsidp; @@ -1152,13 +1182,16 @@ static int sg_attach(Scsi_Device * scsidp) sdp->headfp= NULL; sdp->exclude = 0; sdp->sgdebug = 0; + sdp->detached = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k); sdp->de = devfs_register (scsidp->de, "generic", 7, DEVFS_FL_NONE, - SCSI_GENERIC_MAJOR, k, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &sg_fops, NULL); + SCSI_GENERIC_MAJOR, k, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &sg_fops, NULL); sg_template.nr_dev++; + sg_dev_arr[k] = sdp; + write_unlock_irqrestore(&sg_dev_arr_lock, flags); return 0; } @@ -1171,19 +1204,21 @@ static void sg_finish(void) static void sg_detach(Scsi_Device * scsidp) { - Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; unsigned long flags = 0; Sg_fd * sfp; Sg_request * srp; int k; - if (NULL == sdp) return; /* all is not well ... */ - for (k = 0; k < sg_template.dev_max; k++, sdp++) { - if(sdp->device != scsidp) + if (NULL == sg_dev_arr) + return; + write_lock_irqsave(&sg_dev_arr_lock, flags); +/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ + for (k = 0; k < sg_template.dev_max; k++) { + sdp = sg_dev_arr[k]; + if ((NULL == sdp) || (sdp->device != scsidp)) continue; /* dirty but lowers nesting */ if (sdp->headfp) { -/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ - spin_lock_irqsave(&sg_request_lock, flags); sfp = sdp->headfp; while (sfp) { srp = sfp->headrp; @@ -1194,23 +1229,28 @@ static void sg_detach(Scsi_Device * scsidp) } sfp = sfp->nextfp; } - spin_unlock_irqrestore(&sg_request_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, flags); SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k)); scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */ + devfs_unregister (sdp->de); + sdp->de = NULL; + sdp->detached = 1; + write_lock_irqsave(&sg_dev_arr_lock, flags); } else { SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); - sdp->device = NULL; + devfs_unregister (sdp->de); + kfree((char *)sdp); + sg_dev_arr[k] = NULL; } - devfs_unregister (sdp->de); - sdp->de = NULL; scsidp->attached--; sg_template.nr_dev--; /* avoid associated device /dev/sg? being incremented * each time module is inserted/removed , */ sg_template.dev_noticed--; - return; + break; } + write_unlock_irqrestore(&sg_dev_arr_lock, flags); return; } @@ -1252,7 +1292,7 @@ extern void scsi_old_times_out (Scsi_Cmnd * SCpnt); /* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ static void sg_shorten_timeout(Scsi_Cmnd * scpnt) -{ +{ /* assumed to be called with sg_dev_arr_lock held */ #if 0 /* scsi_syms.c is very miserly about exported functions */ scsi_delete_timer(scpnt); if (! scpnt) @@ -1265,9 +1305,10 @@ static void sg_shorten_timeout(Scsi_Cmnd * scpnt) scsi_old_times_out); #else unsigned long flags = 0; - spin_lock_irqsave(&sg_request_lock, flags); + + write_unlock_irqrestore(&sg_dev_arr_lock, flags); scsi_sleep(HZ); /* just sleep 1 second and hope ... */ - spin_unlock_irqrestore(&sg_request_lock, flags); + write_lock_irqsave(&sg_dev_arr_lock, flags); #endif } @@ -1986,7 +2027,7 @@ static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) } static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) -{ +{ /* if this is to be locked remember that it is called from _bh */ Sg_request * srp; Sg_request * tsrp; int dirty = 0; @@ -1994,7 +2035,6 @@ static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) srp = sfp->headrp; if (srp) { -/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ while (srp) { tsrp = srp->nextrp; if (srp->done) @@ -2027,6 +2067,18 @@ SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", sfp->parentdp = NULL; SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp)); sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src); + if (sdp->detached && (NULL == sdp->headfp)) { + int k, maxd; + + maxd = sg_template.dev_max; + for (k = 0; k < maxd; ++k) { + if (sdp == sg_dev_arr[k]) + break; + } + if (k < maxd) + sg_dev_arr[k] = NULL; + kfree((char *)sdp); + } res = 1; } else { @@ -2264,15 +2316,31 @@ static int sg_allow_access(unsigned char opcode, char dev_type) static int sg_last_dev() -{ +{ /* assumed to be called with sg_dev_arr_lock held */ int k; + for (k = sg_template.dev_max - 1; k >= 0; --k) { - if (sg_dev_arr[k].device) + if (sg_dev_arr[k] && sg_dev_arr[k]->device) return k + 1; } return 0; /* origin 1 */ } +static Sg_device * sg_get_dev(int dev) +{ + Sg_device * sdp; + + if ((NULL == sg_dev_arr) || (dev < 0)) + return NULL; + read_lock(&sg_dev_arr_lock); + if (dev < sg_template.dev_max) + sdp = sg_dev_arr[dev]; + else + sdp = NULL; + read_unlock(&sg_dev_arr_lock); + return sdp; +} + #ifdef CONFIG_PROC_FS static struct proc_dir_entry * sg_proc_sgp = NULL; @@ -2427,36 +2495,35 @@ static int sg_proc_debug_read(char * buffer, char ** start, off_t offset, static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - const Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; const sg_io_hdr_t * hp; int j, max_dev; if (NULL == sg_dev_arr) { - PRINT_PROC("sg_dev_arr NULL, death is imminent\n"); + PRINT_PROC("sg_dev_arr NULL, driver not initialized\n"); return 1; } + read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); PRINT_PROC("dev_max=%d max_active_device=%d (origin 1)\n", sg_template.dev_max, max_dev); PRINT_PROC(" scsi_dma_free_sectors=%u sg_pool_secs_aval=%d " "def_reserved_size=%d\n", scsi_dma_free_sectors, sg_pool_secs_avail, sg_big_buff); - max_dev = sg_last_dev(); - for (j = 0; j < max_dev; ++j, ++sdp) { - if (sdp) { + for (j = 0; j < max_dev; ++j) { + if ((sdp = sg_dev_arr[j])) { Sg_fd * fp; Sg_request * srp; struct scsi_device * scsidp; - int dev, k, blen, usg, crep; + int dev, k, blen, usg; if (! (scsidp = sdp->device)) { PRINT_PROC("device %d detached ??\n", j); continue; } dev = MINOR(sdp->i_rdev); - crep = 'a' + dev; - PRINT_PROC(" >>> device=%d(sg%c) ", dev, crep > 126 ? '?' : crep); + PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev); PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d sg_tablesize=%d" " excl=%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->host->hostt->emulated, @@ -2496,6 +2563,7 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, } } } + read_unlock(&sg_dev_arr_lock); return 1; } @@ -2506,23 +2574,23 @@ static int sg_proc_dev_read(char * buffer, char ** start, off_t offset, static int sg_proc_dev_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - const Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; int j, max_dev; struct scsi_device * scsidp; + read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); - for (j = 0; j < max_dev; ++j, ++sdp) { - if (sdp) { - if (! (scsidp = sdp->device)) { - PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); - continue; - } + for (j = 0; j < max_dev; ++j) { + sdp = sg_dev_arr[j]; + if (sdp && (scsidp = sdp->device)) PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, (int)scsidp->type, (int)scsidp->disconnect, (int)scsidp->queue_depth, (int)scsidp->tagged_queue); - } + else + PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); } + read_unlock(&sg_dev_arr_lock); return 1; } @@ -2544,20 +2612,21 @@ static int sg_proc_devstrs_read(char * buffer, char ** start, off_t offset, static int sg_proc_devstrs_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - const Sg_device * sdp = sg_dev_arr; + Sg_device * sdp; int j, max_dev; struct scsi_device * scsidp; + read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); - for (j = 0; j < max_dev; ++j, ++sdp) { - if (sdp) { - if ((scsidp = sdp->device)) - PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n", - scsidp->vendor, scsidp->model, scsidp->rev); - else - PRINT_PROC("\n"); - } + for (j = 0; j < max_dev; ++j) { + sdp = sg_dev_arr[j]; + if (sdp && (scsidp = sdp->device)) + PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n", + scsidp->vendor, scsidp->model, scsidp->rev); + else + PRINT_PROC("\n"); } + read_unlock(&sg_dev_arr_lock); return 1; } @@ -2569,12 +2638,16 @@ static int sg_proc_host_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { struct Scsi_Host * shp; + int k; - for (shp = scsi_hostlist; shp; shp = shp->next) + for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { + for ( ; k < shp->host_no; ++k) + PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\n"); PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n", shp->unique_id, shp->host_busy, shp->cmd_per_lun, shp->sg_tablesize, (int)shp->unchecked_isa_dma, (int)shp->hostt->emulated); + } return 1; } @@ -2597,10 +2670,14 @@ static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { struct Scsi_Host * shp; + int k; - for (shp = scsi_hostlist; shp; shp = shp->next) + for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { + for ( ; k < shp->host_no; ++k) + PRINT_PROC("\n"); PRINT_PROC("%s\n", shp->hostt->info ? shp->hostt->info(shp) : (shp->hostt->name ? shp->hostt->name : "")); + } return 1; } diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 39659ca553c3..9f0943d3d7e3 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -9,11 +9,11 @@ if [ ! "$CONFIG_USB" = "n" ]; then comment 'USB Controllers' dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB - if [ "$CONFIG_USB_UHCI" != "n" ]; then + if [ "$CONFIG_USB_UHCI" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' USB-UHCI High Bandwidth (EXPERIMENTAL)' CONFIG_USB_UHCI_HIGH_BANDWIDTH fi dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB - if [ "$CONFIG_USB_UHCI_ALT" != "n" ]; then + if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE fi dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB @@ -30,9 +30,11 @@ comment 'USB Devices' if [ "$CONFIG_USB_SERIAL" != "n" ]; then bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC bool ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR - bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT - bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO - bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA + if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then + bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT + bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO + bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA + fi fi dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c index db6e69c90d7e..1ddbbcf60e96 100644 --- a/drivers/usb/devices.c +++ b/drivers/usb/devices.c @@ -165,8 +165,10 @@ static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct u if (start > end) return start; start += sprintf(start, format_endpt, desc->bEndpointAddress, + (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL + ? 'B' : /* bidirectional */ (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O', - desc->bmAttributes, EndpointType[desc->bmAttributes & 3], + desc->bmAttributes, EndpointType[desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK], desc->wMaxPacketSize, desc->bInterval); return start; } diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c index a641e098bca3..7053d56d746d 100644 --- a/drivers/usb/inode.c +++ b/drivers/usb/inode.c @@ -212,9 +212,7 @@ static int usbdevfs_revalidate(struct dentry *dentry, int flags) } static struct dentry_operations usbdevfs_dentry_operations = { - usbdevfs_revalidate, /* d_revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ + d_revalidate: usbdevfs_revalidate, }; static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry) diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 573e0485deb6..6b9eba17a5d2 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -410,21 +410,27 @@ static void usb_find_drivers(struct usb_device *dev) { unsigned ifnum; unsigned rejected = 0; + unsigned claimed = 0; for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) { /* if this interface hasn't already been claimed */ if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) { if (usb_find_interface_driver(dev, ifnum)) rejected++; + else + claimed++; } } if (rejected) dbg("unhandled interfaces on device"); + if (!claimed) { + warn("This device is not recognized by any installed USB driver."); #ifdef DEBUG - usb_show_device(dev); + usb_show_device(dev); #endif + } } /* diff --git a/drivers/video/Config.in b/drivers/video/Config.in index 70db39ddb49f..4de32c098c50 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -174,6 +174,7 @@ if [ "$CONFIG_FB" = "y" ]; then tristate ' Mac variable bpp packed pixels support' CONFIG_FBCON_MAC tristate ' VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES tristate ' VGA characters/attributes support' CONFIG_FBCON_VGA + tristate ' HGA monochrome support (EXPERIMENTAL)' CONFIG_FBCON_HGA else # Guess what we need if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \ diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index 9207df06efcb..264cf14a7956 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -16,22 +16,6 @@ #include - -static void memcpy_fs(int fsfromto, void *to, void *from, int len) -{ - switch (fsfromto) { - case 0: - memcpy(to, from, len); - return; - case 1: - copy_from_user(to, from, len); - return; - case 2: - copy_to_user(to, from, len); - return; - } -} - static u16 red2[] = { 0x0000, 0xaaaa }; @@ -148,11 +132,30 @@ void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) if (size < 0) return; size *= sizeof(u16); - memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size); - memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size); - memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size); - if (from->transp && to->transp) - memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size); + + switch (fsfromto) { + case 0: + memcpy(to->red+tooff, from->red+fromoff, size); + memcpy(to->green+tooff, from->green+fromoff, size); + memcpy(to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy(to->transp+tooff, from->transp+fromoff, size); + break; + case 1: + copy_from_user(to->red+tooff, from->red+fromoff, size); + copy_from_user(to->green+tooff, from->green+fromoff, size); + copy_from_user(to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + copy_from_user(to->transp+tooff, from->transp+fromoff, size); + break; + case 2: + copy_to_user(to->red+tooff, from->red+fromoff, size); + copy_to_user(to->green+tooff, from->green+fromoff, size); + copy_to_user(to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + copy_to_user(to->transp+tooff, from->transp+fromoff, size); + break; + } } diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 431a90a16b1d..bffa6b02ef35 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -7,6 +7,8 @@ * * History: * + * - Revision 0.1.4 (24 Jan 2000): fixed a bug in hga_card_detect() for + * HGA-only systems * - Revision 0.1.3 (22 Jan 2000): modified for the new fb_info structure * screen is cleared after rmmod * virtual resolutions @@ -18,11 +20,10 @@ * - First release (25 Nov 1999) * * This file is subject to the terms and conditions of the GNU General Public - * License. See the file README.legal in the main directory of this archive + * License. See the file COPYING in the main directory of this archive * for more details. */ -#include #include #include #include @@ -141,6 +142,8 @@ static struct display disp; /* Don't assume that tty1 will be the initial current console. */ static int currcon = -1; +static int release_io_port = 0; +static int release_io_ports = 0; #ifdef MODULE static char *font = NULL; @@ -290,9 +293,10 @@ static int hga_card_detect(void) hga_vram_base); return 0; } - if (!request_region(0x3b0, 16, "hgafb")) { - printk(KERN_ERR "hgafb: cannot reserve io ports\n"); - } + if (request_region(0x3b0, 12, "hgafb")) + release_io_ports = 1; + if (request_region(0x3bf, 1, "hgafb")) + release_io_port = 1; /* do a memory check */ @@ -717,7 +721,8 @@ static void hgafb_cleanup(struct fb_info *info) hga_txt_mode(); hga_clear_screen(); unregister_framebuffer(info); - release_region(0x3b0, 16); + if (release_io_ports) release_region(0x3b0, 12); + if (release_io_port) release_region(0x3bf, 1); release_mem_region(hga_vram_base, hga_vram_len); } #endif /* MODULE */ diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c index 8228d5c8bd25..56a0526477a4 100644 --- a/drivers/video/vgacon.c +++ b/drivers/video/vgacon.c @@ -94,6 +94,8 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, static void vgacon_invert_region(struct vc_data *c, u16 *p, int count); static unsigned long vgacon_uni_pagedir[2]; +void clear_status_line( void ); + /* Description of the hardware situation */ static unsigned long vga_vram_base; /* Base of video memory */ diff --git a/drivers/zorro/Makefile b/drivers/zorro/Makefile index a8c66ed099fc..8e14649b267a 100644 --- a/drivers/zorro/Makefile +++ b/drivers/zorro/Makefile @@ -9,24 +9,17 @@ # parent makefile. # -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) - L_TARGET := zorro.a -# Nasty trick as nobody references zorrosyms.o, but we still want it linked. -ifeq ($(CONFIG_MODULES),y) -O_TARGET = zorro_syms.o -OX_OBJS = zorrosyms.o -O_OBJS = zorro.o names.o -L_OBJS := zorro_syms.o -else -L_OBJS := zorro.o names.o -endif +# Nasty trick as we need to link files with no references from the outside. +O_TARGET := zorro_core.o +L_OBJS := zorro_core.o +OX_OBJS := zorro.o ifdef CONFIG_PROC_FS -L_OBJS += proc.o +O_OBJS += proc.o endif +L_OBJS += names.o + include $(TOPDIR)/Rules.make diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index 11b485b0501b..28b7c4272dd8 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -120,14 +120,18 @@ static int __init zorro_proc_attach_device(u_int slot) return 0; } -void __init zorro_proc_init(void) +static int __init zorro_proc_init(void) { u_int slot; - if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO)) - return; - proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus); - create_proc_info_entry("devices", 0, proc_bus_zorro_dir, get_zorro_dev_info); - for (slot = 0; slot < zorro_num_autocon; slot++) - zorro_proc_attach_device(slot); + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { + proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus); + create_proc_info_entry("devices", 0, proc_bus_zorro_dir, + get_zorro_dev_info); + for (slot = 0; slot < zorro_num_autocon; slot++) + zorro_proc_attach_device(slot); + } + return 0; } + +__initcall(zorro_proc_init); diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 227677c4d7a2..b1d164d3578c 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -10,7 +10,7 @@ * for more details. */ -#include +#include #include #include #include @@ -75,6 +75,8 @@ struct zorro_dev *zorro_find_device(zorro_id id, struct zorro_dev *from) * Possible uses: * - z2ram device * - SCSI DMA bounce buffers + * + * FIXME: use the normal resource management */ u32 zorro_unused_z2ram[4] = { 0, 0, 0, 0 }; @@ -151,8 +153,8 @@ void __init zorro_init(void) if (m68k_memory[i].addr < 16*1024*1024) mark_region(m68k_memory[i].addr, m68k_memory[i].addr+m68k_memory[i].size, 0); - -#ifdef CONFIG_PROC_FS - zorro_proc_init(); -#endif } + + +EXPORT_SYMBOL(zorro_find_device); +EXPORT_SYMBOL(zorro_unused_z2ram); diff --git a/drivers/zorro/zorrosyms.c b/drivers/zorro/zorrosyms.c deleted file mode 100644 index d4ac5da87871..000000000000 --- a/drivers/zorro/zorrosyms.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * $Id: zorrosyms.c,v 1.1.2.1 1998/06/07 23:21:02 geert Exp $ - * - * Zorro Bus Services -- Exported Symbols - * - * Copyright (C) 1998-2000 Geert Uytterhoeven - */ - -#include -#include -#include - - /* Board configuration */ - -EXPORT_SYMBOL(zorro_find_device); - - /* Z2 memory */ - -EXPORT_SYMBOL(zorro_unused_z2ram); - diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index a7da5eedaf17..794097871caf 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -256,12 +256,8 @@ adfs_compare(struct dentry *parent, struct qstr *entry, struct qstr *name) } struct dentry_operations adfs_dentry_operations = { - NULL, /* revalidate */ - adfs_hash, - adfs_compare, - NULL, /* delete = called by dput */ - NULL, /* release - called by d_free */ - NULL /* iput - called by dentry_iput */ + d_hash: adfs_hash, + d_compare: adfs_compare, }; struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry) diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 43085a64bd40..38e5bccbe31e 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -44,10 +44,8 @@ affs_intl_toupper(unsigned int ch) static int affs_hash_dentry(struct dentry *, struct qstr *); static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); struct dentry_operations affs_dentry_operations = { - NULL, /* d_validate */ - affs_hash_dentry, /* d_hash */ - affs_compare_dentry, /* d_compare */ - NULL /* d_delete */ + d_hash: affs_hash_dentry, + d_compare: affs_compare_dentry, }; /* diff --git a/fs/autofs/root.c b/fs/autofs/root.c index ea517f0b11cb..35afe3cdc4f1 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -174,9 +174,7 @@ static int autofs_revalidate(struct dentry * dentry, int flags) } static struct dentry_operations autofs_dentry_operations = { - autofs_revalidate, /* d_revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ + d_revalidate: autofs_revalidate, }; static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index ec16d8fa5c38..c329b725067f 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -707,7 +707,9 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) __MOD_INC_USE_COUNT(current->binfmt->module); #ifndef VM_STACK_FLAGS + lock_kernel(); current->executable = dget(bprm->dentry); + unlock_kernel(); #endif compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c index 2c76e55928af..d89bd9ca8e11 100644 --- a/fs/binfmt_em86.c +++ b/fs/binfmt_em86.c @@ -42,7 +42,9 @@ static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs) } bprm->sh_bang++; /* Well, the bang-shell is implicit... */ + lock_kernel(); dput(bprm->dentry); + unlock_kernel(); bprm->dentry = NULL; /* Unlike in the script case, we don't have to do any hairy @@ -78,7 +80,9 @@ static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs) * Note that we use open_namei() as the name is now in kernel * space, and we don't need to copy it. */ + lock_kernel(); dentry = open_namei(interp, 0, 0); + unlock_kernel(); if (IS_ERR(dentry)) return PTR_ERR(dentry); diff --git a/fs/buffer.c b/fs/buffer.c index 6d31f18e864a..4e79483e408a 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2474,6 +2474,7 @@ asmlinkage long sys_bdflush(int func, long data) */ int bdflush(void * unused) { + struct task_struct *tsk = current; int flushed; /* * We have a bare-bones task_struct, and really should fill @@ -2481,17 +2482,17 @@ int bdflush(void * unused) * display semi-sane things. Not real crucial though... */ - current->session = 1; - current->pgrp = 1; - sprintf(current->comm, "kflushd"); - bdflush_tsk = current; + tsk->session = 1; + tsk->pgrp = 1; + strcpy(tsk->comm, "kflushd"); + bdflush_tsk = tsk; /* avoid getting signals */ - spin_lock_irq(¤t->sigmask_lock); - flush_signals(current); - sigfillset(¤t->blocked); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + spin_lock_irq(&tsk->sigmask_lock); + flush_signals(tsk); + sigfillset(&tsk->blocked); + recalc_sigpending(tsk); + spin_unlock_irq(&tsk->sigmask_lock); for (;;) { CHECK_EMERGENCY_SYNC diff --git a/fs/coda/dir.c b/fs/coda/dir.c index dac8e8884fc5..8e25fccd674a 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -57,10 +57,8 @@ int coda_hasmknod = 0; struct dentry_operations coda_dentry_operations = { - coda_dentry_revalidate, /* revalidate */ - NULL, /* hash */ - NULL, /* compare */ - coda_dentry_delete /* delete */ + d_revalidate: coda_dentry_revalidate, + d_delete: coda_dentry_delete, }; struct inode_operations coda_dir_inode_operations = @@ -541,9 +539,7 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir) result = coda_venus_readdir(&open_file, dirent, filldir); } else { /* potemkin case: we are handed a directory inode */ - down(&cnp->c_ovp->i_sem); - result = open_file.f_op->readdir(&open_file, dirent, filldir); - up(&cnp->c_ovp->i_sem); + result = vfs_readdir(&open_file, filldir, dirent); } coda_restore_codafile(inode, file, cnp->c_ovp, &open_file); EXIT; diff --git a/fs/devfs/base.c b/fs/devfs/base.c index ad50e21b9f50..f2e09cd6ec87 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -426,6 +426,12 @@ Removed . Work sponsored by SGI. v0.92 + 20000306 Richard Gooch + Added DEVFS_FL_NO_PERSISTENCE flag. + Removed unnecessary call to in + . + Work sponsored by SGI. + v0.93 */ #include #include @@ -460,7 +466,7 @@ #include #include -#define DEVFS_VERSION "0.92 (20000203)" +#define DEVFS_VERSION "0.93 (20000306)" #ifndef DEVFS_NAME # define DEVFS_NAME "devfs" @@ -601,6 +607,7 @@ struct devfs_entry unsigned char registered:1; unsigned char show_unreg:1; unsigned char hide:1; + unsigned char no_persistence:1; char name[1]; /* This is just a dummy: the allocated array is bigger. This is NULL-terminated */ }; @@ -1240,6 +1247,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, de->show_unreg = ( (boot_options & OPTION_SHOW) || (flags & DEVFS_FL_SHOW_UNREG) ) ? TRUE : FALSE; de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE; + de->no_persistence = (flags & DEVFS_FL_NO_PERSISTENCE) ? TRUE : FALSE; devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT); return de; } /* End Function devfs_register */ @@ -1983,24 +1991,17 @@ static void update_devfs_inode_from_entry (struct devfs_inode *di) else { if (di->de->u.fcb.auto_owner) - { - mode_t mode = di->de->mode; - - di->mode = (mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO; - } - else - { - di->mode = di->de->mode; - } + di->mode = (di->de->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO; + else di->mode = di->de->mode; di->uid = di->de->u.fcb.default_uid; di->gid = di->de->u.fcb.default_gid; } } /* End Function update_devfs_inode_from_entry */ -static struct devfs_inode *create_devfs_inode (struct devfs_entry *entry, +static struct devfs_inode *create_devfs_inode (struct devfs_entry *de, struct fs_info *fs_info) /* [SUMMARY] Create a devfs inode entry. - The devfs entry to associate the new inode with. + The devfs entry to associate the new inode with. The FS info. [RETURNS] A pointer to the devfs inode on success, else NULL. */ @@ -2032,12 +2033,12 @@ static struct devfs_inode *create_devfs_inode (struct devfs_entry *entry, di->nlink = 1; fs_info->table[fs_info->num_inodes] = di; ++fs_info->num_inodes; - di->de = entry; + di->de = de; di->fs_info = fs_info; - di->prev = entry->last_inode; - if (entry->first_inode == NULL) entry->first_inode = di; - else entry->last_inode->next = di; - entry->last_inode = di; + di->prev = de->last_inode; + if (de->first_inode == NULL) de->first_inode = di; + else de->last_inode->next = di; + de->last_inode = di; update_devfs_inode_from_entry (di); #ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_I_CREATE) @@ -2183,8 +2184,9 @@ static int get_removable_partition (struct devfs_entry *dir, const char *name, /* Superblock operations follow */ -extern struct inode_operations devfs_iops; +static struct inode_operations devfs_iops; static struct file_operations devfs_fops; +static struct inode_operations devfs_symlink_iops; static void devfs_read_inode (struct inode *inode) { @@ -2206,22 +2208,29 @@ static void devfs_read_inode (struct inode *inode) inode->i_blocks = 0; inode->i_blksize = 1024; inode->i_op = &devfs_iops; - inode->i_fop = &devfs_fops; inode->i_rdev = NODEV; - if ( S_ISCHR (di->mode) ) + if ( S_ISCHR (di->mode) ) { inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major, di->de->u.fcb.u.device.minor); - else if ( S_ISBLK (di->mode) ) - { + inode->i_fop = &devfs_fops; + } else if ( S_ISBLK (di->mode) ) { inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major, di->de->u.fcb.u.device.minor); inode->i_bdev = bdget (inode->i_rdev); if (inode->i_bdev) inode->i_bdev->bd_op = di->de->u.fcb.ops; else printk ("%s: read_inode(%d): no block device from bdget()\n", DEVFS_NAME, (int) inode->i_ino); + inode->i_fop = &devfs_fops; + } else if ( S_ISFIFO (di->mode) ) { + inode->i_fop = &def_fifo_fops; + } else if ( S_ISREG (di->mode) ) { + inode->i_size = di->de->u.fcb.u.file.size; + inode->i_fop = &devfs_fops; + } else if (S_ISLNK(di->mode)) { + inode->i_op = &devfs_symlink_iops; + } else { + inode->i_fop = &devfs_fops; } - else if ( S_ISFIFO (di->mode) ) inode->i_fop = &def_fifo_fops; - else if ( S_ISREG (di->mode) ) inode->i_size = di->de->u.fcb.u.file.size; inode->i_mode = di->mode; inode->i_uid = di->uid; inode->i_gid = di->gid; @@ -2438,11 +2447,10 @@ static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir) if (di == NULL) { if (fs_info->require_explicit) continue; - /* Have to create the inode right now */ + /* Have to create the inode right now to get the inum */ di = create_devfs_inode (de, fs_info); if (di == NULL) return -ENOMEM; } - else if (di->ctime == 0) update_devfs_inode_from_entry (di); err = (*filldir) (dirent, de->name, de->namelen, file->f_pos, di->ino); if (err == -EINVAL) break; @@ -2659,6 +2667,7 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) /* Create an inode, now that the driver information is available */ if (di == NULL) di = create_devfs_inode (de, fs_info); + else if (de->no_persistence) update_devfs_inode_from_entry (di); else if (di->ctime == 0) update_devfs_inode_from_entry (di); else di->mode = (de->mode & ~S_IALLUGO) | (di->mode & S_IALLUGO); if (di == NULL) return 1; @@ -2784,6 +2793,7 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) } /* Create an inode, now that the driver information is available */ if (di == NULL) di = create_devfs_inode (de, fs_info); + else if (de->no_persistence) update_devfs_inode_from_entry (di); else if (di->ctime == 0) update_devfs_inode_from_entry (di); else di->mode = (de->mode & ~S_IALLUGO) | (di->mode & S_IALLUGO); if (di == NULL) return ERR_PTR (-ENOMEM); @@ -3079,49 +3089,24 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode, static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen) { - struct inode *inode = dentry->d_inode; - struct devfs_inode *di; + struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode); + char *name = ERR_PTR(-ENOENT); - if ( !inode || !S_ISLNK (inode->i_mode) ) return -EINVAL; - di = get_devfs_inode_from_vfs_inode (inode); - if (di == NULL) return -ENOENT; - if (!di->de->registered) return -ENOENT; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_RLINK) - printk ("%s: readlink(): dentry: %p\n", DEVFS_NAME, dentry); -#endif - if (buflen > di->de->u.symlink.length + 1) - buflen = di->de->u.symlink.length + 1; - if (copy_to_user (buffer, di->de->u.symlink.linkname, buflen) == 0) - return buflen; - return -EFAULT; + if (di && di->de->registered) + name = di->de->u.symlink.linkname; + return vfs_readlink(dentry, buffer, buflen, name); } /* End Function devfs_readlink */ static struct dentry *devfs_follow_link (struct dentry *dentry, struct dentry *base, unsigned int follow) { - struct inode *inode = dentry->d_inode; - struct devfs_inode *di; + struct devfs_inode *di=get_devfs_inode_from_vfs_inode(dentry->d_inode); + char *name = ERR_PTR(-ENOENT); - if ( !inode || !S_ISLNK (inode->i_mode) ) - { - dget (dentry); - dput (base); - return dentry; - } -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_FLINK) - printk ("%s: follow_link(): dentry: %p\n", DEVFS_NAME, dentry); -#endif - di = get_devfs_inode_from_vfs_inode (inode); - if ( (di == NULL) || !di->de->registered ) - { - dput (base); - return ERR_PTR (-ENOENT); - } - base = lookup_dentry (di->de->u.symlink.linkname, base, follow); - return base; + if (di && di->de->registered) + name = di->de->u.symlink.linkname; + return vfs_follow_link(dentry, base, follow, name); } /* End Function devfs_follow_link */ static struct inode_operations devfs_iops = @@ -3133,6 +3118,11 @@ static struct inode_operations devfs_iops = mkdir: devfs_mkdir, rmdir: devfs_rmdir, mknod: devfs_mknod, + setattr: devfs_notify_change, +}; + +static struct inode_operations devfs_symlink_iops = +{ readlink: devfs_readlink, follow_link: devfs_follow_link, setattr: devfs_notify_change, diff --git a/fs/devpts/root.c b/fs/devpts/root.c index ed62586639c0..93df8a8ec4f1 100644 --- a/fs/devpts/root.c +++ b/fs/devpts/root.c @@ -30,9 +30,7 @@ struct inode_operations devpts_root_inode_operations = { }; static struct dentry_operations devpts_dentry_operations = { - devpts_revalidate, /* d_revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ + d_revalidate: devpts_revalidate, }; /* diff --git a/fs/exec.c b/fs/exec.c index 694bba67518a..1b881e12312b 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -84,6 +84,7 @@ int open_dentry(struct dentry * dentry, int mode) struct list_head * l = NULL; int fd, error; + lock_kernel(); if (inode->i_sb) l = &inode->i_sb->s_files; @@ -111,6 +112,7 @@ int open_dentry(struct dentry * dentry, int mode) fd_install(fd, f); dget(dentry); } + unlock_kernel(); return fd; out_filp: @@ -120,6 +122,7 @@ out_filp: out_fd: put_unused_fd(fd); out: + unlock_kernel(); return error; } diff --git a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c index b8bcbd9e6d58..3a2e4ea820ec 100644 --- a/fs/fat/fatfs_syms.c +++ b/fs/fat/fatfs_syms.c @@ -52,6 +52,7 @@ EXPORT_SYMBOL(unlock_fat); EXPORT_SYMBOL(fat_dir_ioctl); EXPORT_SYMBOL(fat_add_entries); EXPORT_SYMBOL(fat_dir_empty); +EXPORT_SYMBOL(fat_truncate); int init_fat_fs(void) { diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c index fb68e9ab21e6..0caa01ad0514 100644 --- a/fs/hfs/sysdep.c +++ b/fs/hfs/sysdep.c @@ -24,12 +24,10 @@ static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); static void hfs_dentry_iput(struct dentry *, struct inode *); struct dentry_operations hfs_dentry_operations = { - hfs_revalidate_dentry, /* d_revalidate(struct dentry *) */ - hfs_hash_dentry, /* d_hash */ - hfs_compare_dentry, /* d_compare */ - NULL, /* d_delete(struct dentry *) */ - NULL, /* d_release(struct dentry *) */ - hfs_dentry_iput /* d_iput(struct dentry *, struct inode *) */ + d_revalidate: hfs_revalidate_dentry, + d_hash: hfs_hash_dentry, + d_compare: hfs_compare_dentry, + d_iput: hfs_dentry_iput, }; /* diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c index b5c3cf2e8eac..3aad4ba50ce2 100644 --- a/fs/hpfs/dentry.c +++ b/fs/hpfs/dentry.c @@ -50,10 +50,8 @@ int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) } struct dentry_operations hpfs_dentry_operations = { - NULL, /* d_validate */ - hpfs_hash_dentry, /* d_hash */ - hpfs_compare_dentry, /* d_compare */ - NULL /* d_delete */ + d_hash: hpfs_hash_dentry, + d_compare: hpfs_compare_dentry, }; void hpfs_set_dentry_operations(struct dentry *dentry) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index b4a633e9fc09..996d5ba68d50 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -84,29 +84,21 @@ static struct super_operations isofs_sops = { static struct dentry_operations isofs_dentry_ops[] = { { - NULL, /* d_revalidate */ - isofs_hash, - isofs_cmp, - NULL /* d_delete */ + d_hash: isofs_hash, + d_compare: isofs_cmp, }, { - NULL, /* d_revalidate */ - isofs_hashi, - isofs_cmpi, - NULL /* d_delete */ + d_hash: isofs_hashi, + d_compare: isofs_cmpi, }, #ifdef CONFIG_JOLIET { - NULL, /* d_revalidate */ - isofs_hash_ms, - isofs_cmp_ms, - NULL /* d_delete */ + d_hash: isofs_hash_ms, + d_compare: isofs_cmp_ms, }, { - NULL, /* d_revalidate */ - isofs_hashi_ms, - isofs_cmpi_ms, - NULL /* d_delete */ + d_hash: isofs_hashi_ms, + d_compare: isofs_cmpi_ms, } #endif }; diff --git a/fs/minix/namei.c b/fs/minix/namei.c index baef110d2c3d..c18b46a3750d 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -106,13 +106,9 @@ static int minix_hash(struct dentry *dentry, struct qstr *qstr) #endif struct dentry_operations minix_dentry_operations = { - 0, /* revalidate */ #ifndef NO_TRUNCATE - minix_hash, -#else - 0, + d_hash: minix_hash, #endif - 0 /* compare */ }; static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry) diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index d74c7104947d..87a49fb47726 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -200,12 +200,8 @@ old_compare: static struct dentry_operations msdos_dentry_operations = { - NULL, /* d_revalidate */ - msdos_hash, - msdos_cmp, - NULL, /* d_delete */ - NULL, - NULL + d_hash: msdos_hash, + d_compare: msdos_cmp, }; /* diff --git a/fs/namei.c b/fs/namei.c index 102f0e43276b..5f148b5a826a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -403,10 +403,10 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned if (IS_ERR(dentry)) break; } - } - /* Check mountpoints.. */ - dentry = follow_mount(dentry); + /* Check mountpoints.. */ + dentry = follow_mount(dentry); + } base = do_follow_link(base, dentry, flags); if (IS_ERR(base)) @@ -577,6 +577,9 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode) { int error; + mode &= S_IALLUGO & ~current->fs->umask; + mode |= S_IFREG; + error = may_create(dir, dentry); if (error) goto exit_lock; @@ -610,9 +613,6 @@ struct dentry * open_namei(const char * pathname, int flag, int mode) struct inode *inode; struct dentry *dentry; - mode &= S_IALLUGO & ~current->fs->umask; - mode |= S_IFREG; - dentry = lookup_dentry(pathname, NULL, lookup_flags(flag)); if (IS_ERR(dentry)) return dentry; @@ -739,14 +739,36 @@ exit: return ERR_PTR(error); } +int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + int error = -EPERM; + + mode &= ~current->fs->umask; + + if (!S_ISFIFO(mode) && !capable(CAP_MKNOD)) + goto exit_lock; + + error = may_create(dir, dentry); + if (error) + goto exit_lock; + + error = -EPERM; + if (!dir->i_op || !dir->i_op->mknod) + goto exit_lock; + + DQUOT_INIT(dir); + error = dir->i_op->mknod(dir, dentry, mode, dev); +exit_lock: + return error; +} + struct dentry * do_mknod(const char * filename, int mode, dev_t dev) { int error; struct dentry *dir; struct dentry *dentry, *retval; - mode &= ~current->fs->umask; - dentry = lookup_dentry(filename, NULL, LOOKUP_FOLLOW); + dentry = lookup_dentry(filename, NULL, 0); if (IS_ERR(dentry)) return dentry; @@ -755,16 +777,8 @@ struct dentry * do_mknod(const char * filename, int mode, dev_t dev) if (!check_parent(dir, dentry)) goto exit_lock; - error = may_create(dir->d_inode, dentry); - if (error) - goto exit_lock; + error = vfs_mknod(dir->d_inode, dentry, mode, dev); - error = -EPERM; - if (!dir->d_inode->i_op || !dir->d_inode->i_op->mknod) - goto exit_lock; - - DQUOT_INIT(dir->d_inode); - error = dir->d_inode->i_op->mknod(dir->d_inode, dentry, mode, dev); exit_lock: retval = ERR_PTR(error); if (!error) @@ -778,47 +792,66 @@ asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev) { int error; char * tmp; - struct dentry * dentry; + struct dentry * dentry, *dir; - if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !capable(CAP_MKNOD))) + if (S_ISDIR(mode)) return -EPERM; tmp = getname(filename); if (IS_ERR(tmp)) return PTR_ERR(tmp); - error = -EINVAL; lock_kernel(); + dentry = lookup_dentry(tmp, NULL, 0); + error = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out; + dir = lock_parent(dentry); + error = -ENOENT; + if (!check_parent(dir, dentry)) + goto out_unlock; switch (mode & S_IFMT) { - case 0: - mode |= S_IFREG; /* fallthrough */ - case S_IFREG: - mode &= ~current->fs->umask; - dentry = lookup_dentry(filename, NULL, LOOKUP_FOLLOW); - if (IS_ERR(dentry)) - error = PTR_ERR(dentry); - else { - struct dentry *dir = lock_parent(dentry); - error = -ENOENT; - if (check_parent(dir, dentry)) - error = vfs_create(dir->d_inode, dentry, mode); - dput(dentry); - } + case 0: case S_IFREG: + error = vfs_create(dir->d_inode, dentry, mode); break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - dentry = do_mknod(tmp,mode,dev); - error = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - dput(dentry); - error = 0; - } + error = vfs_mknod(dir->d_inode, dentry, mode, dev); break; + case S_IFDIR: + error = -EPERM; + break; + default: + error = -EINVAL; } +out_unlock: + unlock_dir(dir); + dput(dentry); +out: unlock_kernel(); putname(tmp); return error; } +int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int error; + + error = may_create(dir, dentry); + if (error) + goto exit_lock; + + error = -EPERM; + if (!dir->i_op || !dir->i_op->mkdir) + goto exit_lock; + + DQUOT_INIT(dir); + mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask; + error = dir->i_op->mkdir(dir, dentry, mode); + +exit_lock: + return error; +} + static inline int do_mkdir(const char * pathname, int mode) { int error; @@ -843,17 +876,7 @@ static inline int do_mkdir(const char * pathname, int mode) if (!check_parent(dir, dentry)) goto exit_lock; - error = may_create(dir->d_inode, dentry); - if (error) - goto exit_lock; - - error = -EPERM; - if (!dir->d_inode->i_op || !dir->d_inode->i_op->mkdir) - goto exit_lock; - - DQUOT_INIT(dir->d_inode); - mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask; - error = dir->d_inode->i_op->mkdir(dir->d_inode, dentry, mode); + error = vfs_mkdir(dir->d_inode, dentry, mode); exit_lock: unlock_dir(dir); @@ -1027,6 +1050,25 @@ asmlinkage long sys_unlink(const char * pathname) return error; } +int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) +{ + int error; + + error = may_create(dir, dentry); + if (error) + goto exit_lock; + + error = -EPERM; + if (!dir->i_op || !dir->i_op->symlink) + goto exit_lock; + + DQUOT_INIT(dir); + error = dir->i_op->symlink(dir, dentry, oldname); + +exit_lock: + return error; +} + static inline int do_symlink(const char * oldname, const char * newname) { int error; @@ -1044,16 +1086,7 @@ static inline int do_symlink(const char * oldname, const char * newname) if (!check_parent(dir, dentry)) goto exit_lock; - error = may_create(dir->d_inode, dentry); - if (error) - goto exit_lock; - - error = -EPERM; - if (!dir->d_inode->i_op || !dir->d_inode->i_op->symlink) - goto exit_lock; - - DQUOT_INIT(dir->d_inode); - error = dir->d_inode->i_op->symlink(dir->d_inode, dentry, oldname); + error = vfs_symlink(dir->d_inode, dentry, oldname); exit_lock: unlock_dir(dir); @@ -1083,10 +1116,43 @@ asmlinkage long sys_symlink(const char * oldname, const char * newname) return error; } +int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +{ + struct inode *inode; + int error; + + error = -ENOENT; + inode = old_dentry->d_inode; + if (!inode) + goto exit_lock; + + error = may_create(dir, new_dentry); + if (error) + goto exit_lock; + + error = -EXDEV; + if (dir->i_dev != inode->i_dev) + goto exit_lock; + + /* + * A link to an append-only or immutable file cannot be created. + */ + error = -EPERM; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + goto exit_lock; + if (!dir->i_op || !dir->i_op->link) + goto exit_lock; + + DQUOT_INIT(dir); + error = dir->i_op->link(old_dentry, dir, new_dentry); + +exit_lock: + return error; +} + static inline int do_link(const char * oldname, const char * newname) { struct dentry *old_dentry, *new_dentry, *dir; - struct inode *inode; int error; /* @@ -1113,32 +1179,7 @@ static inline int do_link(const char * oldname, const char * newname) if (!check_parent(dir, new_dentry)) goto exit_lock; - error = -ENOENT; - inode = old_dentry->d_inode; - if (!inode) - goto exit_lock; - - error = may_create(dir->d_inode, new_dentry); - if (error) - goto exit_lock; - - error = -EXDEV; - if (dir->d_inode->i_dev != inode->i_dev) - goto exit_lock; - - /* - * A link to an append-only or immutable file cannot be created. - */ - error = -EPERM; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - goto exit_lock; - - error = -EPERM; - if (!dir->d_inode->i_op || !dir->d_inode->i_op->link) - goto exit_lock; - - DQUOT_INIT(dir->d_inode); - error = dir->d_inode->i_op->link(old_dentry, dir->d_inode, new_dentry); + error = vfs_link(old_dentry, dir->d_inode, new_dentry); exit_lock: unlock_dir(dir); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 5c23664e3834..ae5c139629b2 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -75,10 +75,10 @@ static void ncp_delete_dentry(struct dentry *); struct dentry_operations ncp_dentry_operations = { - ncp_lookup_validate, /* d_revalidate(struct dentry *, int) */ - ncp_hash_dentry, /* d_hash */ - ncp_compare_dentry, /* d_compare */ - ncp_delete_dentry /* d_delete(struct dentry *) */ + d_revalidate: ncp_lookup_validate, + d_hash: ncp_hash_dentry, + d_compare: ncp_compare_dentry, + d_delete: ncp_delete_dentry, }; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 9dfc2f055748..d111076c05ab 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -654,12 +654,9 @@ static void nfs_dentry_release(struct dentry *dentry) } struct dentry_operations nfs_dentry_operations = { - nfs_lookup_revalidate, /* d_revalidate(struct dentry *, int) */ - NULL, /* d_hash */ - NULL, /* d_compare */ - nfs_dentry_delete, /* d_delete(struct dentry *) */ - nfs_dentry_release, /* d_release(struct dentry *) */ - NULL /* d_iput */ + d_revalidate: nfs_lookup_revalidate, + d_delete: nfs_dentry_delete, + d_release: nfs_dentry_release, }; #if 0 /* dead code */ diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index aa03c0a16bb7..084a17d9b502 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -63,7 +63,10 @@ dprintk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name); } /* - * Read a directory and return the name of the specified entry. i_sem is already down(). + * Read a directory and return the name of the specified entry. + * i_sem is already down(). + * The whole thing is a total BS. It should not be done via readdir(), damnit! + * Oh, well, as soon as it will be in filesystems... */ static int get_ino_name(struct dentry *dentry, struct qstr *name, unsigned long ino) { diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 55c351852ee3..c8389381f0ee 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -801,7 +801,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, { struct dentry *dentry, *dchild; struct inode *dirp; - nfsd_dirop_t opfunc = NULL; int err; err = nfserr_perm; @@ -856,45 +855,31 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } + if (!(iap->ia_valid & ATTR_MODE)) + iap->ia_mode = 0; + iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type; + /* * Get the dir op function pointer. */ err = nfserr_perm; switch (type) { case S_IFREG: - opfunc = (nfsd_dirop_t) dirp->i_op->create; + err = vfs_create(dirp, dchild, iap->ia_mode); break; case S_IFDIR: - opfunc = (nfsd_dirop_t) dirp->i_op->mkdir; + err = vfs_mkdir(dirp, dchild, iap->ia_mode); break; case S_IFCHR: case S_IFBLK: - /* The client is _NOT_ required to do security enforcement */ - if(!capable(CAP_SYS_ADMIN)) - { - err = -EPERM; - goto out; - } case S_IFIFO: case S_IFSOCK: - opfunc = dirp->i_op->mknod; + err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); break; default: printk("nfsd: bad file type %o in nfsd_create\n", type); - err = nfserr_inval; + err = -EINVAL; } - if (!opfunc) - goto out; - - if (!(iap->ia_valid & ATTR_MODE)) - iap->ia_mode = 0; - iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type; - - /* - * Call the dir op function to create the object. - */ - DQUOT_INIT(dirp); - err = opfunc(dirp, dchild, iap->ia_mode, rdev); if (err < 0) goto out_nfserr; @@ -954,9 +939,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_notdir; if(!dirp->i_op || !dirp->i_op->lookup) goto out; - err = nfserr_perm; - if(!dirp->i_op->create) - goto out; /* * Compose the response file handle. @@ -1003,7 +985,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } - err = dirp->i_op->create(dirp, dchild, iap->ia_mode); + err = vfs_create(dirp, dchild, iap->ia_mode); if (err < 0) goto out_nfserr; @@ -1101,7 +1083,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) { struct dentry *dentry, *dnew; - struct inode *dirp; int err; err = nfserr_noent; @@ -1113,11 +1094,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; dentry = fhp->fh_dentry; - err = nfserr_perm; - dirp = dentry->d_inode; - if (!dirp->i_op || !dirp->i_op->symlink) - goto out; - dnew = lookup_dentry(fname, dget(dentry), 0); err = PTR_ERR(dnew); if (IS_ERR(dnew)) @@ -1130,27 +1106,23 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, if (err) goto out_compose; - err = nfserr_exist; - if (!dnew->d_inode) { - DQUOT_INIT(dirp); - err = dirp->i_op->symlink(dirp, dnew, path); - if (!err) { - if (EX_ISSYNC(fhp->fh_export)) - nfsd_sync_dir(dentry); - if (iap) { - iap->ia_valid &= ATTR_MODE /* ~(ATTR_MODE|ATTR_UID|ATTR_GID)*/; - if (iap->ia_valid) { - iap->ia_valid |= ATTR_CTIME; - iap->ia_mode = (iap->ia_mode&S_IALLUGO) - | S_IFLNK; - err = notify_change(dnew, iap); - if (!err && EX_ISSYNC(fhp->fh_export)) - write_inode_now(dentry->d_inode); - } - } - } else - err = nfserrno(-err); - } + err = vfs_symlink(dentry->d_inode, dnew, path); + if (!err) { + if (EX_ISSYNC(fhp->fh_export)) + nfsd_sync_dir(dentry); + if (iap) { + iap->ia_valid &= ATTR_MODE /* ~(ATTR_MODE|ATTR_UID|ATTR_GID)*/; + if (iap->ia_valid) { + iap->ia_valid |= ATTR_CTIME; + iap->ia_mode = (iap->ia_mode&S_IALLUGO) + | S_IFLNK; + err = notify_change(dnew, iap); + if (!err && EX_ISSYNC(fhp->fh_export)) + write_inode_now(dentry->d_inode); + } + } + } else + err = nfserrno(-err); fh_unlock(fhp); /* Compose the fh so the dentry will be freed ... */ @@ -1201,34 +1173,22 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, if (err) goto out_dput; - err = nfserr_exist; - if (dnew->d_inode) - goto out_unlock; - dold = tfhp->fh_dentry; dest = dold->d_inode; - err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev; - if (dirp->i_dev != dest->i_dev) - goto out_unlock; - - err = nfserr_perm; - if (IS_IMMUTABLE(dest) || IS_APPEND(dest)) - goto out_unlock; - if (!dirp->i_op || !dirp->i_op->link) - goto out_unlock; - - DQUOT_INIT(dirp); - err = dirp->i_op->link(dold, dirp, dnew); + err = vfs_link(dold, dirp, dnew); if (!err) { if (EX_ISSYNC(ffhp->fh_export)) { nfsd_sync_dir(ddir); write_inode_now(dest); } - } else - err = nfserrno(-err); + } else { + if (err == -EXDEV && rqstp->rq_vers == 2) + err = nfserr_acces; + else + err = nfserrno(-err); + } -out_unlock: fh_unlock(ffhp); out_dput: dput(dnew); diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c index 6db74a14e94d..89888bb6025b 100644 --- a/fs/ntfs/fs.c +++ b/fs/ntfs/fs.c @@ -31,6 +31,7 @@ /* Forward declarations */ static struct inode_operations ntfs_dir_inode_operations; +static struct file_operations ntfs_dir_operations; #define ITEM_SIZE 2040 diff --git a/fs/pipe.c b/fs/pipe.c index 7cfe6caf509e..020416013012 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -161,7 +161,6 @@ pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) if (down_interruptible(PIPE_SEM(*inode))) goto out_nolock; -do_more_write: /* No readers yields SIGPIPE. */ if (!PIPE_READERS(*inode)) goto sigpipe; diff --git a/fs/proc/base.c b/fs/proc/base.c index 54d93e131dde..4a191bfef5b3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -631,26 +631,19 @@ static void pid_delete_dentry(struct dentry * dentry) static struct dentry_operations pid_fd_dentry_operations = { - pid_fd_revalidate, /* revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ - pid_delete_dentry /* d_delete(struct dentry *) */ + d_revalidate: pid_fd_revalidate, + d_delete: pid_delete_dentry, }; static struct dentry_operations pid_dentry_operations = { - NULL, /* revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ - pid_delete_dentry /* d_delete(struct dentry *) */ + d_delete: pid_delete_dentry, }; static struct dentry_operations pid_base_dentry_operations = { - pid_base_revalidate, /* revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ - pid_delete_dentry /* d_delete(struct dentry *) */ + d_revalidate: pid_base_revalidate, + d_delete: pid_delete_dentry, }; /* Lookups */ diff --git a/fs/proc/generic.c b/fs/proc/generic.c index fcfadbc998f7..28e0c08e5dc4 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -226,10 +226,7 @@ proc_delete_dentry(struct dentry * dentry) static struct dentry_operations proc_dentry_operations = { - NULL, /* revalidate */ - NULL, /* d_hash */ - NULL, /* d_compare */ - proc_delete_dentry /* d_delete(struct dentry *) */ + d_delete: proc_delete_dentry, }; /* diff --git a/fs/readdir.c b/fs/readdir.c index 31bc56cc2122..4bf222288288 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -13,6 +13,21 @@ #include +int vfs_readdir(struct file *file, + int (*filler)(void *,const char *,int,off_t,ino_t), + void *buf) +{ + struct inode *inode = file->f_dentry->d_inode; + int res = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out; + down(&inode->i_sem); + res = file->f_op->readdir(file, buf, filler); + up(&inode->i_sem); +out: + return res; +} + /* * Traditional linux readdir() handling.. * @@ -57,46 +72,24 @@ asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count) { int error; struct file * file; - struct dentry * dentry; - struct inode * inode; struct readdir_callback buf; - lock_kernel(); error = -EBADF; file = fget(fd); if (!file) goto out; - dentry = file->f_dentry; - if (!dentry) - goto out_putf; - - inode = dentry->d_inode; - if (!inode) - goto out_putf; - buf.count = 0; buf.dirent = dirent; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - /* - * Get the inode's semaphore to prevent changes - * to the directory while we read it. - */ - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, fillonedir); - up(&inode->i_sem); - if (error < 0) - goto out_putf; - error = buf.count; + lock_kernel(); + error = vfs_readdir(file, fillonedir, &buf); + if (error >= 0) + error = buf.count; + unlock_kernel(); -out_putf: fput(file); out: - unlock_kernel(); return error; } @@ -145,42 +138,22 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in asmlinkage long sys_getdents(unsigned int fd, void * dirent, unsigned int count) { struct file * file; - struct dentry * dentry; - struct inode * inode; struct linux_dirent * lastdirent; struct getdents_callback buf; int error; - lock_kernel(); error = -EBADF; file = fget(fd); if (!file) goto out; - dentry = file->f_dentry; - if (!dentry) - goto out_putf; - - inode = dentry->d_inode; - if (!inode) - goto out_putf; - buf.current_dir = (struct linux_dirent *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) - goto out_putf; - - /* - * Get the inode's semaphore to prevent changes - * to the directory while we read it. - */ - down(&inode->i_sem); - error = file->f_op->readdir(file, &buf, filldir); - up(&inode->i_sem); + lock_kernel(); + error = vfs_readdir(file, filldir, &buf); if (error < 0) goto out_putf; error = buf.error; @@ -191,8 +164,8 @@ asmlinkage long sys_getdents(unsigned int fd, void * dirent, unsigned int count) } out_putf: + unlock_kernel(); fput(file); out: - unlock_kernel(); return error; } diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index ca98fc9ca57b..91061a28ffd7 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -172,10 +172,10 @@ static void smb_delete_dentry(struct dentry *); static struct dentry_operations smbfs_dentry_operations = { - smb_lookup_validate, /* d_revalidate(struct dentry *) */ - smb_hash_dentry, /* d_hash */ - smb_compare_dentry, /* d_compare */ - smb_delete_dentry /* d_delete(struct dentry *) */ + d_revalidate: smb_lookup_validate, + d_hash: smb_hash_dentry, + d_compare: smb_compare_dentry, + d_delete: smb_delete_dentry, }; /* diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index be27c54a7975..18dd76572564 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -46,10 +46,8 @@ static void umsdos_dentry_dput(struct dentry *dentry) struct dentry_operations umsdos_dentry_operations = { - umsdos_dentry_validate, /* d_revalidate(struct dentry *, int) */ - NULL, /* d_hash */ - NULL, /* d_compare */ - umsdos_dentry_dput /* d_delete(struct dentry *) */ + d_revalidate: umsdos_dentry_validate, + d_delete: umsdos_dentry_dput, }; struct UMSDOS_DIR_ONCE { diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index b077082866a5..476a09e9cc05 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -59,28 +59,22 @@ static int vfat_revalidate(struct dentry *dentry, int); static struct dentry_operations vfat_dentry_ops[4] = { { - NULL, /* d_revalidate */ - vfat_hashi, - vfat_cmpi, - NULL /* d_delete */ + d_hash: vfat_hashi, + d_compare: vfat_cmpi, }, { - vfat_revalidate, - vfat_hashi, - vfat_cmpi, - NULL /* d_delete */ + d_revalidate: vfat_revalidate, + d_hash: vfat_hashi, + d_compare: vfat_cmpi, }, { - NULL, /* d_revalidate */ - vfat_hash, - vfat_cmp, - NULL /* d_delete */ + d_hash: vfat_hash, + d_compare: vfat_cmp, }, { - vfat_revalidate, - vfat_hash, - vfat_cmp, - NULL /* d_delete */ + d_revalidate: vfat_revalidate, + d_hash: vfat_hash, + d_compare: vfat_cmp, } }; diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 1945221792e9..eb5d9124e04c 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -179,6 +179,10 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "jmp common_interrupt"); extern unsigned long prof_cpu_mask; +extern unsigned int * prof_buffer; +extern unsigned long prof_len; +extern unsigned long prof_shift; + /* * x86 profiling function, SMP safe. We might want to do this in * assembly totally? diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h index c81925cd5bc1..0b728aee381a 100644 --- a/include/asm-sh/pgalloc.h +++ b/include/asm-sh/pgalloc.h @@ -1,7 +1,6 @@ #ifndef __ASM_SH_PGALLOC_H #define __ASM_SH_PGALLOC_H -#include #include #include diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h index 2d66e87f8319..b0543fffb870 100644 --- a/include/asm-sparc/pgtable.h +++ b/include/asm-sparc/pgtable.h @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.91 2000/02/16 08:44:52 anton Exp $ */ +/* $Id: pgtable.h,v 1.92 2000/03/02 20:37:37 davem Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index b271dad950d4..056b60f6ab73 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.120 2000/02/16 07:34:54 davem Exp $ +/* $Id: pgtable.h,v 1.121 2000/03/02 20:37:41 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index 5989d8c4a5b5..87379139bb40 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.55 1999/09/10 10:44:44 davem Exp $ */ +/* $Id: system.h,v 1.56 2000/03/06 22:33:45 davem Exp $ */ #ifndef __SPARC64_SYSTEM_H #define __SPARC64_SYSTEM_H @@ -116,7 +116,16 @@ extern void __global_restore_flags(unsigned long flags); #define read_pcr(__p) __asm__ __volatile__("rd %%pcr, %0" : "=r" (__p)) #define write_pcr(__p) __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (__p)); #define read_pic(__p) __asm__ __volatile__("rd %%pic, %0" : "=r" (__p)) -#define reset_pic() __asm__ __volatile__("wr %g0, 0x0, %pic"); + +/* Blackbird errata workaround. See commentary in + * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt() + * for more information. + */ +#define reset_pic() \ + __asm__ __volatile__("ba,pt %xcc, 99f\n\t" \ + ".align 64\n" \ + "99:wr %g0, 0x0, %pic\n\t" \ + "rd %pic, %g0") #ifndef __ASSEMBLY__ diff --git a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h index b3abeacd47e1..b35fbe6e19d2 100644 --- a/include/linux/devfs_fs_kernel.h +++ b/include/linux/devfs_fs_kernel.h @@ -16,22 +16,26 @@ ) ? m : MINOR((inode)->r_dev); }) -#define DEVFS_FL_NONE 0x000 /* This helps making code more readable */ -#define DEVFS_FL_AUTO_OWNER 0x001 /* When a closed inode is opened the - ownerships are set to the opening - process and the protection is set to - that given in <>. When the inode - is closed, ownership reverts back to - <> and <> and the protection - is set to read-write for all */ -#define DEVFS_FL_SHOW_UNREG 0x002 /* Show unregistered entries in - directory listings */ -#define DEVFS_FL_HIDE 0x004 /* Do not show entry in directory list */ -#define DEVFS_FL_AUTO_DEVNUM 0x008 /* Automatically generate device number */ -#define DEVFS_FL_AOPEN_NOTIFY 0x010 /* Asynchronously notify devfsd on open */ -#define DEVFS_FL_REMOVABLE 0x020 /* This is a removable media device */ -#define DEVFS_FL_WAIT 0x040 /* Wait for devfsd to finish */ -#define DEVFS_FL_DEFAULT DEVFS_FL_NONE +#define DEVFS_FL_NONE 0x000 /* This helps to make code more readable + */ +#define DEVFS_FL_AUTO_OWNER 0x001 /* When a closed inode is opened the + ownerships are set to the opening + process and the protection is set to + that given in <>. When the inode + is closed, ownership reverts back to + <> and <> and the protection + is set to read-write for all */ +#define DEVFS_FL_SHOW_UNREG 0x002 /* Show unregistered entries in + directory listings */ +#define DEVFS_FL_HIDE 0x004 /* Do not show entry in directory list */ +#define DEVFS_FL_AUTO_DEVNUM 0x008 /* Automatically generate device number + */ +#define DEVFS_FL_AOPEN_NOTIFY 0x010 /* Asynchronously notify devfsd on open + */ +#define DEVFS_FL_REMOVABLE 0x020 /* This is a removable media device */ +#define DEVFS_FL_WAIT 0x040 /* Wait for devfsd to finish */ +#define DEVFS_FL_NO_PERSISTENCE 0x080 /* Forget changes after unregister */ +#define DEVFS_FL_DEFAULT DEVFS_FL_NONE #define DEVFS_SPECIAL_CHR 0 diff --git a/include/linux/fs.h b/include/linux/fs.h index e33bdfa72999..45ec949e17ae 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -630,6 +630,11 @@ struct super_block { /* * VFS helper functions.. */ +extern int vfs_create(struct inode *, struct dentry *, int); +extern int vfs_mkdir(struct inode *, struct dentry *, int); +extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t); +extern int vfs_symlink(struct inode *, struct dentry *, const char *); +extern int vfs_link(struct dentry *, struct inode *, struct dentry *); extern int vfs_rmdir(struct inode *, struct dentry *); extern int vfs_unlink(struct inode *, struct dentry *); extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); @@ -1028,6 +1033,8 @@ extern int page_readlink(struct dentry *, char *, int); extern struct dentry *page_follow_link(struct dentry *, struct dentry *, unsigned); extern struct inode_operations page_symlink_inode_operations; +extern int vfs_readdir(struct file *, filldir_t, void *); + extern struct super_block *get_super(kdev_t); struct super_block *get_empty_super(void); void remove_vfsmnt(kdev_t dev); diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 954229d6c0f2..9b72c14de63e 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -179,7 +179,6 @@ enum nf_reason { NF_REASON_SET_BY_IPCHAINS, NF_REASON_FOR_ROUTING, NF_REASON_FOR_CLS_FW, - NF_REASON_MIN_RESERVED_FOR_CONNTRACK = 1024, }; #endif /*__LINUX_NETFILTER_H*/ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 015855fa0e52..6081b089052e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -37,6 +37,17 @@ #define NET_CALLER(arg) __builtin_return_address(0) #endif +#ifdef CONFIG_NETFILTER +struct nf_conntrack { + atomic_t use; + void (*destroy)(struct nf_conntrack *); +}; + +struct nf_ct_info { + struct nf_conntrack *master; +}; +#endif + struct sk_buff_head { /* These two members must be first. */ struct sk_buff * next; @@ -115,6 +126,8 @@ struct sk_buff { __u32 nfreason; /* Cache info */ __u32 nfcache; + /* Associated connection, if any */ + struct nf_ct_info *nfct; #ifdef CONFIG_NETFILTER_DEBUG unsigned int nf_debug; #endif @@ -635,5 +648,20 @@ extern void skb_free_datagram(struct sock * sk, struct sk_buff *skb); extern void skb_init(void); extern void skb_add_mtu(int mtu); +#ifdef CONFIG_NETFILTER +extern __inline__ void +nf_conntrack_put(struct nf_ct_info *nfct) +{ + if (nfct && atomic_dec_and_test(&nfct->master->use)) + nfct->master->destroy(nfct->master); +} +extern __inline__ void +nf_conntrack_get(struct nf_ct_info *nfct) +{ + if (nfct) + atomic_inc(&nfct->master->use); +} +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/include/linux/zorro.h b/include/linux/zorro.h index 26c7a460ee06..9e7c078890d1 100644 --- a/include/linux/zorro.h +++ b/include/linux/zorro.h @@ -717,7 +717,6 @@ extern struct zorro_dev zorro_autocon[ZORRO_NUM_AUTO]; */ extern void zorro_init(void); -extern void zorro_proc_init(void); extern struct zorro_dev *zorro_find_device(zorro_id id, struct zorro_dev *from); diff --git a/include/scsi/sg.h b/include/scsi/sg.h index ddd942d1453a..20b7d158e9a6 100644 --- a/include/scsi/sg.h +++ b/include/scsi/sg.h @@ -9,11 +9,15 @@ Original driver (sg.h): * Copyright (C) 1992 Lawrence Foard Version 2 and 3 extensions to driver: -* Copyright (C) 1998, 1999 Douglas Gilbert +* Copyright (C) 1998 - 2000 Douglas Gilbert - Version: 3.1.10 (20000123) + Version: 3.1.12 (20000222) This version is for 2.3/2.4 series kernels. + Changes since 3.1.10 (20000123) + - make device allocation dynamic (get rid of SG_EXTRA_DEVS) + - move to sg0,sg1,sg2 rather than sga,sgb,sgc + - make sg_io_hdr_t safer across architectures Changes since 2.1.34 (990603) and 2.3.35 (990708) - add new interface structure: sg_io_hdr_t - supports larger sense buffer, DMA residual count + direct IO @@ -110,11 +114,11 @@ typedef struct sg_iovec /* same structure as used by readv() Linux system */ typedef struct sg_io_hdr { - char interface_id; /* [i] 'S' for SCSI generic (required) */ + int interface_id; /* [i] 'S' for SCSI generic (required) */ + int dxfer_direction; /* [i] data transfer direction */ unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ - unsigned char iovec_count; /* [i] 0 implies no scatter gather */ unsigned char mx_sb_len; /* [i] max length to write to sbp */ - int dxfer_direction; /* [i] data transfer direction */ + unsigned short iovec_count; /* [i] 0 implies no scatter gather */ unsigned int dxfer_len; /* [i] byte count of data transfer */ void * dxferp; /* [i], [*io] points to data transfer memory or scatter gather list */ @@ -133,7 +137,7 @@ typedef struct sg_io_hdr int resid; /* [o] dxfer_len - actual_transferred */ unsigned int duration; /* [o] time taken by cmd (unit: millisec) */ unsigned int info; /* [o] auxiliary information */ -} sg_io_hdr_t; /* 60 bytes long (on i386) */ +} sg_io_hdr_t; /* 64 bytes long (on i386) */ /* Use negative values to flag difference from original sg_header structure */ #define SG_DXFER_NONE -1 /* e.g. a SCSI Test Unit Ready command */ @@ -223,9 +227,13 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ #define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */ -/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing, - 1 -> device reset or 2 -> bus reset (may not be activated yet) */ +/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */ #define SG_SCSI_RESET 0x2284 +/* Associated values that can be given to SG_SCSI_RESET follow */ +#define SG_SCSI_RESET_NOTHING 0 +#define SG_SCSI_RESET_DEVICE 1 +#define SG_SCSI_RESET_BUS 2 +#define SG_SCSI_RESET_HOST 3 /* synchronous SCSI command ioctl, (only in version 3 interface) */ #define SG_IO 0x2285 /* similar effect as write() followed by read() */ @@ -291,7 +299,7 @@ struct sg_header /* IOCTLs: The following are not required (or ignored) when the sg_io_hdr_t - interface is used. That are kept for backward compatibility with + interface is used. They are kept for backward compatibility with the original and version 2 drivers. */ #define SG_SET_TIMEOUT 0x2201 /* unit: jiffies (10ms on i386) */ diff --git a/include/video/fbcon-hga.h b/include/video/fbcon-hga.h new file mode 100644 index 000000000000..695ab443f2a4 --- /dev/null +++ b/include/video/fbcon-hga.h @@ -0,0 +1,32 @@ +/* + * FBcon low-level driver for Hercules Graphics Adaptor (hga) + */ + +#ifndef _VIDEO_FBCON_HGA_H +#define _VIDEO_FBCON_HGA_H + +#include + +#ifdef MODULE +#if defined(CONFIG_FBCON_HGA) || defined(CONFIG_FBCON_HGA_MODULE) +#define FBCON_HAS_HGA +#endif +#else +#if defined(CONFIG_FBCON_HGA) +#define FBCON_HAS_HGA +#endif +#endif + +extern struct display_switch fbcon_hga; +extern void fbcon_hga_setup(struct display *p); +extern void fbcon_hga_bmove(struct display *p, int sy, int sx, int dy, int dx, + int height, int width); +extern void fbcon_hga_clear(struct vc_data *conp, struct display *p, int sy, + int sx, int height, int width); +extern void fbcon_hga_putc(struct vc_data *conp, struct display *p, int c, + int yy, int xx); +extern void fbcon_hga_putcs(struct vc_data *conp, struct display *p, + const unsigned short *s, int count, int yy, int xx); +extern void fbcon_hga_revc(struct display *p, int xx, int yy); + +#endif /* _VIDEO_FBCON_HGA_H */ diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 95e54dc4d73c..c3da1e840731 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -217,6 +217,11 @@ EXPORT_SYMBOL(shrink_dcache_parent); EXPORT_SYMBOL(find_inode_number); EXPORT_SYMBOL(is_subdir); EXPORT_SYMBOL(get_unused_fd); +EXPORT_SYMBOL(vfs_create); +EXPORT_SYMBOL(vfs_mkdir); +EXPORT_SYMBOL(vfs_mknod); +EXPORT_SYMBOL(vfs_symlink); +EXPORT_SYMBOL(vfs_link); EXPORT_SYMBOL(vfs_rmdir); EXPORT_SYMBOL(vfs_unlink); EXPORT_SYMBOL(vfs_rename); @@ -233,6 +238,7 @@ EXPORT_SYMBOL(page_readlink); EXPORT_SYMBOL(page_follow_link); EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(block_symlink); +EXPORT_SYMBOL(vfs_readdir); /* for stackable file systems (lofs, wrapfs, etc.) */ EXPORT_SYMBOL(add_to_page_cache); @@ -368,6 +374,7 @@ EXPORT_SYMBOL(enable_hlt); EXPORT_SYMBOL(request_resource); EXPORT_SYMBOL(release_resource); EXPORT_SYMBOL(allocate_resource); +EXPORT_SYMBOL(check_resource); EXPORT_SYMBOL(__request_region); EXPORT_SYMBOL(__check_region); EXPORT_SYMBOL(__release_region); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 4e1647b842bf..02ba33bd5c81 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -82,6 +82,8 @@ void __free_pages_ok (struct page *page, unsigned long order) if (PageReserved(page)) return; + if (page->buffers) + BUG(); if (page-mem_map >= max_mapnr) BUG(); if (PageSwapCache(page)) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 30aa1f6bbc67..ecda47d7a470 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4,7 +4,7 @@ * Authors: Alan Cox * Florian La Roche * - * Version: $Id: skbuff.c,v 1.68 2000/02/18 16:47:18 davem Exp $ + * Version: $Id: skbuff.c,v 1.69 2000/03/06 03:47:58 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -204,6 +204,7 @@ static inline void skb_headerinit(void *p, kmem_cache_t *cache, skb->rx_dev = NULL; #ifdef CONFIG_NETFILTER skb->nfmark = skb->nfreason = skb->nfcache = 0; + skb->nfct = NULL; #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = 0; #endif @@ -246,6 +247,9 @@ void __kfree_skb(struct sk_buff *skb) } skb->destructor(skb); } +#ifdef CONFIG_NETFILTER + nf_conntrack_put(skb->nfct); +#endif #ifdef CONFIG_NET if(skb->rx_dev) dev_put(skb->rx_dev); @@ -282,6 +286,9 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) n->is_clone = 1; atomic_set(&n->users, 1); n->destructor = NULL; +#ifdef CONFIG_NETFILTER + nf_conntrack_get(skb->nfct); +#endif return n; } @@ -314,6 +321,8 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->nfmark=old->nfmark; new->nfreason=old->nfreason; new->nfcache=old->nfcache; + new->nfct=old->nfct; + nf_conntrack_get(new->nfct); #ifdef CONFIG_NETFILTER_DEBUG new->nf_debug=old->nf_debug; #endif diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index e06825e2e6cd..26d025d3280d 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.80 2000/02/09 11:16:41 davem Exp $ + * Version: $Id: ip_output.c,v 1.81 2000/03/06 03:48:01 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -890,6 +890,12 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) ptr += len; offset += len; +#ifdef CONFIG_NETFILTER + /* Connection association is same as pre-frag packet */ + skb2->nfct = skb->nfct; + nf_conntrack_get(skb2->nfct); +#endif + /* * Put this fragment into the sending queue. */ -- 2.39.5